mirror of
https://github.com/EnumeratedDev/bpm.git
synced 2026-09-16 02:26:12 +00:00
Add package compilation flags
This commit is contained in:
+41
-28
@@ -239,21 +239,20 @@ func showPackageInfo() {
|
||||
}
|
||||
|
||||
for n, pkg := range packages {
|
||||
if showDatabaseInfo {
|
||||
// Split package name and required version
|
||||
pkgName, _, _ := bpmlib.SplitPkgNameAndVersion(pkg)
|
||||
|
||||
entry := bpmlib.ResolveDatabaseEntry(pkgName, rootDir)
|
||||
if entry == nil {
|
||||
log.Printf("Error: could not find package (%s) in any database\n", pkg)
|
||||
// Deconstruct package string
|
||||
d, err := bpmlib.DeconstructPackageString(pkg)
|
||||
if err != nil {
|
||||
log.Printf("Error: could not deconstruct package string: %s\n", err)
|
||||
exitCode = 1
|
||||
return
|
||||
}
|
||||
|
||||
if !bpmlib.EvaluateDependency(pkg, entry.Info.Version) {
|
||||
if showDatabaseInfo {
|
||||
entry := bpmlib.ResolveDatabaseEntry(d, rootDir)
|
||||
if entry == nil {
|
||||
log.Printf("Error: could not find package (%s) in any database\n", pkg)
|
||||
exitCode = 1
|
||||
continue
|
||||
return
|
||||
}
|
||||
|
||||
if n != 0 {
|
||||
@@ -266,8 +265,8 @@ func showPackageInfo() {
|
||||
|
||||
var bpmpkg *bpmlib.BPMPackage
|
||||
isFile := false
|
||||
if stat, err := os.Stat(pkg); err == nil && !stat.IsDir() {
|
||||
bpmpkg, err = bpmlib.ReadPackage(pkg)
|
||||
if stat, err := os.Stat(d.PkgName); err == nil && !stat.IsDir() {
|
||||
bpmpkg, err = bpmlib.ReadPackage(d.PkgName)
|
||||
if err != nil {
|
||||
log.Printf("Error: could not read package: %s\n", err)
|
||||
exitCode = 1
|
||||
@@ -275,13 +274,10 @@ func showPackageInfo() {
|
||||
}
|
||||
isFile = true
|
||||
} else {
|
||||
// Split package name and required version
|
||||
pkgName, _, _ := bpmlib.SplitPkgNameAndVersion(pkg)
|
||||
|
||||
if providers := bpmlib.GetVirtualPackageInfo(pkgName, rootDir); len(providers) > 0 {
|
||||
if providers := bpmlib.GetVirtualPackageInfo(d.PkgName, rootDir); len(providers) > 0 {
|
||||
bpmpkg = bpmlib.GetPackage(providers[0].Name, rootDir)
|
||||
} else {
|
||||
bpmpkg = bpmlib.GetPackage(pkgName, rootDir)
|
||||
bpmpkg = bpmlib.GetPackage(d.PkgName, rootDir)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -291,7 +287,7 @@ func showPackageInfo() {
|
||||
return
|
||||
}
|
||||
|
||||
if !bpmlib.EvaluateDependency(pkg, bpmpkg.PkgInfo.Version) {
|
||||
if !bpmlib.EvaluatePackageString(bpmpkg.PkgInfo, d) {
|
||||
log.Printf("Error: package (%s) is not installed\n", pkg)
|
||||
exitCode = 1
|
||||
return
|
||||
@@ -301,7 +297,7 @@ func showPackageInfo() {
|
||||
fmt.Println()
|
||||
}
|
||||
if isFile {
|
||||
abs, err := filepath.Abs(pkg)
|
||||
abs, err := filepath.Abs(d.PkgName)
|
||||
if err != nil {
|
||||
log.Printf("Error: could not get absolute path of file (%s)\n", abs)
|
||||
exitCode = 1
|
||||
@@ -632,7 +628,7 @@ func installPackages() {
|
||||
|
||||
// Create installation operation
|
||||
operation, err := bpmlib.InstallPackages(rootDir, ir, reinstallPackages, installRuntime, force, !skipChecks, verbose, packages...)
|
||||
if errors.As(err, &bpmlib.PackageNotFoundErr{}) || errors.As(err, &bpmlib.DependencyNotFoundErr{}) || errors.As(err, &bpmlib.PackageConflictErr{}) {
|
||||
if errors.As(err, &bpmlib.PackageNotResolvedErr{}) || errors.As(err, &bpmlib.PackageConflictErr{}) {
|
||||
log.Printf("Error: %s", err)
|
||||
exitCode = 1
|
||||
return
|
||||
@@ -787,7 +783,7 @@ func removePackages() {
|
||||
|
||||
// Create remove operation
|
||||
operation, err := bpmlib.RemovePackages(rootDir, force, cleanupPackages, packages...)
|
||||
if errors.As(err, &bpmlib.PackageNotFoundErr{}) || errors.As(err, &bpmlib.DependencyNotFoundErr{}) || errors.As(err, &bpmlib.PackageConflictErr{}) {
|
||||
if errors.As(err, &bpmlib.PackageNotResolvedErr{}) || errors.As(err, &bpmlib.PackageConflictErr{}) {
|
||||
log.Printf("Error: %s", err)
|
||||
exitCode = 1
|
||||
return
|
||||
@@ -931,7 +927,7 @@ func doCleanup() {
|
||||
|
||||
// Create cleanup operation
|
||||
operation, err := bpmlib.CleanupPackages(cleanupMakeDepends, rootDir)
|
||||
if errors.As(err, &bpmlib.PackageNotFoundErr{}) || errors.As(err, &bpmlib.DependencyNotFoundErr{}) || errors.As(err, &bpmlib.PackageConflictErr{}) {
|
||||
if errors.As(err, &bpmlib.PackageNotResolvedErr{}) || errors.As(err, &bpmlib.PackageConflictErr{}) {
|
||||
log.Printf("Error: %s", err)
|
||||
exitCode = 1
|
||||
return
|
||||
@@ -1095,7 +1091,7 @@ func updatePackages() {
|
||||
|
||||
// Create update operation
|
||||
operation, err := bpmlib.UpdatePackages(rootDir, !noSync, allowDowngrades, force, !skipChecks, verbose)
|
||||
if errors.As(err, &bpmlib.PackageNotFoundErr{}) || errors.As(err, &bpmlib.DependencyNotFoundErr{}) || errors.As(err, &bpmlib.PackageConflictErr{}) {
|
||||
if errors.As(err, &bpmlib.PackageNotResolvedErr{}) || errors.As(err, &bpmlib.PackageConflictErr{}) {
|
||||
log.Printf("Error: %s", err)
|
||||
exitCode = 1
|
||||
return
|
||||
@@ -1300,8 +1296,16 @@ func compilePackage() {
|
||||
|
||||
// Compile packages
|
||||
for _, sourcePackage := range sourcePackages {
|
||||
if _, err := os.Stat(sourcePackage); os.IsNotExist(err) {
|
||||
log.Printf("Error: file (%s) does not exist!", sourcePackage)
|
||||
// Deconstruct package string
|
||||
d, err := bpmlib.DeconstructPackageString(sourcePackage)
|
||||
if err != nil {
|
||||
log.Printf("Error: could not deconstruct package string: %s\n", err)
|
||||
exitCode = 1
|
||||
return
|
||||
}
|
||||
|
||||
if _, err := os.Stat(d.PkgName); os.IsNotExist(err) {
|
||||
log.Printf("Error: file (%s) does not exist!", d.PkgName)
|
||||
exitCode = 1
|
||||
return
|
||||
}
|
||||
@@ -1321,6 +1325,12 @@ func compilePackage() {
|
||||
return
|
||||
}
|
||||
|
||||
if !bpmlib.EvaluatePackageString(bpmpkg.PkgInfo, d) {
|
||||
log.Printf("Error: could not evaluate package: %s\n", sourcePackage)
|
||||
exitCode = 1
|
||||
return
|
||||
}
|
||||
|
||||
// Get common, make and check dependencies
|
||||
totalDepends := make([]string, 0)
|
||||
totalDepends = append(totalDepends, bpmpkg.PkgInfo.Depends...)
|
||||
@@ -1350,10 +1360,13 @@ func compilePackage() {
|
||||
// Ignore packages that can't be found in any databases
|
||||
if force {
|
||||
unmetDepends = slices.DeleteFunc(unmetDepends, func(s string) bool {
|
||||
if bpmlib.ResolveDatabaseEntry(s, rootDir) == nil {
|
||||
return true
|
||||
}
|
||||
// Deconstruct package string
|
||||
d, err := bpmlib.DeconstructPackageString(s)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
return bpmlib.ResolveDatabaseEntry(d, rootDir) == nil
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1485,7 +1498,7 @@ func compilePackage() {
|
||||
return
|
||||
}
|
||||
|
||||
outputBpmPackages, err := bpmlib.CompileSourcePackage(sourcePackage, outputDirectory, compilationJobs, skipChecks, keepCompilationFiles, verbose)
|
||||
outputBpmPackages, err := bpmlib.CompileSourcePackage(sourcePackage, outputDirectory, d.Flags, compilationJobs, skipChecks, keepCompilationFiles, verbose)
|
||||
if err != nil {
|
||||
// Remove unused packages
|
||||
cleanupFunc()
|
||||
|
||||
@@ -24,7 +24,7 @@ import (
|
||||
var rootCompilationUID = "65534"
|
||||
var rootCompilationGID = "65534"
|
||||
|
||||
func CompileSourcePackage(archiveFilename, outputDirectory string, compilationJobs int, skipChecks, keepCompilationFiles, verbose bool) (outputBpmPackages map[string]string, err error) {
|
||||
func CompileSourcePackage(archiveFilename, outputDirectory string, flags map[string]string, compilationJobs int, skipChecks, keepCompilationFiles, verbose bool) (outputBpmPackages map[string]string, err error) {
|
||||
// Set compilation jobs
|
||||
if compilationJobs <= 0 || compilationJobs > runtime.NumCPU() {
|
||||
compilationJobs = runtime.NumCPU()
|
||||
@@ -146,6 +146,15 @@ func CompileSourcePackage(archiveFilename, outputDirectory string, compilationJo
|
||||
env = append(env, "BPM_PKG_URL="+bpmpkg.PkgInfo.Url)
|
||||
env = append(env, "BPM_PKG_ARCH="+bpmpkg.PkgInfo.OutputArch)
|
||||
env = append(env, "BPM_JOBS="+strconv.Itoa(compilationJobs))
|
||||
for _, flag := range bpmpkg.PkgInfo.Flags {
|
||||
if value, ok := flags[flag.Name]; ok {
|
||||
env = append(env, "BPM_PKG_FLAG_"+strings.ToUpper(flag.Name)+"="+value)
|
||||
fmt.Printf("Package flag: %s=%s\n", flag.Name, value)
|
||||
} else {
|
||||
env = append(env, "BPM_PKG_FLAG_"+strings.ToUpper(flag.Name)+"="+flag.DefaultValue)
|
||||
fmt.Printf("Package flag: %s=%s\n", flag.Name, flag.DefaultValue)
|
||||
}
|
||||
}
|
||||
env = append(env, CompilationBPMConfig.CompilationEnvironment...)
|
||||
|
||||
// Set common flags used for limiting job count
|
||||
@@ -381,6 +390,31 @@ func CompileSourcePackage(archiveFilename, outputDirectory string, compilationJo
|
||||
pkgInfo.SplitPackages = nil
|
||||
pkgInfo.Downloads = nil
|
||||
|
||||
// Set built flag values and add their dependencies
|
||||
for i, flag := range pkgInfo.Flags {
|
||||
if value, ok := flags[flag.Name]; ok {
|
||||
flag.BuiltValue = value
|
||||
} else {
|
||||
flag.BuiltValue = flag.DefaultValue
|
||||
}
|
||||
|
||||
acceptedValueIndex := slices.IndexFunc(flag.AcceptedValues, func(acceptedValue PackageAcceptedValue) bool {
|
||||
return acceptedValue.Value == flag.BuiltValue
|
||||
})
|
||||
if acceptedValueIndex < 0 {
|
||||
return nil, fmt.Errorf("flag value not accepted: %s=%s", flag.Name, flag.BuiltValue)
|
||||
}
|
||||
acceptedValue := flag.AcceptedValues[acceptedValueIndex]
|
||||
|
||||
pkgInfo.Flags[i] = flag
|
||||
|
||||
pkgInfo.Depends = append(pkgInfo.Depends, acceptedValue.Depends...)
|
||||
pkgInfo.RuntimeDepends = append(pkgInfo.RuntimeDepends, acceptedValue.RuntimeDepends...)
|
||||
pkgInfo.OptionalDepends = append(pkgInfo.OptionalDepends, acceptedValue.OptionalDepends...)
|
||||
pkgInfo.MakeDepends = append(pkgInfo.MakeDepends, acceptedValue.MakeDepends...)
|
||||
pkgInfo.CheckDepends = append(pkgInfo.CheckDepends, acceptedValue.CheckDepends...)
|
||||
}
|
||||
|
||||
// Marshal package info
|
||||
pkgInfoBytes, err := yaml.Marshal(pkgInfo)
|
||||
if err != nil {
|
||||
|
||||
+143
-49
@@ -42,7 +42,7 @@ type BPMDatabaseEntry struct {
|
||||
Database *BPMDatabase
|
||||
}
|
||||
|
||||
var BPMDatabases = make(map[string]*BPMDatabase)
|
||||
var BPMDatabases = make([]*BPMDatabase, 0)
|
||||
|
||||
func (db *BPMDatabase) ContainsPackage(pkg string) bool {
|
||||
_, ok := db.Entries[pkg]
|
||||
@@ -135,7 +135,7 @@ func (db *configDatabase) ReadLocalDatabase() error {
|
||||
}
|
||||
}
|
||||
|
||||
BPMDatabases[db.Name] = database
|
||||
BPMDatabases = append(BPMDatabases, database)
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -207,61 +207,76 @@ func ReadLocalDatabaseFiles() (err error) {
|
||||
return nil
|
||||
}
|
||||
|
||||
func ResolveDatabaseEntry(pkg string, rootDir string) *BPMDatabaseEntry {
|
||||
entry := GetDatabaseEntry(pkg)
|
||||
if entry != nil {
|
||||
return entry
|
||||
}
|
||||
func ResolveDatabaseEntry(d DeconstructedPackageString, rootDir string) *BPMDatabaseEntry {
|
||||
results := SearchDatabaseEntries(d.PkgName)
|
||||
for _, result := range results {
|
||||
|
||||
installedProviders := GetVirtualPackageInfo(pkg, rootDir)
|
||||
if len(installedProviders) > 0 {
|
||||
entry := GetDatabaseEntry(installedProviders[0].Name)
|
||||
if entry != nil {
|
||||
return entry
|
||||
if EvaluatePackageString(result.Info, d) {
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
databaseProviders := GetDatabaseVirtualPackageEntry(pkg)
|
||||
if len(databaseProviders) > 0 {
|
||||
entry := GetDatabaseEntry(databaseProviders[0].Info.Name)
|
||||
if entry != nil {
|
||||
return entry
|
||||
installedProviders := GetVirtualPackageInfo(d.PkgName, rootDir)
|
||||
for _, provider := range installedProviders {
|
||||
results := SearchDatabaseEntries(provider.Name)
|
||||
for _, result := range results {
|
||||
if EvaluatePackageString(result.Info, d) {
|
||||
return result
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
databaseProviders := SearchDatabaseVirtualPackageProviders(d.PkgName)
|
||||
for _, provider := range databaseProviders {
|
||||
results := SearchDatabaseEntries(provider.Info.Name)
|
||||
for _, result := range results {
|
||||
if EvaluatePackageString(result.Info, d) {
|
||||
return result
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func GetDatabaseEntry(pkg string) *BPMDatabaseEntry {
|
||||
func SearchDatabaseEntries(pkg string) (results []*BPMDatabaseEntry) {
|
||||
split := strings.Split(pkg, "/")
|
||||
if len(split) == 1 {
|
||||
pkgName := strings.TrimSpace(split[0])
|
||||
if pkgName == "" {
|
||||
return nil
|
||||
return results
|
||||
}
|
||||
for _, db := range BPMDatabases {
|
||||
if db.ContainsPackage(pkgName) {
|
||||
return db.Entries[pkgName]
|
||||
results = append(results, db.Entries[pkgName])
|
||||
}
|
||||
}
|
||||
return nil
|
||||
return results
|
||||
} else if len(split) == 2 {
|
||||
dbName := strings.TrimSpace(split[0])
|
||||
pkgName := strings.TrimSpace(split[1])
|
||||
if dbName == "" || pkgName == "" {
|
||||
return nil
|
||||
}
|
||||
db := BPMDatabases[dbName]
|
||||
if db == nil || !db.ContainsPackage(pkgName) {
|
||||
return nil
|
||||
}
|
||||
return db.Entries[pkgName]
|
||||
} else {
|
||||
return nil
|
||||
return results
|
||||
}
|
||||
dbIndex := slices.IndexFunc(BPMDatabases, func(db *BPMDatabase) bool {
|
||||
return db.Name == dbName
|
||||
})
|
||||
if dbIndex < 0 {
|
||||
return results
|
||||
}
|
||||
|
||||
func GetDatabaseVirtualPackageEntry(vpkg string) (providers []*BPMDatabaseEntry) {
|
||||
db := BPMDatabases[dbIndex]
|
||||
if !db.ContainsPackage(pkgName) {
|
||||
return results
|
||||
}
|
||||
|
||||
results = append(results, db.Entries[pkgName])
|
||||
}
|
||||
|
||||
return results
|
||||
}
|
||||
|
||||
func SearchDatabaseVirtualPackageProviders(vpkg string) (providers []*BPMDatabaseEntry) {
|
||||
for _, db := range BPMDatabases {
|
||||
providers = append(providers, db.VirtualPackages[vpkg]...)
|
||||
}
|
||||
@@ -336,8 +351,12 @@ func (entry *BPMDatabaseEntry) GetEntryDependants() (dependants []string) {
|
||||
|
||||
// Add installed package to list if its dependencies include pkgName
|
||||
if slices.ContainsFunc(e.Info.Depends, func(n string) bool {
|
||||
n, _, _ = SplitPkgNameAndVersion(n)
|
||||
return n == entry.Info.Name
|
||||
d, err := DeconstructPackageString(n)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
return d.PkgName == entry.Info.Name
|
||||
}) {
|
||||
dependantsMap[e.Info.Name] = append(dependantsMap[e.Info.Name], db.Name)
|
||||
continue
|
||||
@@ -345,8 +364,12 @@ func (entry *BPMDatabaseEntry) GetEntryDependants() (dependants []string) {
|
||||
|
||||
// Add installed package to list if its runtime dependencies include pkgName
|
||||
if slices.ContainsFunc(e.Info.RuntimeDepends, func(n string) bool {
|
||||
n, _, _ = SplitPkgNameAndVersion(n)
|
||||
return n == entry.Info.Name
|
||||
d, err := DeconstructPackageString(n)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
return d.PkgName == entry.Info.Name
|
||||
}) {
|
||||
dependantsMap[e.Info.Name] = append(dependantsMap[e.Info.Name], db.Name)
|
||||
continue
|
||||
@@ -356,8 +379,12 @@ func (entry *BPMDatabaseEntry) GetEntryDependants() (dependants []string) {
|
||||
for _, vpkg := range entry.Info.Provides {
|
||||
// Add installed package to list if its dependencies contain a provided virtual package
|
||||
if slices.ContainsFunc(e.Info.Depends, func(n string) bool {
|
||||
n, _, _ = SplitPkgNameAndVersion(n)
|
||||
return n == vpkg
|
||||
d, err := DeconstructPackageString(n)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
return d.PkgName == vpkg
|
||||
}) {
|
||||
dependantsMap[e.Info.Name] = append(dependantsMap[e.Info.Name], db.Name)
|
||||
break
|
||||
@@ -365,8 +392,12 @@ func (entry *BPMDatabaseEntry) GetEntryDependants() (dependants []string) {
|
||||
|
||||
// Add installed package to list if its runtime dependencies contain a provided virtual package
|
||||
if slices.ContainsFunc(e.Info.RuntimeDepends, func(n string) bool {
|
||||
n, _, _ = SplitPkgNameAndVersion(n)
|
||||
return n == vpkg
|
||||
d, err := DeconstructPackageString(n)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
return d.PkgName == vpkg
|
||||
}) {
|
||||
dependantsMap[e.Info.Name] = append(dependantsMap[e.Info.Name], db.Name)
|
||||
break
|
||||
@@ -399,13 +430,13 @@ func (entry *BPMDatabaseEntry) GetEntryOptionalDependants() (dependants []string
|
||||
for _, db := range BPMDatabases {
|
||||
for _, e := range db.Entries {
|
||||
if slices.ContainsFunc(e.Info.OptionalDepends, func(n string) bool {
|
||||
// Remove optional dependency comment
|
||||
n = strings.SplitN(n, ":", 2)[0]
|
||||
// Deconstruct package string
|
||||
d, err := DeconstructPackageString(n)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
// Remove required version
|
||||
n, _, _ = SplitPkgNameAndVersion(n)
|
||||
|
||||
return n == entry.Info.Name
|
||||
return d.PkgName == entry.Info.Name
|
||||
}) {
|
||||
dependantsMap[e.Info.Name] = append(dependantsMap[e.Info.Name], e.Database.Name)
|
||||
}
|
||||
@@ -436,8 +467,13 @@ func (entry *BPMDatabaseEntry) GetEntryMakeDependants() (dependants []string) {
|
||||
for _, db := range BPMDatabases {
|
||||
for _, e := range db.Entries {
|
||||
if slices.ContainsFunc(e.Info.MakeDepends, func(n string) bool {
|
||||
n, _, _ = SplitPkgNameAndVersion(n)
|
||||
return n == entry.Info.Name
|
||||
// Deconstruct package string
|
||||
d, err := DeconstructPackageString(n)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
return d.PkgName == entry.Info.Name
|
||||
}) {
|
||||
dependantsMap[e.Info.Name] = append(dependantsMap[e.Info.Name], e.Database.Name)
|
||||
}
|
||||
@@ -498,7 +534,7 @@ func (entry *BPMDatabaseEntry) CreateReadableInfo(rootDir string, showBytes bool
|
||||
builder.WriteString(" - " + val)
|
||||
|
||||
// Show virtual package providers
|
||||
if providers := GetDatabaseVirtualPackageEntry(val); len(providers) > 0 {
|
||||
if providers := SearchDatabaseVirtualPackageProviders(val); len(providers) > 0 {
|
||||
builder.WriteString(" (")
|
||||
for i, vpkg := range providers {
|
||||
if i == len(providers)-1 {
|
||||
@@ -528,6 +564,64 @@ func (entry *BPMDatabaseEntry) CreateReadableInfo(rootDir string, showBytes bool
|
||||
}
|
||||
builder.WriteString("Type: " + entry.Info.Type + "\n")
|
||||
|
||||
// Flags
|
||||
if entry.Info.Type == "binary" {
|
||||
var flags []string
|
||||
for _, flag := range entry.Info.Flags {
|
||||
flags = append(flags, fmt.Sprintf("%s=%s", flag.Name, flag.BuiltValue))
|
||||
}
|
||||
builderWriteArray("Built with flags:", flags, false)
|
||||
} else {
|
||||
if len(entry.Info.Flags) > 0 {
|
||||
builder.WriteString("Available flags (")
|
||||
builder.WriteString(strconv.Itoa(len(entry.Info.Flags)))
|
||||
builder.WriteString("):\n")
|
||||
for _, flag := range entry.Info.Flags {
|
||||
builder.WriteString(" - Flag: ")
|
||||
builder.WriteString(flag.Name)
|
||||
builder.WriteRune('\n')
|
||||
if flag.DefaultValue != "" {
|
||||
builder.WriteString(" Default value: ")
|
||||
builder.WriteString(flag.DefaultValue)
|
||||
builder.WriteRune('\n')
|
||||
}
|
||||
if len(flag.AcceptedValues) > 0 {
|
||||
builder.WriteString(" Accepted values (")
|
||||
builder.WriteString(strconv.Itoa(len(flag.AcceptedValues)))
|
||||
builder.WriteString("):\n")
|
||||
|
||||
for i, acceptedValue := range flag.AcceptedValues {
|
||||
writeValueDepends := func(text string, depends []string) {
|
||||
if len(depends) > 0 {
|
||||
builder.WriteString(" ")
|
||||
builder.WriteString(text)
|
||||
builder.WriteString(" (")
|
||||
builder.WriteString(strconv.Itoa(len(depends)))
|
||||
builder.WriteString("): ")
|
||||
for _, depend := range depends {
|
||||
if i != 0 {
|
||||
builder.WriteString(", ")
|
||||
}
|
||||
builder.WriteString(depend)
|
||||
}
|
||||
builder.WriteRune('\n')
|
||||
}
|
||||
}
|
||||
|
||||
builder.WriteString(" - Value: ")
|
||||
builder.WriteString(acceptedValue.Value)
|
||||
builder.WriteRune('\n')
|
||||
writeValueDepends("Dependencies", acceptedValue.Depends)
|
||||
writeValueDepends("Make Dependencies", acceptedValue.MakeDepends)
|
||||
writeValueDepends("Check Dependencies", acceptedValue.CheckDepends)
|
||||
writeValueDepends("Runtime Dependencies", acceptedValue.RuntimeDepends)
|
||||
writeValueDepends("Optional Dependencies", acceptedValue.OptionalDepends)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Dependencies
|
||||
builderWriteDependencyArray("Dependencies", entry.Info.Depends)
|
||||
if entry.Info.Type == "source" {
|
||||
@@ -546,7 +640,7 @@ func (entry *BPMDatabaseEntry) CreateReadableInfo(rootDir string, showBytes bool
|
||||
}
|
||||
|
||||
// Show virtual package providers
|
||||
if providers := GetDatabaseVirtualPackageEntry(dependSplit[0]); len(providers) > 0 {
|
||||
if providers := SearchDatabaseVirtualPackageProviders(dependSplit[0]); len(providers) > 0 {
|
||||
builder.WriteString(" (")
|
||||
for i, vpkg := range providers {
|
||||
if i == len(providers)-1 {
|
||||
|
||||
+264
-90
@@ -1,6 +1,8 @@
|
||||
package bpmlib
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"maps"
|
||||
"slices"
|
||||
"strings"
|
||||
)
|
||||
@@ -21,8 +23,13 @@ func (pkgInfo *PackageInfo) GetPackageDependants(rootDir string, skipMultiplePro
|
||||
|
||||
// Add installed package to list if its dependencies include pkgName
|
||||
if slices.ContainsFunc(installedPkg.Depends, func(n string) bool {
|
||||
n, _, _ = SplitPkgNameAndVersion(n)
|
||||
return n == pkgInfo.Name
|
||||
// Deconstruct package string
|
||||
d, err := DeconstructPackageString(n)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
return d.PkgName == pkgInfo.Name
|
||||
}) {
|
||||
dependants = append(dependants, installedPkg.Name)
|
||||
continue
|
||||
@@ -30,8 +37,13 @@ func (pkgInfo *PackageInfo) GetPackageDependants(rootDir string, skipMultiplePro
|
||||
|
||||
// Add installed package to list if its runtime dependencies include pkgName
|
||||
if slices.ContainsFunc(installedPkg.RuntimeDepends, func(n string) bool {
|
||||
n, _, _ = SplitPkgNameAndVersion(n)
|
||||
return n == pkgInfo.Name
|
||||
// Deconstruct package string
|
||||
d, err := DeconstructPackageString(n)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
return d.PkgName == pkgInfo.Name
|
||||
}) {
|
||||
dependants = append(dependants, installedPkg.Name)
|
||||
continue
|
||||
@@ -45,8 +57,13 @@ func (pkgInfo *PackageInfo) GetPackageDependants(rootDir string, skipMultiplePro
|
||||
|
||||
// Add installed package to list if its dependencies contain a provided virtual package
|
||||
if slices.ContainsFunc(installedPkg.Depends, func(n string) bool {
|
||||
n, _, _ = SplitPkgNameAndVersion(n)
|
||||
return n == vpkg
|
||||
// Deconstruct package string
|
||||
d, err := DeconstructPackageString(n)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
return d.PkgName == vpkg
|
||||
}) {
|
||||
dependants = append(dependants, installedPkg.Name)
|
||||
break
|
||||
@@ -54,8 +71,13 @@ func (pkgInfo *PackageInfo) GetPackageDependants(rootDir string, skipMultiplePro
|
||||
|
||||
// Add installed package to list if its runtime dependencies contain a provided virtual package
|
||||
if slices.ContainsFunc(installedPkg.RuntimeDepends, func(n string) bool {
|
||||
n, _, _ = SplitPkgNameAndVersion(n)
|
||||
return n == vpkg
|
||||
// Deconstruct package string
|
||||
d, err := DeconstructPackageString(n)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
return d.PkgName == vpkg
|
||||
}) {
|
||||
dependants = append(dependants, installedPkg.Name)
|
||||
break
|
||||
@@ -82,13 +104,13 @@ func (pkgInfo *PackageInfo) GetPackageOptionalDependants(rootDir string) (depend
|
||||
|
||||
// Add installed package to list if its optional dependencies include pkgName
|
||||
if slices.ContainsFunc(installedPkg.OptionalDepends, func(n string) bool {
|
||||
// Remove optional dependency comment
|
||||
n = strings.SplitN(n, ":", 2)[0]
|
||||
// Deconstruct package string
|
||||
d, err := DeconstructPackageString(n)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
// Remove required version
|
||||
n, _, _ = SplitPkgNameAndVersion(n)
|
||||
|
||||
return n == pkgInfo.Name
|
||||
return d.PkgName == pkgInfo.Name
|
||||
}) {
|
||||
dependants = append(dependants, installedPkg.Name)
|
||||
continue
|
||||
@@ -98,13 +120,13 @@ func (pkgInfo *PackageInfo) GetPackageOptionalDependants(rootDir string) (depend
|
||||
for _, vpkg := range pkgInfo.Provides {
|
||||
// Add installed package to list if its optional dependencies contain a provided virtual package
|
||||
if slices.ContainsFunc(installedPkg.OptionalDepends, func(n string) bool {
|
||||
// Remove optional dependency comment
|
||||
n = strings.SplitN(n, ":", 2)[0]
|
||||
// Deconstruct package string
|
||||
d, err := DeconstructPackageString(n)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
// Remove required version
|
||||
n, _, _ = SplitPkgNameAndVersion(n)
|
||||
|
||||
return n == vpkg
|
||||
return d.PkgName == vpkg
|
||||
}) {
|
||||
dependants = append(dependants, installedPkg.Name)
|
||||
break
|
||||
@@ -117,49 +139,74 @@ func (pkgInfo *PackageInfo) GetPackageOptionalDependants(rootDir string) (depend
|
||||
|
||||
type ResolvedPackage struct {
|
||||
DatabaseEntry *BPMDatabaseEntry
|
||||
Flags map[string]string
|
||||
InstallationReason InstallationReason
|
||||
}
|
||||
|
||||
func ResolveDependencies(pkgInfo *PackageInfo, resolvedVirtualPackages map[string]string, includeRuntimeDepends bool, rootDir string) (resolved []ResolvedPackage, unresolved []string) {
|
||||
func ResolveDependencies(pkgInfo *PackageInfo, flags, resolvedVirtualPackages map[string]string, includeRuntimeDepends bool, rootDir string) (resolved []ResolvedPackage, unresolved map[string]string) {
|
||||
unresolved = make(map[string]string)
|
||||
visited := make([]string, 0)
|
||||
|
||||
var dfs func(resolvedPkg *PackageInfo)
|
||||
dfs = func(pkgInfo *PackageInfo) {
|
||||
var dfs func(resolvedPkg *PackageInfo, flags map[string]string)
|
||||
dfs = func(pkgInfo *PackageInfo, flags map[string]string) {
|
||||
checkDependencies := func(dependencies []string, installationReason InstallationReason) {
|
||||
for _, depend := range dependencies {
|
||||
// Split dependency name and required version
|
||||
dependName, _, _ := SplitPkgNameAndVersion(depend)
|
||||
|
||||
// Ignore if package is already installed
|
||||
if IsPackageInstalled(dependName, rootDir) && EvaluateDependency(depend, GetPackageInfo(dependName, rootDir).Version) {
|
||||
continue
|
||||
} else if providers := GetVirtualPackageInfo(dependName, rootDir); len(providers) > 0 {
|
||||
// Deconstruct package string
|
||||
d, err := DeconstructPackageString(depend)
|
||||
if err != nil {
|
||||
unresolved[depend] = "could not deconstruct package string: " + err.Error()
|
||||
continue
|
||||
}
|
||||
|
||||
// Check resolved virtual packages
|
||||
if resolvedPkg, ok := resolvedVirtualPackages[dependName]; ok {
|
||||
dependName = resolvedPkg
|
||||
if resolvedPkg, ok := resolvedVirtualPackages[d.PkgName]; ok {
|
||||
d.PkgName = resolvedPkg
|
||||
}
|
||||
|
||||
// Find database entry for dependency
|
||||
dependEntry := ResolveDatabaseEntry(dependName, rootDir)
|
||||
dependEntry := ResolveDatabaseEntry(d, rootDir)
|
||||
if dependEntry == nil {
|
||||
unresolved = append(unresolved, depend)
|
||||
continue
|
||||
}
|
||||
|
||||
// Ensure entry has required version
|
||||
if !EvaluateDependency(depend, dependEntry.Info.Version) {
|
||||
unresolved = append(unresolved, depend)
|
||||
unresolved[depend] = "could not find in any database"
|
||||
continue
|
||||
}
|
||||
d.PkgName = dependEntry.Info.Name
|
||||
|
||||
// Skip ignored packages in config
|
||||
if rootDir == "/" && slices.Contains(MainBPMConfig.IgnorePackages, dependEntry.Info.Name) {
|
||||
continue
|
||||
}
|
||||
|
||||
// Add user defined package flags and resolve entry again if package is already installed
|
||||
if installedInfo := GetPackageInfo(dependEntry.Info.Name, rootDir); installedInfo != nil {
|
||||
d.Flags, err = CombineFlags(getPackageLocalInfo(dependEntry.Info.Name, rootDir).Flags, d.Flags)
|
||||
if err != nil {
|
||||
unresolved[depend] = "could not combine flags: " + err.Error()
|
||||
continue
|
||||
}
|
||||
|
||||
dependEntry = ResolveDatabaseEntry(d, rootDir)
|
||||
if dependEntry == nil {
|
||||
unresolved[depend] = "could not find in any database"
|
||||
continue
|
||||
}
|
||||
|
||||
shouldIgnore := true
|
||||
|
||||
// Skip if no update/downgrade is available
|
||||
if installedInfo.GetFullVersion() != dependEntry.Info.GetFullVersion() {
|
||||
shouldIgnore = false
|
||||
}
|
||||
|
||||
// Skip if no new package flags
|
||||
if !maps.Equal(getPackageLocalInfo(dependEntry.Info.Name, rootDir).Flags, d.Flags) {
|
||||
shouldIgnore = false
|
||||
}
|
||||
|
||||
if shouldIgnore {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
// Resolve virtual packages
|
||||
for _, vpkg := range dependEntry.Info.Provides {
|
||||
if _, ok := resolvedVirtualPackages[vpkg]; !ok {
|
||||
@@ -169,8 +216,8 @@ func ResolveDependencies(pkgInfo *PackageInfo, resolvedVirtualPackages map[strin
|
||||
|
||||
// Resolve entry dependencies
|
||||
if !slices.Contains(visited, dependEntry.Info.Name) {
|
||||
dfs(dependEntry.Info)
|
||||
resolved = append(resolved, ResolvedPackage{DatabaseEntry: dependEntry, InstallationReason: installationReason})
|
||||
dfs(dependEntry.Info, d.Flags)
|
||||
resolved = append(resolved, ResolvedPackage{DatabaseEntry: dependEntry, Flags: d.Flags, InstallationReason: installationReason})
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -184,69 +231,196 @@ func ResolveDependencies(pkgInfo *PackageInfo, resolvedVirtualPackages map[strin
|
||||
if pkgInfo.Type == "source" {
|
||||
checkDependencies(pkgInfo.MakeDepends, InstallationReasonMakeDependency)
|
||||
checkDependencies(pkgInfo.CheckDepends, InstallationReasonMakeDependency)
|
||||
|
||||
// Resolve flag-specific dependencies
|
||||
for _, flag := range pkgInfo.Flags {
|
||||
acceptedValueIndex := slices.IndexFunc(flag.AcceptedValues, func(acceptedValue PackageAcceptedValue) bool {
|
||||
if value, ok := flags[flag.Name]; ok {
|
||||
return acceptedValue.Value == value
|
||||
} else {
|
||||
return acceptedValue.Value == flag.DefaultValue
|
||||
}
|
||||
})
|
||||
if acceptedValueIndex < 0 {
|
||||
continue
|
||||
}
|
||||
acceptedValue := flag.AcceptedValues[acceptedValueIndex]
|
||||
|
||||
checkDependencies(acceptedValue.Depends, InstallationReasonDependency)
|
||||
checkDependencies(acceptedValue.RuntimeDepends, InstallationReasonDependency)
|
||||
checkDependencies(acceptedValue.MakeDepends, InstallationReasonMakeDependency)
|
||||
checkDependencies(acceptedValue.CheckDepends, InstallationReasonMakeDependency)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dfs(pkgInfo)
|
||||
dfs(pkgInfo, flags)
|
||||
|
||||
return resolved, unresolved
|
||||
}
|
||||
|
||||
func SplitPkgNameAndVersion(pkg string) (string, string, string) {
|
||||
if strings.Contains(pkg, ">=") {
|
||||
pkgSplit := strings.SplitN(pkg, ">=", 2)
|
||||
pkgName := pkgSplit[0]
|
||||
pkgVersion := pkgSplit[1]
|
||||
|
||||
return pkgName, ">=", pkgVersion
|
||||
} else if strings.Contains(pkg, ">") {
|
||||
pkgSplit := strings.SplitN(pkg, ">", 2)
|
||||
pkgName := pkgSplit[0]
|
||||
pkgVersion := pkgSplit[1]
|
||||
|
||||
return pkgName, ">", pkgVersion
|
||||
} else if strings.Contains(pkg, "<=") {
|
||||
pkgSplit := strings.SplitN(pkg, "<=", 2)
|
||||
pkgName := pkgSplit[0]
|
||||
pkgVersion := pkgSplit[1]
|
||||
|
||||
return pkgName, "<=", pkgVersion
|
||||
} else if strings.Contains(pkg, "<") {
|
||||
pkgSplit := strings.SplitN(pkg, "<", 2)
|
||||
pkgName := pkgSplit[0]
|
||||
pkgVersion := pkgSplit[1]
|
||||
|
||||
return pkgName, "<", pkgVersion
|
||||
} else if strings.Contains(pkg, "=") {
|
||||
pkgSplit := strings.SplitN(pkg, "=", 2)
|
||||
pkgName := pkgSplit[0]
|
||||
pkgVersion := pkgSplit[1]
|
||||
|
||||
return pkgName, "=", pkgVersion
|
||||
type DeconstructedPackageString struct {
|
||||
PkgName string
|
||||
Description string
|
||||
Flags map[string]string
|
||||
RequiredVersionOperator string
|
||||
RequiredVersion string
|
||||
}
|
||||
|
||||
return pkg, "", ""
|
||||
func DeconstructPackageString(pkg string) (ret DeconstructedPackageString, err error) {
|
||||
// Initialize values
|
||||
ret.Flags = make(map[string]string)
|
||||
|
||||
// Get dependency description
|
||||
if i := strings.IndexRune(pkg, ':'); i > 0 {
|
||||
ret.Description = pkg[i+1:]
|
||||
pkg = pkg[0:i]
|
||||
}
|
||||
|
||||
func EvaluateDependency(pkg, matchVersion string) bool {
|
||||
_, comparisonSymbol, pkgVersion := SplitPkgNameAndVersion(pkg)
|
||||
if left := strings.IndexRune(pkg, '['); left > 0 {
|
||||
if right := strings.IndexRune(pkg, ']'); right > left {
|
||||
flagsStr := pkg[left+1 : right]
|
||||
pkg = pkg[0:left] + pkg[right+1:]
|
||||
|
||||
switch comparisonSymbol {
|
||||
case ">=":
|
||||
return CompareVersions(matchVersion, pkgVersion) >= 0
|
||||
case ">":
|
||||
return CompareVersions(matchVersion, pkgVersion) > 0
|
||||
case "<=":
|
||||
return CompareVersions(matchVersion, pkgVersion) <= 0
|
||||
case "<":
|
||||
return CompareVersions(matchVersion, pkgVersion) < 0
|
||||
case "=":
|
||||
if cutPkgVersion, ok := strings.CutSuffix(pkgVersion, "*"); ok {
|
||||
return strings.HasPrefix(matchVersion, cutPkgVersion)
|
||||
if flagsStr != "" {
|
||||
for flag := range strings.SplitSeq(flagsStr, ",") {
|
||||
flagSplit := strings.SplitN(flag, "=", 2)
|
||||
if len(flagSplit) != 2 {
|
||||
return ret, fmt.Errorf("could not parse flag: %s", flag)
|
||||
}
|
||||
|
||||
ret.Flags[flagSplit[0]] = flagSplit[1]
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return CompareVersions(matchVersion, pkgVersion) == 0
|
||||
return ret, fmt.Errorf("could not find closing square bracket for set flags")
|
||||
}
|
||||
}
|
||||
|
||||
if strings.Contains(pkg, ">=") {
|
||||
ret.RequiredVersionOperator = ">="
|
||||
} else if strings.Contains(pkg, ">") {
|
||||
ret.RequiredVersionOperator = ">"
|
||||
} else if strings.Contains(pkg, "<=") {
|
||||
ret.RequiredVersionOperator = "<="
|
||||
} else if strings.Contains(pkg, "<") {
|
||||
ret.RequiredVersionOperator = "<"
|
||||
} else if strings.Contains(pkg, "=") {
|
||||
ret.RequiredVersionOperator = "="
|
||||
}
|
||||
if ret.RequiredVersionOperator != "" {
|
||||
pkgSplit := strings.SplitN(pkg, ret.RequiredVersionOperator, 2)
|
||||
if len(pkgSplit) != 2 {
|
||||
return ret, fmt.Errorf("could not parse required version: %s", pkg)
|
||||
}
|
||||
pkg = pkgSplit[0]
|
||||
ret.RequiredVersion = pkgSplit[1]
|
||||
}
|
||||
|
||||
ret.PkgName = pkg
|
||||
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func EvaluatePackageString(pkgInfo *PackageInfo, match DeconstructedPackageString) bool {
|
||||
// Validate flags
|
||||
for flag, value := range match.Flags {
|
||||
pkgFlagIndex := slices.IndexFunc(pkgInfo.Flags, func(f PackageFlag) bool {
|
||||
return f.Name == flag
|
||||
})
|
||||
if pkgFlagIndex < 0 {
|
||||
return false
|
||||
}
|
||||
pkgFlag := pkgInfo.Flags[pkgFlagIndex]
|
||||
|
||||
if pkgInfo.Type == "binary" {
|
||||
if pkgFlag.BuiltValue != value {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
if len(pkgFlag.AcceptedValues) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
if !slices.ContainsFunc(pkgFlag.AcceptedValues, func(acceptedFlag PackageAcceptedValue) bool {
|
||||
return acceptedFlag.Value == value
|
||||
}) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// Validate version
|
||||
switch match.RequiredVersionOperator {
|
||||
case ">=":
|
||||
return CompareVersions(match.RequiredVersion, pkgInfo.Version) >= 0
|
||||
case ">":
|
||||
return CompareVersions(match.RequiredVersion, pkgInfo.Version) > 0
|
||||
case "<=":
|
||||
return CompareVersions(match.RequiredVersion, pkgInfo.Version) <= 0
|
||||
case "<":
|
||||
return CompareVersions(match.RequiredVersion, pkgInfo.Version) < 0
|
||||
case "=":
|
||||
if cutPkgVersion, ok := strings.CutSuffix(match.RequiredVersion, "*"); ok {
|
||||
return strings.HasPrefix(pkgInfo.Version, cutPkgVersion)
|
||||
} else {
|
||||
return CompareVersions(pkgInfo.Version, match.RequiredVersion) == 0
|
||||
}
|
||||
default:
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
func GetBuiltFlags(pkg, rootDir string) map[string]string {
|
||||
builtFlags := make(map[string]string)
|
||||
|
||||
pkgInfo := GetPackageInfo(pkg, rootDir)
|
||||
if pkgInfo == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
for _, flag := range pkgInfo.Flags {
|
||||
builtFlags[flag.Name] = flag.BuiltValue
|
||||
}
|
||||
|
||||
return builtFlags
|
||||
}
|
||||
|
||||
func RemoveInvalidFlags(pkgInfo *PackageInfo, userFlags map[string]string) (ret map[string]string) {
|
||||
ret = make(map[string]string)
|
||||
|
||||
for userFlag, userValue := range userFlags {
|
||||
flagIndex := slices.IndexFunc(pkgInfo.Flags, func(flag PackageFlag) bool {
|
||||
return flag.Name == userFlag
|
||||
})
|
||||
if flagIndex < 0 {
|
||||
continue
|
||||
}
|
||||
flag := pkgInfo.Flags[flagIndex]
|
||||
|
||||
if len(flag.AcceptedValues) > 0 && !slices.ContainsFunc(flag.AcceptedValues, func(acceptedValue PackageAcceptedValue) bool {
|
||||
return acceptedValue.Value == userValue
|
||||
}) {
|
||||
continue
|
||||
}
|
||||
|
||||
ret[userFlag] = userValue
|
||||
}
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
func CombineFlags(flags, newFlags map[string]string) (map[string]string, error) {
|
||||
ret := make(map[string]string)
|
||||
maps.Copy(ret, flags)
|
||||
|
||||
for flag, value := range newFlags {
|
||||
if oldValue, ok := flags[flag]; ok && value != oldValue {
|
||||
return ret, fmt.Errorf("flag already defined: %s=%s/%s", flag, oldValue, value)
|
||||
}
|
||||
|
||||
ret[flag] = value
|
||||
}
|
||||
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
+11
-12
@@ -2,26 +2,25 @@ package bpmlib
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"maps"
|
||||
"slices"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type PackageNotFoundErr struct {
|
||||
packages []string
|
||||
type PackageNotResolvedErr struct {
|
||||
packages map[string]string
|
||||
}
|
||||
|
||||
func (e PackageNotFoundErr) Error() string {
|
||||
slices.Sort(e.packages)
|
||||
return "The following packages were not found in any databases: " + strings.Join(e.packages, ", ")
|
||||
func (e PackageNotResolvedErr) Error() (ret string) {
|
||||
ret = "The following packages could not be resolved:"
|
||||
|
||||
keys := slices.Collect(maps.Keys(e.packages))
|
||||
slices.Sort(keys)
|
||||
for _, key := range keys {
|
||||
ret += "\n " + key + ": " + e.packages[key]
|
||||
}
|
||||
|
||||
type DependencyNotFoundErr struct {
|
||||
dependencies []string
|
||||
}
|
||||
|
||||
func (e DependencyNotFoundErr) Error() string {
|
||||
slices.Sort(e.dependencies)
|
||||
return "The following dependencies were not found in any databases: " + strings.Join(e.dependencies, ", ")
|
||||
return ret
|
||||
}
|
||||
|
||||
type PackageConflictErr struct {
|
||||
|
||||
+123
-30
@@ -16,7 +16,7 @@ func InstallPackages(rootDir string, forceInstallationReason InstallationReason,
|
||||
// Setup operation struct
|
||||
operation = &BPMOperation{
|
||||
Actions: make([]OperationAction, 0),
|
||||
UnresolvedDepends: make([]string, 0),
|
||||
UnresolvedDepends: make(map[string]string, 0),
|
||||
ModifiedFiles: make(map[string]string),
|
||||
RunChecks: runChecks,
|
||||
RootDir: rootDir,
|
||||
@@ -27,21 +27,58 @@ func InstallPackages(rootDir string, forceInstallationReason InstallationReason,
|
||||
packages = removeDuplicates(packages)
|
||||
|
||||
// Resolve packages
|
||||
pkgsNotFound := make([]string, 0)
|
||||
unresolvedPackages := make(map[string]string)
|
||||
resolvedVirtualPackages := make(map[string]string)
|
||||
for _, pkg := range packages {
|
||||
if stat, err := os.Stat(pkg); err == nil && !stat.IsDir() {
|
||||
bpmpkg, err := ReadPackage(pkg)
|
||||
d, err := DeconstructPackageString(pkg)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not deconstruct package string: %s", err)
|
||||
}
|
||||
|
||||
if stat, err := os.Stat(d.PkgName); err == nil && !stat.IsDir() {
|
||||
bpmpkg, err := ReadPackage(d.PkgName)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not read package: %s", err)
|
||||
}
|
||||
|
||||
if bpmpkg.PkgInfo.Type == "source" && bpmpkg.PkgInfo.IsSplitPackage() {
|
||||
// Add user defined package flags
|
||||
if !reinstallPackages && IsPackageInstalled(bpmpkg.PkgInfo.Name, rootDir) {
|
||||
d.Flags, err = CombineFlags(getPackageLocalInfo(bpmpkg.PkgInfo.Name, rootDir).Flags, d.Flags)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not combine flags for package (%s): %s", bpmpkg.PkgInfo.Name, err)
|
||||
}
|
||||
}
|
||||
|
||||
if !EvaluatePackageString(bpmpkg.PkgInfo, d) {
|
||||
unresolvedPackages[pkg] = "could not evaluate package"
|
||||
continue
|
||||
}
|
||||
|
||||
if bpmpkg.PkgInfo.IsSplitPackage() {
|
||||
for _, splitPkg := range bpmpkg.PkgInfo.SplitPackages {
|
||||
if !reinstallPackages && IsPackageInstalled(splitPkg.Name, rootDir) && GetPackageInfo(splitPkg.Name, rootDir).GetFullVersion() == splitPkg.GetFullVersion() {
|
||||
continue
|
||||
}
|
||||
|
||||
// Check if installation can be ignored
|
||||
if !reinstallPackages && IsPackageInstalled(splitPkg.Name, rootDir) {
|
||||
shouldIgnore := true
|
||||
|
||||
// Skip if no update/downgrade is available
|
||||
if GetPackageInfo(splitPkg.Name, rootDir).GetFullVersion() != splitPkg.GetFullVersion() {
|
||||
shouldIgnore = false
|
||||
}
|
||||
|
||||
// Skip if no new package flags
|
||||
if !maps.Equal(getPackageLocalInfo(splitPkg.Name, rootDir).Flags, d.Flags) {
|
||||
shouldIgnore = false
|
||||
}
|
||||
|
||||
if shouldIgnore {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
// Set package installation reason
|
||||
installationReason := forceInstallationReason
|
||||
if installationReason == InstallationReasonUnknown {
|
||||
@@ -52,9 +89,17 @@ func InstallPackages(rootDir string, forceInstallationReason InstallationReason,
|
||||
}
|
||||
}
|
||||
|
||||
// Resolve virtual packages
|
||||
for _, vpkg := range splitPkg.Provides {
|
||||
if _, ok := resolvedVirtualPackages[vpkg]; !ok {
|
||||
resolvedVirtualPackages[vpkg] = splitPkg.Name
|
||||
}
|
||||
}
|
||||
|
||||
operation.Actions = append(operation.Actions, &InstallPackageAction{
|
||||
File: pkg,
|
||||
InstallationReason: installationReason,
|
||||
Flags: d.Flags,
|
||||
BpmPackage: bpmpkg,
|
||||
SplitPackageToInstall: splitPkg.Name,
|
||||
})
|
||||
@@ -62,9 +107,24 @@ func InstallPackages(rootDir string, forceInstallationReason InstallationReason,
|
||||
continue
|
||||
}
|
||||
|
||||
if !reinstallPackages && IsPackageInstalled(bpmpkg.PkgInfo.Name, rootDir) && GetPackageInfo(bpmpkg.PkgInfo.Name, rootDir).GetFullVersion() == bpmpkg.PkgInfo.GetFullVersion() {
|
||||
// Check if installation can be ignored
|
||||
if !reinstallPackages && IsPackageInstalled(bpmpkg.PkgInfo.Name, rootDir) {
|
||||
shouldIgnore := true
|
||||
|
||||
// Skip if no update/downgrade is available
|
||||
if GetPackageInfo(bpmpkg.PkgInfo.Name, rootDir).GetFullVersion() != bpmpkg.PkgInfo.GetFullVersion() {
|
||||
shouldIgnore = false
|
||||
}
|
||||
|
||||
// Skip if no new package flags
|
||||
if !maps.Equal(getPackageLocalInfo(bpmpkg.PkgInfo.Name, rootDir).Flags, d.Flags) {
|
||||
shouldIgnore = false
|
||||
}
|
||||
|
||||
if shouldIgnore {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
// Set package installation reason
|
||||
installationReason := forceInstallationReason
|
||||
@@ -86,31 +146,55 @@ func InstallPackages(rootDir string, forceInstallationReason InstallationReason,
|
||||
operation.Actions = append(operation.Actions, &InstallPackageAction{
|
||||
File: pkg,
|
||||
InstallationReason: installationReason,
|
||||
Flags: d.Flags,
|
||||
BpmPackage: bpmpkg,
|
||||
})
|
||||
} else {
|
||||
// Split package name and required version
|
||||
pkgName, _, _ := SplitPkgNameAndVersion(pkg)
|
||||
|
||||
// Check resolved virtual packages
|
||||
if resolvedPkg, ok := resolvedVirtualPackages[pkgName]; ok {
|
||||
pkgName = resolvedPkg
|
||||
if resolvedPkg, ok := resolvedVirtualPackages[d.PkgName]; ok {
|
||||
d.PkgName = resolvedPkg
|
||||
}
|
||||
|
||||
entry := ResolveDatabaseEntry(pkgName, rootDir)
|
||||
entry := ResolveDatabaseEntry(d, rootDir)
|
||||
if entry == nil {
|
||||
pkgsNotFound = append(pkgsNotFound, pkg)
|
||||
unresolvedPackages[pkg] = "could not find in any database"
|
||||
continue
|
||||
}
|
||||
|
||||
if !EvaluateDependency(pkg, entry.Info.Version) {
|
||||
pkgsNotFound = append(pkgsNotFound, pkg)
|
||||
continue
|
||||
pkgInfo := GetPackageInfo(entry.Info.Name, rootDir)
|
||||
|
||||
// Add user defined package flags and resolve entry again if package is already installed
|
||||
if !reinstallPackages && pkgInfo != nil {
|
||||
d.Flags, err = CombineFlags(getPackageLocalInfo(entry.Info.Name, rootDir).Flags, d.Flags)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not combine flags for package (%s): %s", entry.Info.Name, err)
|
||||
}
|
||||
|
||||
if !reinstallPackages && IsPackageInstalled(entry.Info.Name, rootDir) && GetPackageInfo(entry.Info.Name, rootDir).GetFullVersion() == entry.Info.GetFullVersion() {
|
||||
entry = ResolveDatabaseEntry(d, rootDir)
|
||||
if entry == nil {
|
||||
unresolvedPackages[pkg] = "could not find in any database"
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
// Check if installation can be ignored
|
||||
if !reinstallPackages && pkgInfo != nil {
|
||||
shouldIgnore := true
|
||||
|
||||
// Skip if no update/downgrade is available
|
||||
if GetPackageInfo(entry.Info.Name, rootDir).GetFullVersion() != entry.Info.GetFullVersion() {
|
||||
shouldIgnore = false
|
||||
}
|
||||
|
||||
// Skip if no new package flags
|
||||
if !maps.Equal(getPackageLocalInfo(entry.Info.Name, rootDir).Flags, d.Flags) {
|
||||
shouldIgnore = false
|
||||
}
|
||||
|
||||
if shouldIgnore {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
// Set package installation reason
|
||||
installationReason := forceInstallationReason
|
||||
@@ -131,23 +215,24 @@ func InstallPackages(rootDir string, forceInstallationReason InstallationReason,
|
||||
|
||||
operation.Actions = append(operation.Actions, &FetchPackageAction{
|
||||
InstallationReason: installationReason,
|
||||
Flags: d.Flags,
|
||||
DatabaseEntry: entry,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Return error if not all packages are found
|
||||
if len(pkgsNotFound) != 0 {
|
||||
return nil, PackageNotFoundErr{pkgsNotFound}
|
||||
if len(unresolvedPackages) != 0 {
|
||||
return nil, PackageNotResolvedErr{unresolvedPackages}
|
||||
}
|
||||
|
||||
// Resolve dependencies
|
||||
operation.ResolveDependencies(installRuntimeDependencies)
|
||||
if len(operation.UnresolvedDepends) != 0 {
|
||||
if !forceInstallation {
|
||||
return nil, DependencyNotFoundErr{operation.UnresolvedDepends}
|
||||
return nil, PackageNotResolvedErr{operation.UnresolvedDepends}
|
||||
} else if verbose {
|
||||
log.Printf("Warning: %s", DependencyNotFoundErr{operation.UnresolvedDepends})
|
||||
log.Printf("Warning: %s", PackageNotResolvedErr{operation.UnresolvedDepends})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -197,7 +282,7 @@ func InstallPackages(rootDir string, forceInstallationReason InstallationReason,
|
||||
func RemovePackages(rootDir string, force, cleanupDependencies bool, packages ...string) (operation *BPMOperation, err error) {
|
||||
operation = &BPMOperation{
|
||||
Actions: make([]OperationAction, 0),
|
||||
UnresolvedDepends: make([]string, 0),
|
||||
UnresolvedDepends: make(map[string]string),
|
||||
ModifiedFiles: make(map[string]string),
|
||||
RootDir: rootDir,
|
||||
compiledPackages: make(map[string]string),
|
||||
@@ -275,7 +360,7 @@ func RemovePackages(rootDir string, force, cleanupDependencies bool, packages ..
|
||||
func CleanupPackages(cleanupMakeDepends bool, rootDir string) (operation *BPMOperation, err error) {
|
||||
operation = &BPMOperation{
|
||||
Actions: make([]OperationAction, 0),
|
||||
UnresolvedDepends: make([]string, 0),
|
||||
UnresolvedDepends: make(map[string]string),
|
||||
ModifiedFiles: make(map[string]string),
|
||||
RootDir: rootDir,
|
||||
compiledPackages: make(map[string]string),
|
||||
@@ -403,7 +488,7 @@ func UpdatePackages(rootDir string, syncDatabase, allowDowngrades, forceInstalla
|
||||
|
||||
operation = &BPMOperation{
|
||||
Actions: make([]OperationAction, 0),
|
||||
UnresolvedDepends: make([]string, 0),
|
||||
UnresolvedDepends: make(map[string]string),
|
||||
ModifiedFiles: make(map[string]string),
|
||||
RunChecks: runChecks,
|
||||
RootDir: rootDir,
|
||||
@@ -417,16 +502,21 @@ func UpdatePackages(rootDir string, syncDatabase, allowDowngrades, forceInstalla
|
||||
continue
|
||||
}
|
||||
|
||||
// Get installed package built flags
|
||||
flags := getPackageLocalInfo(pkg, rootDir).Flags
|
||||
|
||||
var entry *BPMDatabaseEntry
|
||||
// Check if installed package can be replaced and install that instead
|
||||
if e := FindReplacement(pkg); e != nil {
|
||||
entry = e
|
||||
} else if entry = ResolveDatabaseEntry(pkg, rootDir); entry == nil {
|
||||
} else if entry = ResolveDatabaseEntry(DeconstructedPackageString{PkgName: pkg, Flags: flags}, rootDir); entry == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
installedInfo := GetPackageInfo(pkg, rootDir)
|
||||
if installedInfo == nil {
|
||||
// Remove invalid flags
|
||||
flags = RemoveInvalidFlags(entry.Info, flags)
|
||||
|
||||
if installedInfo := GetPackageInfo(pkg, rootDir); installedInfo == nil {
|
||||
return nil, fmt.Errorf("could not get package info for package (%s)", pkg)
|
||||
} else {
|
||||
comparison := CompareVersions(entry.Info.GetFullVersion(), installedInfo.GetFullVersion())
|
||||
@@ -438,8 +528,11 @@ func UpdatePackages(rootDir string, syncDatabase, allowDowngrades, forceInstalla
|
||||
}
|
||||
}
|
||||
|
||||
bpmpkg := GetPackage(pkg, rootDir)
|
||||
|
||||
operation.Actions = append(operation.Actions, &FetchPackageAction{
|
||||
InstallationReason: GetPackage(pkg, rootDir).LocalInfo.GetInstallationReason(),
|
||||
InstallationReason: bpmpkg.LocalInfo.GetInstallationReason(),
|
||||
Flags: flags,
|
||||
DatabaseEntry: entry,
|
||||
})
|
||||
}
|
||||
@@ -450,9 +543,9 @@ func UpdatePackages(rootDir string, syncDatabase, allowDowngrades, forceInstalla
|
||||
operation.ResolveDependencies(true)
|
||||
if len(operation.UnresolvedDepends) != 0 {
|
||||
if !forceInstallation {
|
||||
return nil, DependencyNotFoundErr{operation.UnresolvedDepends}
|
||||
return nil, PackageNotResolvedErr{operation.UnresolvedDepends}
|
||||
} else if verbose {
|
||||
log.Printf("Warning: %s", DependencyNotFoundErr{operation.UnresolvedDepends})
|
||||
log.Printf("Warning: %s", PackageNotResolvedErr{operation.UnresolvedDepends})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+61
-32
@@ -4,6 +4,7 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"log"
|
||||
"maps"
|
||||
"os"
|
||||
"path"
|
||||
"slices"
|
||||
@@ -13,7 +14,7 @@ import (
|
||||
|
||||
type BPMOperation struct {
|
||||
Actions []OperationAction
|
||||
UnresolvedDepends []string
|
||||
UnresolvedDepends map[string]string
|
||||
ModifiedFiles map[string]string
|
||||
CompilationJobs int
|
||||
RunChecks bool
|
||||
@@ -91,26 +92,29 @@ func (operation *BPMOperation) ResolveDependencies(installRuntimeDepends bool) {
|
||||
newActions := make([]OperationAction, 0)
|
||||
for _, value := range operation.Actions {
|
||||
var pkgInfo *PackageInfo
|
||||
var flags map[string]string
|
||||
if value.GetActionType() == "install" {
|
||||
action := value.(*InstallPackageAction)
|
||||
pkgInfo = action.BpmPackage.PkgInfo
|
||||
flags = action.Flags
|
||||
} else if value.GetActionType() == "fetch" {
|
||||
action := value.(*FetchPackageAction)
|
||||
pkgInfo = action.DatabaseEntry.Info
|
||||
flags = action.Flags
|
||||
} else {
|
||||
continue
|
||||
}
|
||||
|
||||
resolved, unresolved := ResolveDependencies(pkgInfo, resolvedVirtualPackages, installRuntimeDepends, operation.RootDir)
|
||||
resolved, unresolved := ResolveDependencies(pkgInfo, flags, resolvedVirtualPackages, installRuntimeDepends, operation.RootDir)
|
||||
|
||||
// Append unresolved dependencies
|
||||
operation.UnresolvedDepends = append(operation.UnresolvedDepends, unresolved...)
|
||||
operation.UnresolvedDepends = removeDuplicates(operation.UnresolvedDepends)
|
||||
// Copy unresolved dependencies
|
||||
maps.Copy(operation.UnresolvedDepends, unresolved)
|
||||
|
||||
for _, resolvedPkg := range resolved {
|
||||
if ActionSliceIndex(newActions, resolvedPkg.DatabaseEntry.Info.Name) == -1 { // Dependency not in actions slice
|
||||
var action OperationAction = &FetchPackageAction{
|
||||
InstallationReason: resolvedPkg.InstallationReason,
|
||||
Flags: resolvedPkg.Flags,
|
||||
DatabaseEntry: resolvedPkg.DatabaseEntry,
|
||||
}
|
||||
newActions = append(newActions, action)
|
||||
@@ -192,15 +196,18 @@ func (operation *BPMOperation) Cleanup(cleanupMakeDepends bool) error {
|
||||
|
||||
// Loop through all dependencies
|
||||
for _, depend := range depends {
|
||||
// Remove required version
|
||||
depend, _, _ = SplitPkgNameAndVersion(depend)
|
||||
// Deconstruct package string
|
||||
d, err := DeconstructPackageString(depend)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not deconstruct package string: %s", err)
|
||||
}
|
||||
|
||||
// Resolve dependency
|
||||
var dependPkgInfo *PackageInfo
|
||||
if providers := GetVirtualPackageInfo(depend, operation.RootDir); len(providers) > 0 {
|
||||
if providers := GetVirtualPackageInfo(d.PkgName, operation.RootDir); len(providers) > 0 {
|
||||
dependPkgInfo = providers[0]
|
||||
} else {
|
||||
dependPkgInfo = GetPackageInfo(depend, operation.RootDir)
|
||||
dependPkgInfo = GetPackageInfo(d.PkgName, operation.RootDir)
|
||||
}
|
||||
if dependPkgInfo == nil {
|
||||
continue
|
||||
@@ -225,7 +232,7 @@ func (operation *BPMOperation) Cleanup(cleanupMakeDepends bool) error {
|
||||
if !slices.Contains(visited, pkg) {
|
||||
bpmpkg := GetPackage(pkg, operation.RootDir)
|
||||
if bpmpkg == nil {
|
||||
return errors.New("Error: could not find installed package (" + pkg + ")")
|
||||
return fmt.Errorf("could not find installed package (%s)", pkg)
|
||||
}
|
||||
operation.Actions = append(operation.Actions, &RemovePackageAction{BpmPackage: bpmpkg})
|
||||
}
|
||||
@@ -358,15 +365,30 @@ func (operation *BPMOperation) ShowOperationSummary() {
|
||||
|
||||
for _, value := range operation.Actions {
|
||||
var pkgInfo *PackageInfo
|
||||
var flagsStr string
|
||||
var installationReason = InstallationReasonUnknown
|
||||
if value.GetActionType() == "install" {
|
||||
installationReason = value.(*InstallPackageAction).InstallationReason
|
||||
pkgInfo = value.(*InstallPackageAction).BpmPackage.PkgInfo
|
||||
if len(value.(*InstallPackageAction).Flags) > 0 {
|
||||
flagsSlice := make([]string, 0)
|
||||
for flag, value := range value.(*InstallPackageAction).Flags {
|
||||
flagsSlice = append(flagsSlice, flag+"="+value)
|
||||
}
|
||||
flagsStr = "[" + strings.Join(flagsSlice, ",") + "]"
|
||||
}
|
||||
if value.(*InstallPackageAction).SplitPackageToInstall != "" {
|
||||
pkgInfo = pkgInfo.GetSplitPackageInfo(value.(*InstallPackageAction).SplitPackageToInstall)
|
||||
}
|
||||
} else if value.GetActionType() == "fetch" {
|
||||
installationReason = value.(*FetchPackageAction).InstallationReason
|
||||
if len(value.(*FetchPackageAction).Flags) > 0 {
|
||||
flagsSlice := make([]string, 0)
|
||||
for flag, value := range value.(*FetchPackageAction).Flags {
|
||||
flagsSlice = append(flagsSlice, flag+"="+value)
|
||||
}
|
||||
flagsStr = "[" + strings.Join(flagsSlice, ",") + "]"
|
||||
}
|
||||
pkgInfo = value.(*FetchPackageAction).DatabaseEntry.Info
|
||||
} else {
|
||||
pkgInfo = value.(*RemovePackageAction).BpmPackage.PkgInfo
|
||||
@@ -388,15 +410,15 @@ func (operation *BPMOperation) ShowOperationSummary() {
|
||||
|
||||
installedInfo := GetPackageInfo(pkgInfo.Name, operation.RootDir)
|
||||
if installedInfo == nil {
|
||||
fmt.Fprintf(writer, "%s\t%s\t%s\t%s\t%t\n", pkgInfo.Name, pkgInfo.GetFullVersion(), "Install", installationReasonStr, pkgInfo.Type == "source")
|
||||
fmt.Fprintf(writer, "%s\t%s\t%s\t%s\t%t\n", pkgInfo.Name+flagsStr, pkgInfo.GetFullVersion(), "Install", installationReasonStr, pkgInfo.Type == "source")
|
||||
} else {
|
||||
comparison := CompareVersions(pkgInfo.GetFullVersion(), installedInfo.GetFullVersion())
|
||||
if comparison < 0 {
|
||||
fmt.Fprintf(writer, "%s\t%s -> %s\t%s\t%s\t%t\n", pkgInfo.Name, installedInfo.GetFullVersion(), pkgInfo.GetFullVersion(), "Downgrade", installationReasonStr, pkgInfo.Type == "source")
|
||||
fmt.Fprintf(writer, "%s\t%s -> %s\t%s\t%s\t%t\n", pkgInfo.Name+flagsStr, installedInfo.GetFullVersion(), pkgInfo.GetFullVersion(), "Downgrade", installationReasonStr, pkgInfo.Type == "source")
|
||||
} else if comparison > 0 {
|
||||
fmt.Fprintf(writer, "%s\t%s -> %s\t%s\t%s\t%t\n", pkgInfo.Name, installedInfo.GetFullVersion(), pkgInfo.GetFullVersion(), "Upgrade", installationReasonStr, pkgInfo.Type == "source")
|
||||
fmt.Fprintf(writer, "%s\t%s -> %s\t%s\t%s\t%t\n", pkgInfo.Name+flagsStr, installedInfo.GetFullVersion(), pkgInfo.GetFullVersion(), "Upgrade", installationReasonStr, pkgInfo.Type == "source")
|
||||
} else {
|
||||
fmt.Fprintf(writer, "%s\t%s\t%s\t%s\t%t\n", pkgInfo.Name, pkgInfo.GetFullVersion(), "Reinstall", installationReasonStr, pkgInfo.Type == "source")
|
||||
fmt.Fprintf(writer, "%s\t%s\t%s\t%s\t%t\n", pkgInfo.Name+flagsStr, pkgInfo.GetFullVersion(), "Reinstall", installationReasonStr, pkgInfo.Type == "source")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -462,12 +484,14 @@ func (operation *BPMOperation) GetOptionalDependencies() (optionalDepends map[st
|
||||
}
|
||||
|
||||
for _, depend := range pkgInfo.OptionalDepends {
|
||||
// Get optional dependency name
|
||||
dependSplit := strings.SplitN(depend, ":", 2)
|
||||
dependName, _, _ := SplitPkgNameAndVersion(dependSplit[0])
|
||||
// Deconstruct package string
|
||||
d, err := DeconstructPackageString(depend)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
// Skip if dependency is already installed
|
||||
if IsPackageInstalled(dependName, operation.RootDir) || len(GetVirtualPackageInfo(dependName, operation.RootDir)) > 0 {
|
||||
if IsPackageInstalled(d.PkgName, operation.RootDir) || len(GetVirtualPackageInfo(d.PkgName, operation.RootDir)) > 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -484,9 +508,9 @@ func (operation *BPMOperation) GetOptionalDependencies() (optionalDepends map[st
|
||||
return false
|
||||
}
|
||||
|
||||
if pkgInfo.Name == dependName {
|
||||
if pkgInfo.Name == d.PkgName {
|
||||
return true
|
||||
} else if slices.Contains(pkgInfo.Provides, dependName) {
|
||||
} else if slices.Contains(pkgInfo.Provides, d.PkgName) {
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -497,21 +521,21 @@ func (operation *BPMOperation) GetOptionalDependencies() (optionalDepends map[st
|
||||
|
||||
// Skip if not a new dependency of the package
|
||||
if installedPkg := GetPackage(pkgInfo.Name, operation.RootDir); installedPkg != nil && slices.ContainsFunc(installedPkg.PkgInfo.OptionalDepends, func(n string) bool {
|
||||
// Remove optional dependency comment
|
||||
n = strings.SplitN(n, ":", 2)[0]
|
||||
// Deconstruct package string
|
||||
d2, err := DeconstructPackageString(depend)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
// Remove required version
|
||||
n, _, _ = SplitPkgNameAndVersion(n)
|
||||
|
||||
return n == dependName
|
||||
return d2.PkgName == d.PkgName
|
||||
}) {
|
||||
continue
|
||||
}
|
||||
|
||||
if len(dependSplit) == 2 {
|
||||
optionalDepends[pkgInfo.Name] = append(optionalDepends[pkgInfo.Name], fmt.Sprintf("%s (%s)", dependSplit[0], dependSplit[1]))
|
||||
if d.Description != "" {
|
||||
optionalDepends[pkgInfo.Name] = append(optionalDepends[pkgInfo.Name], fmt.Sprintf("%s (%s)", d.PkgName, d.Description))
|
||||
} else {
|
||||
optionalDepends[pkgInfo.Name] = append(optionalDepends[pkgInfo.Name], dependName)
|
||||
optionalDepends[pkgInfo.Name] = append(optionalDepends[pkgInfo.Name], d.PkgName)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -648,6 +672,7 @@ func (operation *BPMOperation) FetchPackages() (err error) {
|
||||
operation.Actions[i] = &InstallPackageAction{
|
||||
File: fetchedPackages[entry.Filepath],
|
||||
InstallationReason: action.(*FetchPackageAction).InstallationReason,
|
||||
Flags: action.(*FetchPackageAction).Flags,
|
||||
BpmPackage: bpmpkg,
|
||||
SplitPackageToInstall: entry.Info.Name,
|
||||
}
|
||||
@@ -655,6 +680,7 @@ func (operation *BPMOperation) FetchPackages() (err error) {
|
||||
operation.Actions[i] = &InstallPackageAction{
|
||||
File: fetchedPackages[entry.Filepath],
|
||||
InstallationReason: action.(*FetchPackageAction).InstallationReason,
|
||||
Flags: action.(*FetchPackageAction).Flags,
|
||||
BpmPackage: bpmpkg,
|
||||
}
|
||||
}
|
||||
@@ -735,6 +761,7 @@ func (operation *BPMOperation) Execute(verbose, force bool) (err error) {
|
||||
} else if action.GetActionType() == "install" {
|
||||
value := action.(*InstallPackageAction)
|
||||
fileToInstall := value.File
|
||||
compilationFlags := value.Flags
|
||||
bpmpkg := value.BpmPackage
|
||||
var err error
|
||||
|
||||
@@ -759,7 +786,7 @@ func (operation *BPMOperation) Execute(verbose, force bool) (err error) {
|
||||
|
||||
// Compile source package if not compiled already
|
||||
if _, ok := operation.compiledPackages[pkgNameToInstall]; !ok {
|
||||
outputBpmPackages, err := CompileSourcePackage(value.File, compiledDir, operation.CompilationJobs, !operation.RunChecks, false, verbose)
|
||||
outputBpmPackages, err := CompileSourcePackage(value.File, compiledDir, compilationFlags, operation.CompilationJobs, !operation.RunChecks, false, verbose)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not compile source package (%s): %s\n", value.File, err)
|
||||
}
|
||||
@@ -779,9 +806,9 @@ func (operation *BPMOperation) Execute(verbose, force bool) (err error) {
|
||||
}
|
||||
|
||||
if value.InstallationReason != InstallationReasonManual {
|
||||
err = installPackage(fileToInstall, value.InstallationReason, operation.RootDir, verbose, true)
|
||||
err = installPackage(fileToInstall, value.InstallationReason, value.Flags, operation.RootDir, verbose, true)
|
||||
} else {
|
||||
err = installPackage(fileToInstall, value.InstallationReason, operation.RootDir, verbose, force)
|
||||
err = installPackage(fileToInstall, value.InstallationReason, value.Flags, operation.RootDir, verbose, force)
|
||||
}
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not install package (%s): %s\n", bpmpkg.PkgInfo.Name, err)
|
||||
@@ -799,6 +826,7 @@ type OperationAction interface {
|
||||
type InstallPackageAction struct {
|
||||
File string
|
||||
InstallationReason InstallationReason
|
||||
Flags map[string]string
|
||||
SplitPackageToInstall string
|
||||
BpmPackage *BPMPackage
|
||||
}
|
||||
@@ -809,6 +837,7 @@ func (action *InstallPackageAction) GetActionType() string {
|
||||
|
||||
type FetchPackageAction struct {
|
||||
InstallationReason InstallationReason
|
||||
Flags map[string]string
|
||||
DatabaseEntry *BPMDatabaseEntry
|
||||
}
|
||||
|
||||
|
||||
+84
-1
@@ -49,10 +49,27 @@ type PackageInfo struct {
|
||||
Replaces []string `yaml:"replaces,omitempty"`
|
||||
Provides []string `yaml:"provides,omitempty"`
|
||||
Options []string `yaml:"options,omitempty"`
|
||||
Flags []PackageFlag `yaml:"flags,omitempty"`
|
||||
Downloads []PackageDownload `yaml:"downloads,omitempty"`
|
||||
SplitPackages []*PackageInfo `yaml:"split_packages,omitempty"`
|
||||
}
|
||||
|
||||
type PackageFlag struct {
|
||||
Name string `yaml:"name"`
|
||||
DefaultValue string `yaml:"default_value"`
|
||||
BuiltValue string `yaml:"built_value"`
|
||||
AcceptedValues []PackageAcceptedValue `yaml:"accepted_values,omitempty"`
|
||||
}
|
||||
|
||||
type PackageAcceptedValue struct {
|
||||
Value string `yaml:"value"`
|
||||
Depends []string `yaml:"depends,omitempty"`
|
||||
RuntimeDepends []string `yaml:"runtime_depends,omitempty"`
|
||||
OptionalDepends []string `yaml:"optional_depends,omitempty"`
|
||||
MakeDepends []string `yaml:"make_depends,omitempty"`
|
||||
CheckDepends []string `yaml:"check_depends,omitempty"`
|
||||
}
|
||||
|
||||
type PackageDownload struct {
|
||||
Url string `yaml:"url"`
|
||||
Type string `yaml:"type,omitempty"`
|
||||
@@ -80,6 +97,7 @@ type PackageFileEntry struct {
|
||||
|
||||
type PackageLocalInfo struct {
|
||||
InstallationReason string `yaml:"installation_reason"`
|
||||
Flags map[string]string `yaml:"flags"`
|
||||
InstalledOn int64 `yaml:"installed_on"`
|
||||
LastUpdatedOn int64 `yaml:"last_updated_on"`
|
||||
}
|
||||
@@ -595,6 +613,70 @@ func (pkgInfo *PackageInfo) CreateReadableInfo(rootDir string) string {
|
||||
}
|
||||
builder.WriteString("Type: " + pkgInfo.Type + "\n")
|
||||
|
||||
// Flags
|
||||
if pkgInfo.Type == "binary" {
|
||||
var flags []string
|
||||
for _, flag := range pkgInfo.Flags {
|
||||
if pkgInfo != GetPackageInfo(pkgInfo.Name, rootDir) {
|
||||
flags = append(flags, fmt.Sprintf("%s=%s", flag.Name, flag.BuiltValue))
|
||||
} else if _, ok := getPackageLocalInfo(pkgInfo.Name, rootDir).Flags[flag.Name]; ok {
|
||||
flags = append(flags, fmt.Sprintf("%s=%s (User defined)", flag.Name, flag.BuiltValue))
|
||||
} else {
|
||||
flags = append(flags, fmt.Sprintf("%s=%s (Default value)", flag.Name, flag.BuiltValue))
|
||||
}
|
||||
}
|
||||
builderWriteArray("Built with flags:", flags, false)
|
||||
} else {
|
||||
if len(pkgInfo.Flags) > 0 {
|
||||
builder.WriteString("Available flags (")
|
||||
builder.WriteString(strconv.Itoa(len(pkgInfo.Flags)))
|
||||
builder.WriteString("):\n")
|
||||
for _, flag := range pkgInfo.Flags {
|
||||
builder.WriteString(" - Flag: ")
|
||||
builder.WriteString(flag.Name)
|
||||
builder.WriteRune('\n')
|
||||
if flag.DefaultValue != "" {
|
||||
builder.WriteString(" Default value: ")
|
||||
builder.WriteString(flag.DefaultValue)
|
||||
builder.WriteRune('\n')
|
||||
}
|
||||
if len(flag.AcceptedValues) > 0 {
|
||||
builder.WriteString(" Accepted values (")
|
||||
builder.WriteString(strconv.Itoa(len(flag.AcceptedValues)))
|
||||
builder.WriteString("):\n")
|
||||
|
||||
for i, acceptedValue := range flag.AcceptedValues {
|
||||
writeValueDepends := func(text string, depends []string) {
|
||||
if len(depends) > 0 {
|
||||
builder.WriteString(" ")
|
||||
builder.WriteString(text)
|
||||
builder.WriteString(" (")
|
||||
builder.WriteString(strconv.Itoa(len(depends)))
|
||||
builder.WriteString("): ")
|
||||
for _, depend := range depends {
|
||||
if i != 0 {
|
||||
builder.WriteString(", ")
|
||||
}
|
||||
builder.WriteString(depend)
|
||||
}
|
||||
builder.WriteRune('\n')
|
||||
}
|
||||
}
|
||||
|
||||
builder.WriteString(" - Value: ")
|
||||
builder.WriteString(acceptedValue.Value)
|
||||
builder.WriteRune('\n')
|
||||
writeValueDepends("Dependencies", acceptedValue.Depends)
|
||||
writeValueDepends("Make Dependencies", acceptedValue.MakeDepends)
|
||||
writeValueDepends("Check Dependencies", acceptedValue.CheckDepends)
|
||||
writeValueDepends("Runtime Dependencies", acceptedValue.RuntimeDepends)
|
||||
writeValueDepends("Optional Dependencies", acceptedValue.OptionalDepends)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Dependencies
|
||||
builderWriteDependencyArray("Dependencies", pkgInfo.Depends)
|
||||
if pkgInfo.Type == "source" {
|
||||
@@ -870,7 +952,7 @@ func extractPackage(bpmpkg *BPMPackage, verbose bool, filename, rootDir string)
|
||||
return nil
|
||||
}
|
||||
|
||||
func installPackage(filename string, installationReason InstallationReason, rootDir string, verbose, force bool) error {
|
||||
func installPackage(filename string, installationReason InstallationReason, flags map[string]string, rootDir string, verbose, force bool) error {
|
||||
if _, err := os.Stat(filename); os.IsNotExist(err) {
|
||||
return err
|
||||
}
|
||||
@@ -1074,6 +1156,7 @@ func installPackage(filename string, installationReason InstallationReason, root
|
||||
}
|
||||
localInfo.LastUpdatedOn = time.Now().Unix()
|
||||
localInfo.InstallationReason = string(installationReason)
|
||||
localInfo.Flags = flags
|
||||
|
||||
SetPackageLocalInfo(bpmpkg.PkgInfo.Name, localInfo, rootDir)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user