mirror of
https://github.com/EnumeratedDev/bpm.git
synced 2026-09-21 21:16:12 +00:00
Compare commits
20
Commits
248359c02f
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
80382c849b
|
||
|
|
6f524ab6fa
|
||
|
|
cb01c96ad6
|
||
|
|
e6456105e1
|
||
|
|
a496777b9e
|
||
|
|
cb191dc16a
|
||
|
|
140cd3c64b
|
||
|
|
677da23c9d
|
||
|
|
7f279ef8e9
|
||
|
|
3950c5f0d6
|
||
|
|
f3c2b9f0f6
|
||
|
|
dc8959c2f8
|
||
|
|
9122ffb9ca
|
||
|
|
a4e20b7d88
|
||
|
|
a03c9ad9ce
|
||
|
|
3f205ec412
|
||
|
|
2f9487affe
|
||
|
|
596d8753a7
|
||
|
|
2de4eea7a4
|
||
|
|
5d0312856d
|
+134
-39
@@ -92,7 +92,7 @@ func main() {
|
|||||||
currentFlagSet.String("installation-reason", "", "Specify the installation reason to use for the specified packages")
|
currentFlagSet.String("installation-reason", "", "Specify the installation reason to use for the specified packages")
|
||||||
currentFlagSet.BoolP("reinstall", "r", false, "Reinstall the specified packages")
|
currentFlagSet.BoolP("reinstall", "r", false, "Reinstall the specified packages")
|
||||||
currentFlagSet.IntP("jobs", "j", bpmlib.CompilationBPMConfig.CompilationJobs, "Set the amount of concurrent processes to use for source package compilation")
|
currentFlagSet.IntP("jobs", "j", bpmlib.CompilationBPMConfig.CompilationJobs, "Set the amount of concurrent processes to use for source package compilation")
|
||||||
currentFlagSet.BoolP("skip-checks", "s", false, "Skip the check function in source.sh scripts")
|
currentFlagSet.Bool("skip-checks", false, "Skip the check function in recipe.sh scripts")
|
||||||
setupFlagsAndHelp(currentFlagSet, fmt.Sprintf("bpm %s <options>", subcommand), "Install the specified packages", os.Args[2:])
|
setupFlagsAndHelp(currentFlagSet, fmt.Sprintf("bpm %s <options>", subcommand), "Install the specified packages", os.Args[2:])
|
||||||
|
|
||||||
installPackages()
|
installPackages()
|
||||||
@@ -141,7 +141,7 @@ func main() {
|
|||||||
currentFlagSet.BoolP("yes", "y", false, "Enter 'yes' in all prompts")
|
currentFlagSet.BoolP("yes", "y", false, "Enter 'yes' in all prompts")
|
||||||
currentFlagSet.BoolP("no-sync", "n", false, "Do not sync databases")
|
currentFlagSet.BoolP("no-sync", "n", false, "Do not sync databases")
|
||||||
currentFlagSet.Bool("allow-downgrades", false, "Allow package downgrades")
|
currentFlagSet.Bool("allow-downgrades", false, "Allow package downgrades")
|
||||||
currentFlagSet.BoolP("skip-checks", "s", false, "Skip the check function in source.sh scripts")
|
currentFlagSet.Bool("skip-checks", false, "Skip the check function in recipe.sh scripts")
|
||||||
currentFlagSet.IntP("jobs", "j", bpmlib.CompilationBPMConfig.CompilationJobs, "Set the amount of concurrent processes to use for source package compilation")
|
currentFlagSet.IntP("jobs", "j", bpmlib.CompilationBPMConfig.CompilationJobs, "Set the amount of concurrent processes to use for source package compilation")
|
||||||
setupFlagsAndHelp(currentFlagSet, fmt.Sprintf("bpm %s <options>", subcommand), "Update installed packages", os.Args[2:])
|
setupFlagsAndHelp(currentFlagSet, fmt.Sprintf("bpm %s <options>", subcommand), "Update installed packages", os.Args[2:])
|
||||||
|
|
||||||
@@ -161,7 +161,7 @@ func main() {
|
|||||||
currentFlagSet.BoolP("force", "f", false, "Bypass warnings during package compilation")
|
currentFlagSet.BoolP("force", "f", false, "Bypass warnings during package compilation")
|
||||||
currentFlagSet.BoolP("yes", "y", false, "Enter 'yes' in all prompts")
|
currentFlagSet.BoolP("yes", "y", false, "Enter 'yes' in all prompts")
|
||||||
currentFlagSet.BoolP("depends", "d", false, "Install required dependencies for package compilation")
|
currentFlagSet.BoolP("depends", "d", false, "Install required dependencies for package compilation")
|
||||||
currentFlagSet.BoolP("skip-checks", "s", false, "Skip the check function in source.sh scripts")
|
currentFlagSet.Bool("skip-checks", false, "Skip the check function in recipe.sh scripts")
|
||||||
currentFlagSet.BoolP("keep", "k", false, "Keep compilation files after successful package compilation")
|
currentFlagSet.BoolP("keep", "k", false, "Keep compilation files after successful package compilation")
|
||||||
currentFlagSet.BoolP("output-directory", "o", false, "Set the output directory for the binary packages")
|
currentFlagSet.BoolP("output-directory", "o", false, "Set the output directory for the binary packages")
|
||||||
currentFlagSet.Int("output-fd", -1, "Set the file descriptor output package names will be written to")
|
currentFlagSet.Int("output-fd", -1, "Set the file descriptor output package names will be written to")
|
||||||
@@ -239,18 +239,20 @@ func showPackageInfo() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for n, pkg := range packages {
|
for n, pkg := range packages {
|
||||||
if showDatabaseInfo {
|
// Deconstruct package string
|
||||||
var err error
|
d, err := bpmlib.DeconstructPackageString(pkg)
|
||||||
var entry *bpmlib.BPMDatabaseEntry
|
|
||||||
entry, _, err = bpmlib.GetDatabaseEntry(pkg)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if providers := bpmlib.GetDatabaseVirtualPackageEntry(pkg); len(providers) > 0 {
|
log.Printf("Error: could not deconstruct package string: %s\n", err)
|
||||||
entry = providers[0]
|
|
||||||
} else {
|
|
||||||
log.Printf("Error: could not find package (%s) in any database\n", pkg)
|
|
||||||
exitCode = 1
|
exitCode = 1
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if n != 0 {
|
if n != 0 {
|
||||||
@@ -263,8 +265,8 @@ func showPackageInfo() {
|
|||||||
|
|
||||||
var bpmpkg *bpmlib.BPMPackage
|
var bpmpkg *bpmlib.BPMPackage
|
||||||
isFile := false
|
isFile := false
|
||||||
if stat, err := os.Stat(pkg); err == nil && !stat.IsDir() {
|
if stat, err := os.Stat(d.PkgName); err == nil && !stat.IsDir() {
|
||||||
bpmpkg, err = bpmlib.ReadPackage(pkg)
|
bpmpkg, err = bpmlib.ReadPackage(d.PkgName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Error: could not read package: %s\n", err)
|
log.Printf("Error: could not read package: %s\n", err)
|
||||||
exitCode = 1
|
exitCode = 1
|
||||||
@@ -272,22 +274,30 @@ func showPackageInfo() {
|
|||||||
}
|
}
|
||||||
isFile = true
|
isFile = true
|
||||||
} else {
|
} else {
|
||||||
if providers := bpmlib.GetVirtualPackageInfo(pkg, rootDir); len(providers) > 0 {
|
if providers := bpmlib.GetVirtualPackageInfo(d.PkgName, rootDir); len(providers) > 0 {
|
||||||
bpmpkg = bpmlib.GetPackage(providers[0].Name, rootDir)
|
bpmpkg = bpmlib.GetPackage(providers[0].Name, rootDir)
|
||||||
} else {
|
} else {
|
||||||
bpmpkg = bpmlib.GetPackage(pkg, rootDir)
|
bpmpkg = bpmlib.GetPackage(d.PkgName, rootDir)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if bpmpkg == nil {
|
if bpmpkg == nil {
|
||||||
log.Printf("Error: package (%s) is not installed\n", pkg)
|
log.Printf("Error: package (%s) is not installed\n", pkg)
|
||||||
exitCode = 1
|
exitCode = 1
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !bpmlib.EvaluatePackageString(bpmpkg.PkgInfo, d) {
|
||||||
|
log.Printf("Error: package (%s) is not installed\n", pkg)
|
||||||
|
exitCode = 1
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if n != 0 {
|
if n != 0 {
|
||||||
fmt.Println()
|
fmt.Println()
|
||||||
}
|
}
|
||||||
if isFile {
|
if isFile {
|
||||||
abs, err := filepath.Abs(pkg)
|
abs, err := filepath.Abs(d.PkgName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Error: could not get absolute path of file (%s)\n", abs)
|
log.Printf("Error: could not get absolute path of file (%s)\n", abs)
|
||||||
exitCode = 1
|
exitCode = 1
|
||||||
@@ -618,7 +628,7 @@ func installPackages() {
|
|||||||
|
|
||||||
// Create installation operation
|
// Create installation operation
|
||||||
operation, err := bpmlib.InstallPackages(rootDir, ir, reinstallPackages, installRuntime, force, !skipChecks, verbose, packages...)
|
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)
|
log.Printf("Error: %s", err)
|
||||||
exitCode = 1
|
exitCode = 1
|
||||||
return
|
return
|
||||||
@@ -662,6 +672,9 @@ func installPackages() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get files that will be modifie during this operation
|
||||||
|
operation.GetModifiedFiles()
|
||||||
|
|
||||||
if bpmlib.MainBPMConfig.ShowSourcePackageContents == "always" || bpmlib.MainBPMConfig.ShowSourcePackageContents == "install-only" {
|
if bpmlib.MainBPMConfig.ShowSourcePackageContents == "always" || bpmlib.MainBPMConfig.ShowSourcePackageContents == "install-only" {
|
||||||
// Show source package contents
|
// Show source package contents
|
||||||
sourcePackagesShown, err := operation.ShowSourcePackageContent()
|
sourcePackagesShown, err := operation.ShowSourcePackageContent()
|
||||||
@@ -684,6 +697,15 @@ func installPackages() {
|
|||||||
// Get optional dependencies
|
// Get optional dependencies
|
||||||
optionalDepends := operation.GetOptionalDependencies()
|
optionalDepends := operation.GetOptionalDependencies()
|
||||||
|
|
||||||
|
// Executing pre-operation hooks
|
||||||
|
fmt.Println("Running pre-operation hooks...")
|
||||||
|
err = operation.RunPreHooks(verbose)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Error: could not run pre-operation hooks: %s\n", err)
|
||||||
|
exitCode = 1
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// Execute operation
|
// Execute operation
|
||||||
err = operation.Execute(verbose, force)
|
err = operation.Execute(verbose, force)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -692,15 +714,17 @@ func installPackages() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Executing hooks
|
// Executing post-operation hooks
|
||||||
fmt.Println("Running hooks...")
|
fmt.Println("Running post-operation hooks...")
|
||||||
err = operation.RunHooks(verbose)
|
err = operation.RunPostHooks(verbose)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Error: could not run hooks: %s\n", err)
|
log.Printf("Error: could not run post-operation hooks: %s\n", err)
|
||||||
exitCode = 1
|
exitCode = 1
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fmt.Println("Operation complete!")
|
||||||
|
|
||||||
// Show optional dependencies
|
// Show optional dependencies
|
||||||
if len(optionalDepends) != 0 {
|
if len(optionalDepends) != 0 {
|
||||||
// List optional dependencies
|
// List optional dependencies
|
||||||
@@ -759,12 +783,13 @@ func removePackages() {
|
|||||||
|
|
||||||
// Create remove operation
|
// Create remove operation
|
||||||
operation, err := bpmlib.RemovePackages(rootDir, force, cleanupPackages, packages...)
|
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)
|
log.Printf("Error: %s", err)
|
||||||
exitCode = 1
|
exitCode = 1
|
||||||
return
|
return
|
||||||
} else if errors.As(err, &bpmlib.PackageRemovalDependencyErr{}) {
|
} else if errors.As(err, &bpmlib.PackageRemovalDependencyErr{}) {
|
||||||
for pkg, dependants := range err.(bpmlib.PackageRemovalDependencyErr).RequiredPackages {
|
for pkg, dependants := range err.(bpmlib.PackageRemovalDependencyErr).RequiredPackages {
|
||||||
|
slices.Sort(dependants)
|
||||||
fmt.Printf("The following packages depend on package (%s): %s\n", pkg, strings.Join(dependants, ", "))
|
fmt.Printf("The following packages depend on package (%s): %s\n", pkg, strings.Join(dependants, ", "))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -800,6 +825,18 @@ func removePackages() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get files that will be modifie during this operation
|
||||||
|
operation.GetModifiedFiles()
|
||||||
|
|
||||||
|
// Executing pre-operation hooks
|
||||||
|
fmt.Println("Running pre-operation hooks...")
|
||||||
|
err = operation.RunPreHooks(verbose)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Error: could not run pre-operation hooks: %s\n", err)
|
||||||
|
exitCode = 1
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// Execute operation
|
// Execute operation
|
||||||
err = operation.Execute(verbose, force)
|
err = operation.Execute(verbose, force)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -808,14 +845,16 @@ func removePackages() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Executing hooks
|
// Executing post-operation hooks
|
||||||
fmt.Println("Running hooks...")
|
fmt.Println("Running post-operation hooks...")
|
||||||
err = operation.RunHooks(verbose)
|
err = operation.RunPostHooks(verbose)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Error: could not run hooks: %s\n", err)
|
log.Printf("Error: could not run post-operation hooks: %s\n", err)
|
||||||
exitCode = 1
|
exitCode = 1
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fmt.Println("Operation complete!")
|
||||||
}
|
}
|
||||||
|
|
||||||
func doCleanup() {
|
func doCleanup() {
|
||||||
@@ -888,7 +927,7 @@ func doCleanup() {
|
|||||||
|
|
||||||
// Create cleanup operation
|
// Create cleanup operation
|
||||||
operation, err := bpmlib.CleanupPackages(cleanupMakeDepends, rootDir)
|
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)
|
log.Printf("Error: %s", err)
|
||||||
exitCode = 1
|
exitCode = 1
|
||||||
return
|
return
|
||||||
@@ -921,6 +960,18 @@ func doCleanup() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get files that will be modifie during this operation
|
||||||
|
operation.GetModifiedFiles()
|
||||||
|
|
||||||
|
// Executing pre-operation hooks
|
||||||
|
fmt.Println("Running pre-operation hooks...")
|
||||||
|
err = operation.RunPreHooks(verbose)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Error: could not run pre-operation hooks: %s\n", err)
|
||||||
|
exitCode = 1
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// Execute operation
|
// Execute operation
|
||||||
err = operation.Execute(verbose, force)
|
err = operation.Execute(verbose, force)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -929,14 +980,16 @@ func doCleanup() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Executing hooks
|
// Executing post-operation hooks
|
||||||
fmt.Println("Running hooks...")
|
fmt.Println("Running post-operation hooks...")
|
||||||
err = operation.RunHooks(verbose)
|
err = operation.RunPostHooks(verbose)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Error: could not run hooks: %s\n", err)
|
log.Printf("Error: could not run post-operation hooks: %s\n", err)
|
||||||
exitCode = 1
|
exitCode = 1
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fmt.Println("Operation complete!")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1038,7 +1091,7 @@ func updatePackages() {
|
|||||||
|
|
||||||
// Create update operation
|
// Create update operation
|
||||||
operation, err := bpmlib.UpdatePackages(rootDir, !noSync, allowDowngrades, force, !skipChecks, verbose)
|
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)
|
log.Printf("Error: %s", err)
|
||||||
exitCode = 1
|
exitCode = 1
|
||||||
return
|
return
|
||||||
@@ -1082,6 +1135,9 @@ func updatePackages() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get files that will be modifie during this operation
|
||||||
|
operation.GetModifiedFiles()
|
||||||
|
|
||||||
if bpmlib.MainBPMConfig.ShowSourcePackageContents == "always" {
|
if bpmlib.MainBPMConfig.ShowSourcePackageContents == "always" {
|
||||||
// Show source package contents
|
// Show source package contents
|
||||||
sourcePackagesShown, err := operation.ShowSourcePackageContent()
|
sourcePackagesShown, err := operation.ShowSourcePackageContent()
|
||||||
@@ -1104,6 +1160,15 @@ func updatePackages() {
|
|||||||
// Get optional dependencies
|
// Get optional dependencies
|
||||||
optionalDepends := operation.GetOptionalDependencies()
|
optionalDepends := operation.GetOptionalDependencies()
|
||||||
|
|
||||||
|
// Executing pre-operation hooks
|
||||||
|
fmt.Println("Running pre-operation hooks...")
|
||||||
|
err = operation.RunPreHooks(verbose)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Error: could not run pre-operation hooks: %s\n", err)
|
||||||
|
exitCode = 1
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// Execute operation
|
// Execute operation
|
||||||
err = operation.Execute(verbose, force)
|
err = operation.Execute(verbose, force)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -1112,15 +1177,17 @@ func updatePackages() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Executing hooks
|
// Executing post-operation hooks
|
||||||
fmt.Println("Running hooks...")
|
fmt.Println("Running post-operation hooks...")
|
||||||
err = operation.RunHooks(verbose)
|
err = operation.RunPostHooks(verbose)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Error: could not run hooks: %s\n", err)
|
log.Printf("Error: could not run post-operation hooks: %s\n", err)
|
||||||
exitCode = 1
|
exitCode = 1
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fmt.Println("Operation complete!")
|
||||||
|
|
||||||
// Show optional dependencies
|
// Show optional dependencies
|
||||||
if len(optionalDepends) != 0 {
|
if len(optionalDepends) != 0 {
|
||||||
// List optional dependencies
|
// List optional dependencies
|
||||||
@@ -1196,6 +1263,7 @@ func compilePackage() {
|
|||||||
rootDir, _ := currentFlagSet.GetString("root")
|
rootDir, _ := currentFlagSet.GetString("root")
|
||||||
verbose, _ := currentFlagSet.GetBool("verbose")
|
verbose, _ := currentFlagSet.GetBool("verbose")
|
||||||
yesAll, _ := currentFlagSet.GetBool("yes")
|
yesAll, _ := currentFlagSet.GetBool("yes")
|
||||||
|
force, _ := currentFlagSet.GetBool("force")
|
||||||
keepCompilationFiles, _ := currentFlagSet.GetBool("keep")
|
keepCompilationFiles, _ := currentFlagSet.GetBool("keep")
|
||||||
installSrcPkgDepends, _ := currentFlagSet.GetBool("depends")
|
installSrcPkgDepends, _ := currentFlagSet.GetBool("depends")
|
||||||
skipChecks, _ := currentFlagSet.GetBool("skip-checks")
|
skipChecks, _ := currentFlagSet.GetBool("skip-checks")
|
||||||
@@ -1228,8 +1296,16 @@ func compilePackage() {
|
|||||||
|
|
||||||
// Compile packages
|
// Compile packages
|
||||||
for _, sourcePackage := range sourcePackages {
|
for _, sourcePackage := range sourcePackages {
|
||||||
if _, err := os.Stat(sourcePackage); os.IsNotExist(err) {
|
// Deconstruct package string
|
||||||
log.Printf("Error: file (%s) does not exist!", sourcePackage)
|
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
|
exitCode = 1
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -1249,6 +1325,12 @@ func compilePackage() {
|
|||||||
return
|
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
|
// Get common, make and check dependencies
|
||||||
totalDepends := make([]string, 0)
|
totalDepends := make([]string, 0)
|
||||||
totalDepends = append(totalDepends, bpmpkg.PkgInfo.Depends...)
|
totalDepends = append(totalDepends, bpmpkg.PkgInfo.Depends...)
|
||||||
@@ -1275,6 +1357,19 @@ func compilePackage() {
|
|||||||
|
|
||||||
// Install missing source package dependencies
|
// Install missing source package dependencies
|
||||||
if installSrcPkgDepends && len(unmetDepends) > 0 {
|
if installSrcPkgDepends && len(unmetDepends) > 0 {
|
||||||
|
// Ignore packages that can't be found in any databases
|
||||||
|
if force {
|
||||||
|
unmetDepends = slices.DeleteFunc(unmetDepends, func(s string) bool {
|
||||||
|
// Deconstruct package string
|
||||||
|
d, err := bpmlib.DeconstructPackageString(s)
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return bpmlib.ResolveDatabaseEntry(d, rootDir) == nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// Get path to current executable
|
// Get path to current executable
|
||||||
executable, err := os.Executable()
|
executable, err := os.Executable()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -1403,7 +1498,7 @@ func compilePackage() {
|
|||||||
return
|
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 {
|
if err != nil {
|
||||||
// Remove unused packages
|
// Remove unused packages
|
||||||
cleanupFunc()
|
cleanupFunc()
|
||||||
|
|||||||
+73
-26
@@ -24,7 +24,7 @@ import (
|
|||||||
var rootCompilationUID = "65534"
|
var rootCompilationUID = "65534"
|
||||||
var rootCompilationGID = "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
|
// Set compilation jobs
|
||||||
if compilationJobs <= 0 || compilationJobs > runtime.NumCPU() {
|
if compilationJobs <= 0 || compilationJobs > runtime.NumCPU() {
|
||||||
compilationJobs = runtime.NumCPU()
|
compilationJobs = runtime.NumCPU()
|
||||||
@@ -96,8 +96,8 @@ func CompileSourcePackage(archiveFilename, outputDirectory string, compilationJo
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extract source.sh file
|
// Extract recipe.sh file
|
||||||
err = extractTarballFile(archiveFilename, "source.sh", tempDirectory, uid, gid)
|
err = extractTarballFile(archiveFilename, "recipe.sh", tempDirectory, uid, gid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -146,6 +146,15 @@ func CompileSourcePackage(archiveFilename, outputDirectory string, compilationJo
|
|||||||
env = append(env, "BPM_PKG_URL="+bpmpkg.PkgInfo.Url)
|
env = append(env, "BPM_PKG_URL="+bpmpkg.PkgInfo.Url)
|
||||||
env = append(env, "BPM_PKG_ARCH="+bpmpkg.PkgInfo.OutputArch)
|
env = append(env, "BPM_PKG_ARCH="+bpmpkg.PkgInfo.OutputArch)
|
||||||
env = append(env, "BPM_JOBS="+strconv.Itoa(compilationJobs))
|
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...)
|
env = append(env, CompilationBPMConfig.CompilationEnvironment...)
|
||||||
|
|
||||||
// Set common flags used for limiting job count
|
// Set common flags used for limiting job count
|
||||||
@@ -166,10 +175,10 @@ func CompileSourcePackage(archiveFilename, outputDirectory string, compilationJo
|
|||||||
env = append(env, "CMAKE_BUILD_PARALLEL_LEVEL="+strconv.Itoa(compilationJobs))
|
env = append(env, "CMAKE_BUILD_PARALLEL_LEVEL="+strconv.Itoa(compilationJobs))
|
||||||
env = append(env, "CARGO_BUILD_JOBS="+strconv.Itoa(compilationJobs))
|
env = append(env, "CARGO_BUILD_JOBS="+strconv.Itoa(compilationJobs))
|
||||||
|
|
||||||
// Execute prepare and build functions in source.sh script
|
// Execute prepare and build functions in recipe.sh script
|
||||||
cmd := exec.Command("bash", "-c",
|
cmd := exec.Command("bash", "-c",
|
||||||
"set -a\n"+ // Source and export functions and variables in source.sh script
|
"set -a\n"+ // Source and export functions and variables in recipe.sh script
|
||||||
". \"${BPM_WORKDIR}\"/source.sh\n"+
|
". \"${BPM_WORKDIR}\"/recipe.sh\n"+
|
||||||
"set +a\n"+
|
"set +a\n"+
|
||||||
"[[ $(type -t prepare) == \"function\" ]] && { echo \"Running prepare() function...\"; bash -e -c 'cd \"$BPM_WORKDIR\" && prepare' || exit 1; }\n"+ // Run prepare() function if it exists
|
"[[ $(type -t prepare) == \"function\" ]] && { echo \"Running prepare() function...\"; bash -e -c 'cd \"$BPM_WORKDIR\" && prepare' || exit 1; }\n"+ // Run prepare() function if it exists
|
||||||
"[[ $(type -t build) == \"function\" ]] && { echo \"Running build() function...\"; bash -e -c 'cd \"$BPM_SOURCE\" && build' || exit 1; }\n"+ // Run build() function if it exists
|
"[[ $(type -t build) == \"function\" ]] && { echo \"Running build() function...\"; bash -e -c 'cd \"$BPM_SOURCE\" && build' || exit 1; }\n"+ // Run build() function if it exists
|
||||||
@@ -187,11 +196,11 @@ func CompileSourcePackage(archiveFilename, outputDirectory string, compilationJo
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Execute check function in source.sh script if not skipping checks
|
// Execute check function in recipe.sh script if not skipping checks
|
||||||
if !skipChecks {
|
if !skipChecks {
|
||||||
cmd = exec.Command("bash", "-c",
|
cmd = exec.Command("bash", "-c",
|
||||||
"set -a\n"+ // Source and export functions and variables in source.sh script
|
"set -a\n"+ // Source and export functions and variables in recipe.sh script
|
||||||
". \"${BPM_WORKDIR}\"/source.sh\n"+
|
". \"${BPM_WORKDIR}\"/recipe.sh\n"+
|
||||||
"set +a\n"+
|
"set +a\n"+
|
||||||
"[[ $(type -t check) == \"function\" ]] && { echo \"Running check() function...\"; bash -e -c 'cd \"$BPM_SOURCE\" && check' || exit 1; }\n"+ // Run check() function if it exists
|
"[[ $(type -t check) == \"function\" ]] && { echo \"Running check() function...\"; bash -e -c 'cd \"$BPM_SOURCE\" && check' || exit 1; }\n"+ // Run check() function if it exists
|
||||||
"exit 0")
|
"exit 0")
|
||||||
@@ -238,10 +247,10 @@ func CompileSourcePackage(archiveFilename, outputDirectory string, compilationJo
|
|||||||
packageFunctionName = "package_" + pkg.Name
|
packageFunctionName = "package_" + pkg.Name
|
||||||
}
|
}
|
||||||
|
|
||||||
// Execute package function in source.sh script and generate package file list
|
// Execute package function in recipe.sh script and generate package file list
|
||||||
cmd = exec.Command("bash", "-c",
|
cmd = exec.Command("bash", "-c",
|
||||||
"set -a\n"+ // Source and export functions and variables in source.sh script
|
"set -a\n"+ // Source and export functions and variables in recipe.sh script
|
||||||
". \"${BPM_WORKDIR}\"/source.sh\n"+
|
". \"${BPM_WORKDIR}\"/recipe.sh\n"+
|
||||||
"set +a\n"+
|
"set +a\n"+
|
||||||
"echo \"Running "+packageFunctionName+"() function...\"\n"+
|
"echo \"Running "+packageFunctionName+"() function...\"\n"+
|
||||||
"( cd \"$BPM_SOURCE\" && fakeroot -s \"$BPM_WORKDIR\"/fakeroot_file bash -e -c '"+packageFunctionName+"' ) || exit 1\n") // Run package() function
|
"( cd \"$BPM_SOURCE\" && fakeroot -s \"$BPM_WORKDIR\"/fakeroot_file bash -e -c '"+packageFunctionName+"' ) || exit 1\n") // Run package() function
|
||||||
@@ -329,7 +338,7 @@ func CompileSourcePackage(archiveFilename, outputDirectory string, compilationJo
|
|||||||
|
|
||||||
// Generate package file list
|
// Generate package file list
|
||||||
fmt.Println("Generating package file list...")
|
fmt.Println("Generating package file list...")
|
||||||
cmd = exec.Command("bash", "-c", "fakeroot -i \"$BPM_WORKDIR\"/fakeroot_file find \"$BPM_OUTPUT\" -mindepth 1 -printf \"%P %#m %U %G %s\\n\" > \"$BPM_WORKDIR\"/pkg.files")
|
cmd = exec.Command("bash", "-c", "fakeroot -i \"$BPM_WORKDIR\"/fakeroot_file find \"$BPM_OUTPUT\" -mindepth 1 -printf \"%P %#m %U %G %s\\n\" > \"$BPM_WORKDIR\"/files.txt")
|
||||||
cmd.Dir = tempDirectory
|
cmd.Dir = tempDirectory
|
||||||
cmd.Stdout = os.Stdout
|
cmd.Stdout = os.Stdout
|
||||||
cmd.Stderr = os.Stderr
|
cmd.Stderr = os.Stderr
|
||||||
@@ -345,7 +354,15 @@ func CompileSourcePackage(archiveFilename, outputDirectory string, compilationJo
|
|||||||
|
|
||||||
// Create gzip-compressed archive for the package files
|
// Create gzip-compressed archive for the package files
|
||||||
fmt.Println("Generating compressed file archive...")
|
fmt.Println("Generating compressed file archive...")
|
||||||
cmd = exec.Command("bash", "-c", fmt.Sprintf("find %s -printf \"%%P\\n\" | fakeroot -i %s/fakeroot_file tar -czf files.tar.gz --no-recursion -C %s -T -", "output_"+pkg.Name, tempDirectory, "output_"+pkg.Name))
|
cmd = exec.Command("bash", "-c", fmt.Sprintf(`find %s -printf "%%P\n" | fakeroot -i %s/fakeroot_file tar czf files.tar.gz \
|
||||||
|
--sort=name \
|
||||||
|
--pax-option=exthdr.name=%%d/PaxHeaders/%%f,delete=atime,delete=ctime \
|
||||||
|
--mtime="UTC 1970-01-01" \
|
||||||
|
--numeric-owner \
|
||||||
|
--no-recursion \
|
||||||
|
-C %s \
|
||||||
|
-T -`,
|
||||||
|
"output_"+pkg.Name, tempDirectory, "output_"+pkg.Name))
|
||||||
cmd.Dir = tempDirectory
|
cmd.Dir = tempDirectory
|
||||||
cmd.Stdout = os.Stdout
|
cmd.Stdout = os.Stdout
|
||||||
cmd.Stderr = os.Stderr
|
cmd.Stderr = os.Stderr
|
||||||
@@ -373,6 +390,31 @@ func CompileSourcePackage(archiveFilename, outputDirectory string, compilationJo
|
|||||||
pkgInfo.SplitPackages = nil
|
pkgInfo.SplitPackages = nil
|
||||||
pkgInfo.Downloads = 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
|
// Marshal package info
|
||||||
pkgInfoBytes, err := yaml.Marshal(pkgInfo)
|
pkgInfoBytes, err := yaml.Marshal(pkgInfo)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -380,26 +422,31 @@ func CompileSourcePackage(archiveFilename, outputDirectory string, compilationJo
|
|||||||
}
|
}
|
||||||
pkgInfoBytes = append(pkgInfoBytes, '\n')
|
pkgInfoBytes = append(pkgInfoBytes, '\n')
|
||||||
|
|
||||||
// Create pkg.info file
|
// Create info.yml file
|
||||||
err = os.WriteFile(path.Join(tempDirectory, "pkg.info"), pkgInfoBytes, 0644)
|
err = os.WriteFile(path.Join(tempDirectory, "info.yml"), pkgInfoBytes, 0644)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Change pkg.info file owner
|
// Change info.yml file owner
|
||||||
err = os.Chown(path.Join(tempDirectory, "pkg.info"), uid, gid)
|
err = os.Chown(path.Join(tempDirectory, "info.yml"), uid, gid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get files to include in BPM archive
|
// Get files to include in BPM archive
|
||||||
bpmArchiveFiles := make([]string, 0)
|
bpmArchiveFiles := make([]string, 0)
|
||||||
bpmArchiveFiles = append(bpmArchiveFiles, "pkg.info", "pkg.files", "files.tar.gz") // Base files
|
bpmArchiveFiles = append(bpmArchiveFiles, "info.yml", "files.txt", "files.tar.gz") // Base files
|
||||||
bpmArchiveFiles = append(bpmArchiveFiles, packageScripts...) // Package scripts
|
bpmArchiveFiles = append(bpmArchiveFiles, packageScripts...) // Package scripts
|
||||||
|
|
||||||
// Create final BPM archive
|
// Create final BPM archive
|
||||||
fmt.Println("Generating final BPM archive...")
|
fmt.Println("Generating final BPM archive...")
|
||||||
cmd = exec.Command("bash", "-c", "tar -cf final-archive.bpm --owner=0 --group=0 -C \"$BPM_WORKDIR\" "+strings.Join(bpmArchiveFiles, " "))
|
cmd = exec.Command("tar", "cf", "final-archive.bpm",
|
||||||
|
"--sort=name",
|
||||||
|
"--pax-option=exthdr.name=%d/PaxHeaders/%f,delete=atime,delete=ctime",
|
||||||
|
"--mtime=UTC 1970-01-01",
|
||||||
|
"--owner=0", "--group=0", "--numeric-owner")
|
||||||
|
cmd.Args = append(cmd.Args, bpmArchiveFiles...)
|
||||||
cmd.Dir = tempDirectory
|
cmd.Dir = tempDirectory
|
||||||
cmd.Stdout = os.Stdout
|
cmd.Stdout = os.Stdout
|
||||||
cmd.Stderr = os.Stderr
|
cmd.Stderr = os.Stderr
|
||||||
@@ -417,8 +464,8 @@ func CompileSourcePackage(archiveFilename, outputDirectory string, compilationJo
|
|||||||
return nil, fmt.Errorf("BPM archive could not be created: %s", err)
|
return nil, fmt.Errorf("BPM archive could not be created: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove pkg.info file
|
// Remove info.yml file
|
||||||
err = os.Remove(path.Join(tempDirectory, "pkg.info"))
|
err = os.Remove(path.Join(tempDirectory, "info.yml"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -725,8 +772,8 @@ func showPackageFiles(archiveFilename string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Print pkg.info content
|
// Print info.yml content
|
||||||
err = printTarballContent("pkg.info")
|
err = printTarballContent("info.yml")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -748,8 +795,8 @@ func showPackageFiles(archiveFilename string) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Print source.sh content
|
// Print recipe.sh content
|
||||||
err = printTarballContent("source.sh")
|
err = printTarballContent("recipe.sh")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import (
|
|||||||
|
|
||||||
type MainBPMConfigStruct struct {
|
type MainBPMConfigStruct struct {
|
||||||
IgnorePackages []string `yaml:"ignore_packages"`
|
IgnorePackages []string `yaml:"ignore_packages"`
|
||||||
|
IgnorePaths []string `yaml:"ignore_paths"`
|
||||||
ShowSourcePackageContents string `yaml:"show_source_package_contents"`
|
ShowSourcePackageContents string `yaml:"show_source_package_contents"`
|
||||||
CleanupMakeDependencies bool `yaml:"cleanup_make_dependencies"`
|
CleanupMakeDependencies bool `yaml:"cleanup_make_dependencies"`
|
||||||
Databases []configDatabase `yaml:"databases"`
|
Databases []configDatabase `yaml:"databases"`
|
||||||
|
|||||||
+202
-32
@@ -42,7 +42,7 @@ type BPMDatabaseEntry struct {
|
|||||||
Database *BPMDatabase
|
Database *BPMDatabase
|
||||||
}
|
}
|
||||||
|
|
||||||
var BPMDatabases = make(map[string]*BPMDatabase)
|
var BPMDatabases = make([]*BPMDatabase, 0)
|
||||||
|
|
||||||
func (db *BPMDatabase) ContainsPackage(pkg string) bool {
|
func (db *BPMDatabase) ContainsPackage(pkg string) bool {
|
||||||
_, ok := db.Entries[pkg]
|
_, ok := db.Entries[pkg]
|
||||||
@@ -135,7 +135,7 @@ func (db *configDatabase) ReadLocalDatabase() error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BPMDatabases[db.Name] = database
|
BPMDatabases = append(BPMDatabases, database)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -207,33 +207,85 @@ func ReadLocalDatabaseFiles() (err error) {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetDatabaseEntry(str string) (*BPMDatabaseEntry, *BPMDatabase, error) {
|
func ResolveDatabaseEntry(d DeconstructedPackageString, rootDir string) *BPMDatabaseEntry {
|
||||||
split := strings.Split(str, "/")
|
results := SearchDatabaseEntries(d.PkgName)
|
||||||
|
for _, result := range results {
|
||||||
|
|
||||||
|
if EvaluatePackageString(result.Info, d) {
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 SearchDatabaseEntries(pkg string) (results []*BPMDatabaseEntry) {
|
||||||
|
split := strings.Split(pkg, "/")
|
||||||
if len(split) == 1 {
|
if len(split) == 1 {
|
||||||
pkgName := strings.TrimSpace(split[0])
|
pkgName := strings.TrimSpace(split[0])
|
||||||
if pkgName == "" {
|
if pkgName == "" {
|
||||||
return nil, nil, errors.New("could not find database entry for this package")
|
return results
|
||||||
}
|
}
|
||||||
for _, db := range BPMDatabases {
|
for _, db := range BPMDatabases {
|
||||||
if db.ContainsPackage(pkgName) {
|
if db.ContainsPackage(pkgName) {
|
||||||
return db.Entries[pkgName], db, nil
|
results = append(results, db.Entries[pkgName])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil, nil, errors.New("could not find database entry for this package")
|
return results
|
||||||
} else if len(split) == 2 {
|
} else if len(split) == 2 {
|
||||||
dbName := strings.TrimSpace(split[0])
|
dbName := strings.TrimSpace(split[0])
|
||||||
pkgName := strings.TrimSpace(split[1])
|
pkgName := strings.TrimSpace(split[1])
|
||||||
if dbName == "" || pkgName == "" {
|
if dbName == "" || pkgName == "" {
|
||||||
return nil, nil, errors.New("could not find database entry for this package")
|
return results
|
||||||
}
|
}
|
||||||
db := BPMDatabases[dbName]
|
dbIndex := slices.IndexFunc(BPMDatabases, func(db *BPMDatabase) bool {
|
||||||
if db == nil || !db.ContainsPackage(pkgName) {
|
return db.Name == dbName
|
||||||
return nil, nil, errors.New("could not find database entry for this package")
|
})
|
||||||
|
if dbIndex < 0 {
|
||||||
|
return results
|
||||||
}
|
}
|
||||||
return db.Entries[pkgName], db, nil
|
|
||||||
} else {
|
db := BPMDatabases[dbIndex]
|
||||||
return nil, nil, errors.New("could not find database entry for this package")
|
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]...)
|
||||||
|
}
|
||||||
|
|
||||||
|
slices.SortFunc(providers, func(a, b *BPMDatabaseEntry) int {
|
||||||
|
return strings.Compare(a.Info.Name, b.Info.Name)
|
||||||
|
})
|
||||||
|
|
||||||
|
return providers
|
||||||
}
|
}
|
||||||
|
|
||||||
func FindReplacement(pkg string) *BPMDatabaseEntry {
|
func FindReplacement(pkg string) *BPMDatabaseEntry {
|
||||||
@@ -250,18 +302,6 @@ func FindReplacement(pkg string) *BPMDatabaseEntry {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetDatabaseVirtualPackageEntry(vpkg string) (providers []*BPMDatabaseEntry) {
|
|
||||||
for _, db := range BPMDatabases {
|
|
||||||
providers = append(providers, db.VirtualPackages[vpkg]...)
|
|
||||||
}
|
|
||||||
|
|
||||||
slices.SortFunc(providers, func(a, b *BPMDatabaseEntry) int {
|
|
||||||
return strings.Compare(a.Info.Name, b.Info.Name)
|
|
||||||
})
|
|
||||||
|
|
||||||
return providers
|
|
||||||
}
|
|
||||||
|
|
||||||
func (db *BPMDatabase) FetchPackage(pkg string) (string, error) {
|
func (db *BPMDatabase) FetchPackage(pkg string) (string, error) {
|
||||||
// Check if package exists in database
|
// Check if package exists in database
|
||||||
if !db.ContainsPackage(pkg) {
|
if !db.ContainsPackage(pkg) {
|
||||||
@@ -300,10 +340,68 @@ func (db *BPMDatabase) FetchPackage(pkg string) (string, error) {
|
|||||||
|
|
||||||
func (entry *BPMDatabaseEntry) GetEntryDependants() (dependants []string) {
|
func (entry *BPMDatabaseEntry) GetEntryDependants() (dependants []string) {
|
||||||
dependantsMap := make(map[string][]string)
|
dependantsMap := make(map[string][]string)
|
||||||
|
|
||||||
|
// Loop through all entries
|
||||||
for _, db := range BPMDatabases {
|
for _, db := range BPMDatabases {
|
||||||
for _, e := range db.Entries {
|
for _, e := range db.Entries {
|
||||||
if slices.Contains(e.Info.Depends, entry.Info.Name) {
|
// Skip iteration if comparing the same packages
|
||||||
dependantsMap[e.Info.Name] = append(dependantsMap[e.Info.Name], e.Database.Name)
|
if e.Info.Name == entry.Info.Name {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add installed package to list if its dependencies include pkgName
|
||||||
|
if slices.ContainsFunc(e.Info.Depends, func(n string) bool {
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add installed package to list if its runtime dependencies include pkgName
|
||||||
|
if slices.ContainsFunc(e.Info.RuntimeDepends, func(n string) bool {
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
// Loop through each virtual package
|
||||||
|
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 {
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add installed package to list if its runtime dependencies contain a provided virtual package
|
||||||
|
if slices.ContainsFunc(e.Info.RuntimeDepends, func(n string) bool {
|
||||||
|
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
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -332,7 +430,13 @@ func (entry *BPMDatabaseEntry) GetEntryOptionalDependants() (dependants []string
|
|||||||
for _, db := range BPMDatabases {
|
for _, db := range BPMDatabases {
|
||||||
for _, e := range db.Entries {
|
for _, e := range db.Entries {
|
||||||
if slices.ContainsFunc(e.Info.OptionalDepends, func(n string) bool {
|
if slices.ContainsFunc(e.Info.OptionalDepends, func(n string) bool {
|
||||||
return strings.SplitN(n, ":", 2)[0] == 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)
|
dependantsMap[e.Info.Name] = append(dependantsMap[e.Info.Name], e.Database.Name)
|
||||||
}
|
}
|
||||||
@@ -362,7 +466,15 @@ func (entry *BPMDatabaseEntry) GetEntryMakeDependants() (dependants []string) {
|
|||||||
dependantsMap := make(map[string][]string)
|
dependantsMap := make(map[string][]string)
|
||||||
for _, db := range BPMDatabases {
|
for _, db := range BPMDatabases {
|
||||||
for _, e := range db.Entries {
|
for _, e := range db.Entries {
|
||||||
if slices.Contains(e.Info.MakeDepends, entry.Info.Name) {
|
if slices.ContainsFunc(e.Info.MakeDepends, func(n string) bool {
|
||||||
|
// 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)
|
dependantsMap[e.Info.Name] = append(dependantsMap[e.Info.Name], e.Database.Name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -422,7 +534,7 @@ func (entry *BPMDatabaseEntry) CreateReadableInfo(rootDir string, showBytes bool
|
|||||||
builder.WriteString(" - " + val)
|
builder.WriteString(" - " + val)
|
||||||
|
|
||||||
// Show virtual package providers
|
// Show virtual package providers
|
||||||
if providers := GetDatabaseVirtualPackageEntry(val); len(providers) > 0 {
|
if providers := SearchDatabaseVirtualPackageProviders(val); len(providers) > 0 {
|
||||||
builder.WriteString(" (")
|
builder.WriteString(" (")
|
||||||
for i, vpkg := range providers {
|
for i, vpkg := range providers {
|
||||||
if i == len(providers)-1 {
|
if i == len(providers)-1 {
|
||||||
@@ -452,6 +564,64 @@ func (entry *BPMDatabaseEntry) CreateReadableInfo(rootDir string, showBytes bool
|
|||||||
}
|
}
|
||||||
builder.WriteString("Type: " + entry.Info.Type + "\n")
|
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
|
// Dependencies
|
||||||
builderWriteDependencyArray("Dependencies", entry.Info.Depends)
|
builderWriteDependencyArray("Dependencies", entry.Info.Depends)
|
||||||
if entry.Info.Type == "source" {
|
if entry.Info.Type == "source" {
|
||||||
@@ -470,7 +640,7 @@ func (entry *BPMDatabaseEntry) CreateReadableInfo(rootDir string, showBytes bool
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Show virtual package providers
|
// Show virtual package providers
|
||||||
if providers := GetDatabaseVirtualPackageEntry(dependSplit[0]); len(providers) > 0 {
|
if providers := SearchDatabaseVirtualPackageProviders(dependSplit[0]); len(providers) > 0 {
|
||||||
builder.WriteString(" (")
|
builder.WriteString(" (")
|
||||||
for i, vpkg := range providers {
|
for i, vpkg := range providers {
|
||||||
if i == len(providers)-1 {
|
if i == len(providers)-1 {
|
||||||
|
|||||||
+299
-27
@@ -1,11 +1,13 @@
|
|||||||
package bpmlib
|
package bpmlib
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
|
"maps"
|
||||||
"slices"
|
"slices"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (pkgInfo *PackageInfo) GetPackageDependants(rootDir string) (dependants []string) {
|
func (pkgInfo *PackageInfo) GetPackageDependants(rootDir string, skipMultipleProviders bool) (dependants []string) {
|
||||||
// Get installed package names
|
// Get installed package names
|
||||||
pkgs, ok := localPackageInformation[rootDir]
|
pkgs, ok := localPackageInformation[rootDir]
|
||||||
if !ok {
|
if !ok {
|
||||||
@@ -21,7 +23,13 @@ func (pkgInfo *PackageInfo) GetPackageDependants(rootDir string) (dependants []s
|
|||||||
|
|
||||||
// Add installed package to list if its dependencies include pkgName
|
// Add installed package to list if its dependencies include pkgName
|
||||||
if slices.ContainsFunc(installedPkg.Depends, func(n string) bool {
|
if slices.ContainsFunc(installedPkg.Depends, func(n string) bool {
|
||||||
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)
|
dependants = append(dependants, installedPkg.Name)
|
||||||
continue
|
continue
|
||||||
@@ -29,7 +37,13 @@ func (pkgInfo *PackageInfo) GetPackageDependants(rootDir string) (dependants []s
|
|||||||
|
|
||||||
// Add installed package to list if its runtime dependencies include pkgName
|
// Add installed package to list if its runtime dependencies include pkgName
|
||||||
if slices.ContainsFunc(installedPkg.RuntimeDepends, func(n string) bool {
|
if slices.ContainsFunc(installedPkg.RuntimeDepends, func(n string) bool {
|
||||||
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)
|
dependants = append(dependants, installedPkg.Name)
|
||||||
continue
|
continue
|
||||||
@@ -37,9 +51,19 @@ func (pkgInfo *PackageInfo) GetPackageDependants(rootDir string) (dependants []s
|
|||||||
|
|
||||||
// Loop through each virtual package
|
// Loop through each virtual package
|
||||||
for _, vpkg := range pkgInfo.Provides {
|
for _, vpkg := range pkgInfo.Provides {
|
||||||
|
if skipMultipleProviders && len(GetVirtualPackageInfo(vpkg, rootDir)) > 1 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
// Add installed package to list if its dependencies contain a provided virtual package
|
// Add installed package to list if its dependencies contain a provided virtual package
|
||||||
if slices.ContainsFunc(installedPkg.Depends, func(n string) bool {
|
if slices.ContainsFunc(installedPkg.Depends, func(n string) bool {
|
||||||
return n == vpkg
|
// Deconstruct package string
|
||||||
|
d, err := DeconstructPackageString(n)
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return d.PkgName == vpkg
|
||||||
}) {
|
}) {
|
||||||
dependants = append(dependants, installedPkg.Name)
|
dependants = append(dependants, installedPkg.Name)
|
||||||
break
|
break
|
||||||
@@ -47,7 +71,13 @@ func (pkgInfo *PackageInfo) GetPackageDependants(rootDir string) (dependants []s
|
|||||||
|
|
||||||
// Add installed package to list if its runtime dependencies contain a provided virtual package
|
// Add installed package to list if its runtime dependencies contain a provided virtual package
|
||||||
if slices.ContainsFunc(installedPkg.RuntimeDepends, func(n string) bool {
|
if slices.ContainsFunc(installedPkg.RuntimeDepends, func(n string) bool {
|
||||||
return n == vpkg
|
// Deconstruct package string
|
||||||
|
d, err := DeconstructPackageString(n)
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return d.PkgName == vpkg
|
||||||
}) {
|
}) {
|
||||||
dependants = append(dependants, installedPkg.Name)
|
dependants = append(dependants, installedPkg.Name)
|
||||||
break
|
break
|
||||||
@@ -74,7 +104,13 @@ func (pkgInfo *PackageInfo) GetPackageOptionalDependants(rootDir string) (depend
|
|||||||
|
|
||||||
// Add installed package to list if its optional dependencies include pkgName
|
// Add installed package to list if its optional dependencies include pkgName
|
||||||
if slices.ContainsFunc(installedPkg.OptionalDepends, func(n string) bool {
|
if slices.ContainsFunc(installedPkg.OptionalDepends, func(n string) bool {
|
||||||
return strings.SplitN(n, ":", 2)[0] == pkgInfo.Name
|
// Deconstruct package string
|
||||||
|
d, err := DeconstructPackageString(n)
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return d.PkgName == pkgInfo.Name
|
||||||
}) {
|
}) {
|
||||||
dependants = append(dependants, installedPkg.Name)
|
dependants = append(dependants, installedPkg.Name)
|
||||||
continue
|
continue
|
||||||
@@ -84,7 +120,13 @@ func (pkgInfo *PackageInfo) GetPackageOptionalDependants(rootDir string) (depend
|
|||||||
for _, vpkg := range pkgInfo.Provides {
|
for _, vpkg := range pkgInfo.Provides {
|
||||||
// Add installed package to list if its optional dependencies contain a provided virtual package
|
// Add installed package to list if its optional dependencies contain a provided virtual package
|
||||||
if slices.ContainsFunc(installedPkg.OptionalDepends, func(n string) bool {
|
if slices.ContainsFunc(installedPkg.OptionalDepends, func(n string) bool {
|
||||||
return strings.SplitN(n, ":", 2)[0] == vpkg
|
// Deconstruct package string
|
||||||
|
d, err := DeconstructPackageString(n)
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return d.PkgName == vpkg
|
||||||
}) {
|
}) {
|
||||||
dependants = append(dependants, installedPkg.Name)
|
dependants = append(dependants, installedPkg.Name)
|
||||||
break
|
break
|
||||||
@@ -97,41 +139,85 @@ func (pkgInfo *PackageInfo) GetPackageOptionalDependants(rootDir string) (depend
|
|||||||
|
|
||||||
type ResolvedPackage struct {
|
type ResolvedPackage struct {
|
||||||
DatabaseEntry *BPMDatabaseEntry
|
DatabaseEntry *BPMDatabaseEntry
|
||||||
|
Flags map[string]string
|
||||||
InstallationReason InstallationReason
|
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)
|
visited := make([]string, 0)
|
||||||
|
|
||||||
var dfs func(resolvedPkg *PackageInfo)
|
var dfs func(resolvedPkg *PackageInfo, flags map[string]string)
|
||||||
dfs = func(pkgInfo *PackageInfo) {
|
dfs = func(pkgInfo *PackageInfo, flags map[string]string) {
|
||||||
checkDependencies := func(dependencies []string, installationReason InstallationReason) {
|
checkDependencies := func(dependencies []string, installationReason InstallationReason) {
|
||||||
for _, depend := range dependencies {
|
for _, depend := range dependencies {
|
||||||
// Ignore if package is already installed
|
// Deconstruct package string
|
||||||
if IsPackageInstalled(depend, rootDir) {
|
d, err := DeconstructPackageString(depend)
|
||||||
continue
|
if err != nil {
|
||||||
} else if providers := GetVirtualPackageInfo(depend, rootDir); len(providers) > 0 {
|
unresolved[depend] = "could not deconstruct package string: " + err.Error()
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check resolved virtual packages
|
||||||
|
if resolvedPkg, ok := resolvedVirtualPackages[d.PkgName]; ok {
|
||||||
|
d.PkgName = resolvedPkg
|
||||||
|
}
|
||||||
|
|
||||||
// Find database entry for dependency
|
// Find database entry for dependency
|
||||||
var dependEntry *BPMDatabaseEntry
|
dependEntry := ResolveDatabaseEntry(d, rootDir)
|
||||||
if resolvedVpkg, ok := resolvedVirtualPackages[depend]; ok {
|
|
||||||
dependEntry, _, _ = GetDatabaseEntry(resolvedVpkg)
|
|
||||||
} else if entry, _, _ := GetDatabaseEntry(depend); entry != nil {
|
|
||||||
dependEntry = entry
|
|
||||||
} else if providers := GetDatabaseVirtualPackageEntry(depend); len(providers) > 0 {
|
|
||||||
dependEntry = providers[0]
|
|
||||||
}
|
|
||||||
|
|
||||||
if dependEntry == nil {
|
if dependEntry == nil {
|
||||||
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
|
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 {
|
||||||
|
resolvedVirtualPackages[vpkg] = dependEntry.Info.Name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Resolve entry dependencies
|
||||||
if !slices.Contains(visited, dependEntry.Info.Name) {
|
if !slices.Contains(visited, dependEntry.Info.Name) {
|
||||||
dfs(dependEntry.Info)
|
dfs(dependEntry.Info, d.Flags)
|
||||||
resolved = append(resolved, ResolvedPackage{DatabaseEntry: dependEntry, InstallationReason: installationReason})
|
resolved = append(resolved, ResolvedPackage{DatabaseEntry: dependEntry, Flags: d.Flags, InstallationReason: installationReason})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -145,10 +231,196 @@ func ResolveDependencies(pkgInfo *PackageInfo, resolvedVirtualPackages map[strin
|
|||||||
if pkgInfo.Type == "source" {
|
if pkgInfo.Type == "source" {
|
||||||
checkDependencies(pkgInfo.MakeDepends, InstallationReasonMakeDependency)
|
checkDependencies(pkgInfo.MakeDepends, InstallationReasonMakeDependency)
|
||||||
checkDependencies(pkgInfo.CheckDepends, 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
|
return resolved, unresolved
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type DeconstructedPackageString struct {
|
||||||
|
PkgName string
|
||||||
|
Description string
|
||||||
|
Flags map[string]string
|
||||||
|
RequiredVersionOperator string
|
||||||
|
RequiredVersion string
|
||||||
|
}
|
||||||
|
|
||||||
|
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]
|
||||||
|
}
|
||||||
|
|
||||||
|
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:]
|
||||||
|
|
||||||
|
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 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
|
||||||
|
}
|
||||||
|
|||||||
+13
-10
@@ -2,23 +2,25 @@ package bpmlib
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"maps"
|
||||||
|
"slices"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
type PackageNotFoundErr struct {
|
type PackageNotResolvedErr struct {
|
||||||
packages []string
|
packages map[string]string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e PackageNotFoundErr) Error() string {
|
func (e PackageNotResolvedErr) Error() (ret string) {
|
||||||
return "The following packages were not found in any databases: " + strings.Join(e.packages, ", ")
|
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 {
|
return ret
|
||||||
dependencies []string
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e DependencyNotFoundErr) Error() string {
|
|
||||||
return "The following dependencies were not found in any databases: " + strings.Join(e.dependencies, ", ")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type PackageConflictErr struct {
|
type PackageConflictErr struct {
|
||||||
@@ -27,6 +29,7 @@ type PackageConflictErr struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (e PackageConflictErr) Error() string {
|
func (e PackageConflictErr) Error() string {
|
||||||
|
slices.Sort(e.conflicts)
|
||||||
return fmt.Sprintf("Package (%s) is in conflict with the following packages: %s", e.pkg, strings.Join(e.conflicts, ", "))
|
return fmt.Sprintf("Package (%s) is in conflict with the following packages: %s", e.pkg, strings.Join(e.conflicts, ", "))
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+166
-46
@@ -16,8 +16,8 @@ func InstallPackages(rootDir string, forceInstallationReason InstallationReason,
|
|||||||
// Setup operation struct
|
// Setup operation struct
|
||||||
operation = &BPMOperation{
|
operation = &BPMOperation{
|
||||||
Actions: make([]OperationAction, 0),
|
Actions: make([]OperationAction, 0),
|
||||||
UnresolvedDepends: make([]string, 0),
|
UnresolvedDepends: make(map[string]string, 0),
|
||||||
Changes: make(map[string]string),
|
ModifiedFiles: make(map[string]string),
|
||||||
RunChecks: runChecks,
|
RunChecks: runChecks,
|
||||||
RootDir: rootDir,
|
RootDir: rootDir,
|
||||||
compiledPackages: make(map[string]string),
|
compiledPackages: make(map[string]string),
|
||||||
@@ -27,20 +27,58 @@ func InstallPackages(rootDir string, forceInstallationReason InstallationReason,
|
|||||||
packages = removeDuplicates(packages)
|
packages = removeDuplicates(packages)
|
||||||
|
|
||||||
// Resolve packages
|
// Resolve packages
|
||||||
pkgsNotFound := make([]string, 0)
|
unresolvedPackages := make(map[string]string)
|
||||||
|
resolvedVirtualPackages := make(map[string]string)
|
||||||
for _, pkg := range packages {
|
for _, pkg := range packages {
|
||||||
if stat, err := os.Stat(pkg); err == nil && !stat.IsDir() {
|
d, err := DeconstructPackageString(pkg)
|
||||||
bpmpkg, err := ReadPackage(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 {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("could not read package: %s", err)
|
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 {
|
for _, splitPkg := range bpmpkg.PkgInfo.SplitPackages {
|
||||||
if !reinstallPackages && IsPackageInstalled(splitPkg.Name, rootDir) && GetPackageInfo(splitPkg.Name, rootDir).GetFullVersion() == splitPkg.GetFullVersion() {
|
if !reinstallPackages && IsPackageInstalled(splitPkg.Name, rootDir) && GetPackageInfo(splitPkg.Name, rootDir).GetFullVersion() == splitPkg.GetFullVersion() {
|
||||||
continue
|
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
|
// Set package installation reason
|
||||||
installationReason := forceInstallationReason
|
installationReason := forceInstallationReason
|
||||||
if installationReason == InstallationReasonUnknown {
|
if installationReason == InstallationReasonUnknown {
|
||||||
@@ -51,9 +89,17 @@ func InstallPackages(rootDir string, forceInstallationReason InstallationReason,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
operation.AppendAction(&InstallPackageAction{
|
// 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,
|
File: pkg,
|
||||||
InstallationReason: installationReason,
|
InstallationReason: installationReason,
|
||||||
|
Flags: d.Flags,
|
||||||
BpmPackage: bpmpkg,
|
BpmPackage: bpmpkg,
|
||||||
SplitPackageToInstall: splitPkg.Name,
|
SplitPackageToInstall: splitPkg.Name,
|
||||||
})
|
})
|
||||||
@@ -61,9 +107,24 @@ func InstallPackages(rootDir string, forceInstallationReason InstallationReason,
|
|||||||
continue
|
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
|
continue
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Set package installation reason
|
// Set package installation reason
|
||||||
installationReason := forceInstallationReason
|
installationReason := forceInstallationReason
|
||||||
@@ -75,30 +136,64 @@ func InstallPackages(rootDir string, forceInstallationReason InstallationReason,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
operation.AppendAction(&InstallPackageAction{
|
// Resolve virtual packages
|
||||||
|
for _, vpkg := range bpmpkg.PkgInfo.Provides {
|
||||||
|
if _, ok := resolvedVirtualPackages[vpkg]; !ok {
|
||||||
|
resolvedVirtualPackages[vpkg] = bpmpkg.PkgInfo.Name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
operation.Actions = append(operation.Actions, &InstallPackageAction{
|
||||||
File: pkg,
|
File: pkg,
|
||||||
InstallationReason: installationReason,
|
InstallationReason: installationReason,
|
||||||
|
Flags: d.Flags,
|
||||||
BpmPackage: bpmpkg,
|
BpmPackage: bpmpkg,
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
var entry *BPMDatabaseEntry
|
// Check resolved virtual packages
|
||||||
|
if resolvedPkg, ok := resolvedVirtualPackages[d.PkgName]; ok {
|
||||||
|
d.PkgName = resolvedPkg
|
||||||
|
}
|
||||||
|
|
||||||
if e, _, err := GetDatabaseEntry(pkg); err == nil {
|
entry := ResolveDatabaseEntry(d, rootDir)
|
||||||
entry = e
|
if entry == nil {
|
||||||
} else if providers := GetVirtualPackageInfo(pkg, rootDir); len(providers) > 0 {
|
unresolvedPackages[pkg] = "could not find in any database"
|
||||||
entry, _, err = GetDatabaseEntry(providers[0].Name)
|
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 {
|
if err != nil {
|
||||||
pkgsNotFound = append(pkgsNotFound, pkg)
|
return nil, fmt.Errorf("could not combine flags for package (%s): %s", entry.Info.Name, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
entry = ResolveDatabaseEntry(d, rootDir)
|
||||||
|
if entry == nil {
|
||||||
|
unresolvedPackages[pkg] = "could not find in any database"
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
} else if providers := GetDatabaseVirtualPackageEntry(pkg); len(providers) > 0 {
|
}
|
||||||
entry = providers[0]
|
|
||||||
} else {
|
// Check if installation can be ignored
|
||||||
pkgsNotFound = append(pkgsNotFound, pkg)
|
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
|
continue
|
||||||
}
|
}
|
||||||
if !reinstallPackages && IsPackageInstalled(entry.Info.Name, rootDir) && GetPackageInfo(entry.Info.Name, rootDir).GetFullVersion() == entry.Info.GetFullVersion() {
|
|
||||||
continue
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set package installation reason
|
// Set package installation reason
|
||||||
@@ -111,25 +206,33 @@ func InstallPackages(rootDir string, forceInstallationReason InstallationReason,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
operation.AppendAction(&FetchPackageAction{
|
// Resolve virtual packages
|
||||||
|
for _, vpkg := range entry.Info.Provides {
|
||||||
|
if _, ok := resolvedVirtualPackages[vpkg]; !ok {
|
||||||
|
resolvedVirtualPackages[vpkg] = entry.Info.Name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
operation.Actions = append(operation.Actions, &FetchPackageAction{
|
||||||
InstallationReason: installationReason,
|
InstallationReason: installationReason,
|
||||||
|
Flags: d.Flags,
|
||||||
DatabaseEntry: entry,
|
DatabaseEntry: entry,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return error if not all packages are found
|
// Return error if not all packages are found
|
||||||
if len(pkgsNotFound) != 0 {
|
if len(unresolvedPackages) != 0 {
|
||||||
return nil, PackageNotFoundErr{pkgsNotFound}
|
return nil, PackageNotResolvedErr{unresolvedPackages}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Resolve dependencies
|
// Resolve dependencies
|
||||||
operation.ResolveDependencies(installRuntimeDependencies)
|
operation.ResolveDependencies(installRuntimeDependencies)
|
||||||
if len(operation.UnresolvedDepends) != 0 {
|
if len(operation.UnresolvedDepends) != 0 {
|
||||||
if !forceInstallation {
|
if !forceInstallation {
|
||||||
return nil, DependencyNotFoundErr{operation.UnresolvedDepends}
|
return nil, PackageNotResolvedErr{operation.UnresolvedDepends}
|
||||||
} else if verbose {
|
} else if verbose {
|
||||||
log.Printf("Warning: %s", DependencyNotFoundErr{operation.UnresolvedDepends})
|
log.Printf("Warning: %s", PackageNotResolvedErr{operation.UnresolvedDepends})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -179,8 +282,8 @@ func InstallPackages(rootDir string, forceInstallationReason InstallationReason,
|
|||||||
func RemovePackages(rootDir string, force, cleanupDependencies bool, packages ...string) (operation *BPMOperation, err error) {
|
func RemovePackages(rootDir string, force, cleanupDependencies bool, packages ...string) (operation *BPMOperation, err error) {
|
||||||
operation = &BPMOperation{
|
operation = &BPMOperation{
|
||||||
Actions: make([]OperationAction, 0),
|
Actions: make([]OperationAction, 0),
|
||||||
UnresolvedDepends: make([]string, 0),
|
UnresolvedDepends: make(map[string]string),
|
||||||
Changes: make(map[string]string),
|
ModifiedFiles: make(map[string]string),
|
||||||
RootDir: rootDir,
|
RootDir: rootDir,
|
||||||
compiledPackages: make(map[string]string),
|
compiledPackages: make(map[string]string),
|
||||||
}
|
}
|
||||||
@@ -197,7 +300,7 @@ func RemovePackages(rootDir string, force, cleanupDependencies bool, packages ..
|
|||||||
if bpmpkg == nil {
|
if bpmpkg == nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
operation.AppendAction(&RemovePackageAction{BpmPackage: bpmpkg})
|
operation.Actions = append(operation.Actions, &RemovePackageAction{BpmPackage: bpmpkg})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Do package cleanup
|
// Do package cleanup
|
||||||
@@ -213,12 +316,12 @@ func RemovePackages(rootDir string, force, cleanupDependencies bool, packages ..
|
|||||||
// Get packages and their dependants
|
// Get packages and their dependants
|
||||||
packageDepndants := make(map[string][]string, 0)
|
packageDepndants := make(map[string][]string, 0)
|
||||||
for _, action := range operation.Actions {
|
for _, action := range operation.Actions {
|
||||||
// Skip package if ignored
|
// Skip package if ignored in config
|
||||||
if slices.Contains(MainBPMConfig.IgnorePackages, action.(*RemovePackageAction).BpmPackage.PkgInfo.Name) {
|
if rootDir == "/" && slices.Contains(MainBPMConfig.IgnorePackages, action.(*RemovePackageAction).BpmPackage.PkgInfo.Name) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
dependants := action.(*RemovePackageAction).BpmPackage.PkgInfo.GetPackageDependants(rootDir)
|
dependants := action.(*RemovePackageAction).BpmPackage.PkgInfo.GetPackageDependants(rootDir, true)
|
||||||
packageDepndants[action.(*RemovePackageAction).BpmPackage.PkgInfo.Name] = dependants
|
packageDepndants[action.(*RemovePackageAction).BpmPackage.PkgInfo.Name] = dependants
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -234,7 +337,7 @@ func RemovePackages(rootDir string, force, cleanupDependencies bool, packages ..
|
|||||||
// Remove dependant packages if ignored
|
// Remove dependant packages if ignored
|
||||||
for pkg, required := range packageDepndants {
|
for pkg, required := range packageDepndants {
|
||||||
required = slices.DeleteFunc(required, func(pkgName string) bool {
|
required = slices.DeleteFunc(required, func(pkgName string) bool {
|
||||||
return slices.Contains(MainBPMConfig.IgnorePackages, pkgName)
|
return rootDir == "/" && slices.Contains(MainBPMConfig.IgnorePackages, pkgName)
|
||||||
})
|
})
|
||||||
packageDepndants[pkg] = required
|
packageDepndants[pkg] = required
|
||||||
}
|
}
|
||||||
@@ -257,8 +360,8 @@ func RemovePackages(rootDir string, force, cleanupDependencies bool, packages ..
|
|||||||
func CleanupPackages(cleanupMakeDepends bool, rootDir string) (operation *BPMOperation, err error) {
|
func CleanupPackages(cleanupMakeDepends bool, rootDir string) (operation *BPMOperation, err error) {
|
||||||
operation = &BPMOperation{
|
operation = &BPMOperation{
|
||||||
Actions: make([]OperationAction, 0),
|
Actions: make([]OperationAction, 0),
|
||||||
UnresolvedDepends: make([]string, 0),
|
UnresolvedDepends: make(map[string]string),
|
||||||
Changes: make(map[string]string),
|
ModifiedFiles: make(map[string]string),
|
||||||
RootDir: rootDir,
|
RootDir: rootDir,
|
||||||
compiledPackages: make(map[string]string),
|
compiledPackages: make(map[string]string),
|
||||||
}
|
}
|
||||||
@@ -385,47 +488,64 @@ func UpdatePackages(rootDir string, syncDatabase, allowDowngrades, forceInstalla
|
|||||||
|
|
||||||
operation = &BPMOperation{
|
operation = &BPMOperation{
|
||||||
Actions: make([]OperationAction, 0),
|
Actions: make([]OperationAction, 0),
|
||||||
UnresolvedDepends: make([]string, 0),
|
UnresolvedDepends: make(map[string]string),
|
||||||
Changes: make(map[string]string),
|
ModifiedFiles: make(map[string]string),
|
||||||
RunChecks: runChecks,
|
RunChecks: runChecks,
|
||||||
RootDir: rootDir,
|
RootDir: rootDir,
|
||||||
compiledPackages: make(map[string]string),
|
compiledPackages: make(map[string]string),
|
||||||
}
|
}
|
||||||
|
|
||||||
// Search for packages
|
// Search for packages
|
||||||
|
resolvedVirtualPackages := make(map[string]string)
|
||||||
for _, pkg := range pkgs {
|
for _, pkg := range pkgs {
|
||||||
if slices.Contains(MainBPMConfig.IgnorePackages, pkg) {
|
if rootDir == "/" && slices.Contains(MainBPMConfig.IgnorePackages, pkg) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get installed package built flags
|
||||||
|
flags := getPackageLocalInfo(pkg, rootDir).Flags
|
||||||
|
|
||||||
var entry *BPMDatabaseEntry
|
var entry *BPMDatabaseEntry
|
||||||
// Check if installed package can be replaced and install that instead
|
// Check if installed package can be replaced and install that instead
|
||||||
if e := FindReplacement(pkg); e != nil {
|
if e := FindReplacement(pkg); e != nil {
|
||||||
entry = e
|
entry = e
|
||||||
} else if entry, _, err = GetDatabaseEntry(pkg); err != nil {
|
} else if entry = ResolveDatabaseEntry(DeconstructedPackageString{PkgName: pkg, Flags: flags}, rootDir); entry == nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
installedInfo := GetPackageInfo(pkg, rootDir)
|
// Remove invalid flags
|
||||||
if installedInfo == nil {
|
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)
|
return nil, fmt.Errorf("could not get package info for package (%s)", pkg)
|
||||||
} else {
|
} else {
|
||||||
comparison := CompareVersions(entry.Info.GetFullVersion(), installedInfo.GetFullVersion())
|
comparison := CompareVersions(entry.Info.GetFullVersion(), installedInfo.GetFullVersion())
|
||||||
if (!allowDowngrades && comparison > 0) || (allowDowngrades && comparison != 0) {
|
if (!allowDowngrades && comparison > 0) || (allowDowngrades && comparison != 0) {
|
||||||
operation.AppendAction(&FetchPackageAction{
|
// Resolve virtual packages
|
||||||
InstallationReason: GetPackage(pkg, rootDir).LocalInfo.GetInstallationReason(),
|
for _, vpkg := range entry.Info.Provides {
|
||||||
|
if _, ok := resolvedVirtualPackages[vpkg]; !ok {
|
||||||
|
resolvedVirtualPackages[vpkg] = entry.Info.Name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bpmpkg := GetPackage(pkg, rootDir)
|
||||||
|
|
||||||
|
operation.Actions = append(operation.Actions, &FetchPackageAction{
|
||||||
|
InstallationReason: bpmpkg.LocalInfo.GetInstallationReason(),
|
||||||
|
Flags: flags,
|
||||||
DatabaseEntry: entry,
|
DatabaseEntry: entry,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for new dependencies in updated packages
|
// Resolve dependencies
|
||||||
operation.ResolveDependencies(true)
|
operation.ResolveDependencies(true)
|
||||||
if len(operation.UnresolvedDepends) != 0 {
|
if len(operation.UnresolvedDepends) != 0 {
|
||||||
if !forceInstallation {
|
if !forceInstallation {
|
||||||
return nil, DependencyNotFoundErr{operation.UnresolvedDepends}
|
return nil, PackageNotResolvedErr{operation.UnresolvedDepends}
|
||||||
} else if verbose {
|
} else if verbose {
|
||||||
log.Printf("Warning: %s", DependencyNotFoundErr{operation.UnresolvedDepends})
|
log.Printf("Warning: %s", PackageNotResolvedErr{operation.UnresolvedDepends})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+40
-61
@@ -1,26 +1,27 @@
|
|||||||
package bpmlib
|
package bpmlib
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"gopkg.in/yaml.v3"
|
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"path"
|
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"slices"
|
"slices"
|
||||||
"strings"
|
"strings"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
|
"gopkg.in/yaml.v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
type BPMHook struct {
|
type BPMHook struct {
|
||||||
SourcePath string
|
SourcePath string
|
||||||
SourceContent string
|
SourceContent string
|
||||||
TriggerOperations []string `yaml:"trigger_operations"`
|
TriggerActions []string `yaml:"trigger_actions"`
|
||||||
TargetType string `yaml:"target_type"`
|
TriggerPreOperation bool `yaml:"trigger_pre_operation"`
|
||||||
Targets []string `yaml:"targets"`
|
Targets []string `yaml:"targets"`
|
||||||
Depends []string `yaml:"depends"`
|
|
||||||
Run string `yaml:"run"`
|
Run string `yaml:"run"`
|
||||||
|
PassTargets bool `yaml:"pass_targets"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// createHook returns a BPMHook instance based on the content of the given string
|
// createHook returns a BPMHook instance based on the content of the given string
|
||||||
@@ -35,10 +36,8 @@ func createHook(sourcePath string) (*BPMHook, error) {
|
|||||||
hook := &BPMHook{
|
hook := &BPMHook{
|
||||||
SourcePath: sourcePath,
|
SourcePath: sourcePath,
|
||||||
SourceContent: string(bytes),
|
SourceContent: string(bytes),
|
||||||
TriggerOperations: nil,
|
TriggerActions: nil,
|
||||||
TargetType: "",
|
|
||||||
Targets: nil,
|
Targets: nil,
|
||||||
Depends: nil,
|
|
||||||
Run: "",
|
Run: "",
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -61,19 +60,15 @@ func (hook *BPMHook) IsValid() error {
|
|||||||
ValidOperations := []string{"install", "upgrade", "remove"}
|
ValidOperations := []string{"install", "upgrade", "remove"}
|
||||||
|
|
||||||
// Return error if any trigger operation is not valid or none are given
|
// Return error if any trigger operation is not valid or none are given
|
||||||
if len(hook.TriggerOperations) == 0 {
|
if len(hook.TriggerActions) == 0 {
|
||||||
return errors.New("no trigger operations specified")
|
return errors.New("no trigger operations specified")
|
||||||
}
|
}
|
||||||
for _, operation := range hook.TriggerOperations {
|
for _, operation := range hook.TriggerActions {
|
||||||
if !slices.Contains(ValidOperations, operation) {
|
if !slices.Contains(ValidOperations, operation) {
|
||||||
return errors.New("trigger operation '" + operation + "' is not valid")
|
return errors.New("trigger operation '" + operation + "' is not valid")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if hook.TargetType != "package" && hook.TargetType != "path" {
|
|
||||||
return errors.New("target type '" + hook.TargetType + "' is not valid")
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(hook.Run) == 0 {
|
if len(hook.Run) == 0 {
|
||||||
return errors.New("command to run is empty")
|
return errors.New("command to run is empty")
|
||||||
}
|
}
|
||||||
@@ -83,55 +78,30 @@ func (hook *BPMHook) IsValid() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Execute hook if all conditions are met
|
// Execute hook if all conditions are met
|
||||||
func (hook *BPMHook) Execute(packageChanges map[string]string, verbose bool, rootDir string) error {
|
func (hook *BPMHook) Execute(modifiedFiles map[string]string, preOperation bool, verbose bool, rootDir string) error {
|
||||||
// Check if package dependencies are met
|
|
||||||
installedPackages, err := GetInstalledPackages(rootDir)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, depend := range hook.Depends {
|
|
||||||
if !slices.Contains(installedPackages, depend) {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get modified files slice
|
|
||||||
modifiedFiles := make([]*PackageFileEntry, 0)
|
|
||||||
for pkg := range packageChanges {
|
|
||||||
if GetPackage(pkg, rootDir) != nil {
|
|
||||||
modifiedFiles = append(modifiedFiles, GetPackage(pkg, rootDir).PkgFiles...)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if any targets are met
|
// Check if any targets are met
|
||||||
targetMet := false
|
targetsMet := make([]string, 0)
|
||||||
for _, target := range hook.Targets {
|
for _, target := range hook.Targets {
|
||||||
if targetMet {
|
for modifiedFile, action := range modifiedFiles {
|
||||||
break
|
// Check if this hook is triggered by this file's action
|
||||||
|
if !slices.Contains(hook.TriggerActions, action) {
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
if hook.TargetType == "package" {
|
|
||||||
for change, operation := range packageChanges {
|
// Check if file has already been checked
|
||||||
if target == change && slices.Contains(hook.TriggerOperations, operation) {
|
if slices.Contains(targetsMet, modifiedFile) {
|
||||||
targetMet = true
|
continue
|
||||||
break
|
}
|
||||||
|
|
||||||
|
if matched, _ := filepath.Match(target, modifiedFile); !matched {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
targetsMet = append(targetsMet, modifiedFile)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
glob, err := filepath.Glob(path.Join(rootDir, target))
|
if len(targetsMet) == 0 {
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
for _, change := range modifiedFiles {
|
|
||||||
if slices.Contains(glob, path.Join(rootDir, change.Path)) {
|
|
||||||
targetMet = true
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !targetMet {
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -140,16 +110,25 @@ func (hook *BPMHook) Execute(packageChanges map[string]string, verbose bool, roo
|
|||||||
cmd := exec.Command(splitCommand[0], splitCommand[1:]...)
|
cmd := exec.Command(splitCommand[0], splitCommand[1:]...)
|
||||||
// Setup subprocess environment
|
// Setup subprocess environment
|
||||||
cmd.Dir = "/"
|
cmd.Dir = "/"
|
||||||
|
// Pass targets
|
||||||
|
if hook.PassTargets {
|
||||||
|
buffer := bytes.Buffer{}
|
||||||
|
buffer.WriteString(strings.Join(targetsMet, "\n") + "\n")
|
||||||
|
|
||||||
|
cmd.Stdin = &buffer
|
||||||
|
}
|
||||||
// Run hook in chroot if using the -R flag
|
// Run hook in chroot if using the -R flag
|
||||||
if rootDir != "/" {
|
if rootDir != "/" {
|
||||||
cmd.SysProcAttr = &syscall.SysProcAttr{Chroot: rootDir}
|
cmd.SysProcAttr = &syscall.SysProcAttr{Chroot: rootDir}
|
||||||
}
|
}
|
||||||
|
|
||||||
if verbose {
|
if !verbose {
|
||||||
fmt.Printf("Running hook (%s) with run command: %s\n", hook.SourcePath, strings.Join(splitCommand, " "))
|
fmt.Printf("Running hook (%s)\n", filepath.Base(hook.SourcePath))
|
||||||
|
} else {
|
||||||
|
fmt.Printf("Running hook (%s) with run command: %s\n", filepath.Base(hook.SourcePath), strings.Join(splitCommand, " "))
|
||||||
}
|
}
|
||||||
|
|
||||||
err = cmd.Run()
|
err := cmd.Run()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ func InitializeLocalPackageInformation(rootDir string) (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Read package info
|
// Read package info
|
||||||
infoData, err := os.ReadFile(path.Join(installedDir, item.Name(), "info"))
|
infoData, err := os.ReadFile(path.Join(installedDir, item.Name(), "info.yml"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -220,7 +220,7 @@ func getPackageFiles(pkg, rootDir string) []*PackageFileEntry {
|
|||||||
var pkgFiles []*PackageFileEntry
|
var pkgFiles []*PackageFileEntry
|
||||||
installedDir := path.Join(rootDir, "var/lib/bpm/installed/")
|
installedDir := path.Join(rootDir, "var/lib/bpm/installed/")
|
||||||
pkgDir := path.Join(installedDir, pkg)
|
pkgDir := path.Join(installedDir, pkg)
|
||||||
files := path.Join(pkgDir, "files")
|
files := path.Join(pkgDir, "files.txt")
|
||||||
if _, err := os.Stat(installedDir); os.IsNotExist(err) {
|
if _, err := os.Stat(installedDir); os.IsNotExist(err) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -280,7 +280,7 @@ func getPackageLocalInfo(pkg, rootDir string) PackageLocalInfo {
|
|||||||
|
|
||||||
installedDir := path.Join(rootDir, "var/lib/bpm/installed/")
|
installedDir := path.Join(rootDir, "var/lib/bpm/installed/")
|
||||||
pkgDir := path.Join(installedDir, pkg)
|
pkgDir := path.Join(installedDir, pkg)
|
||||||
localInfoFile := path.Join(path.Join(pkgDir, "local"))
|
localInfoFile := path.Join(path.Join(pkgDir, "local.yml"))
|
||||||
|
|
||||||
if _, err := os.Stat(localInfoFile); os.IsNotExist(err) {
|
if _, err := os.Stat(localInfoFile); os.IsNotExist(err) {
|
||||||
return localInfo
|
return localInfo
|
||||||
@@ -304,7 +304,7 @@ func SetPackageLocalInfo(pkg string, localInfo PackageLocalInfo, rootDir string)
|
|||||||
installedDir := path.Join(rootDir, "var/lib/bpm/installed/")
|
installedDir := path.Join(rootDir, "var/lib/bpm/installed/")
|
||||||
pkgDir := path.Join(installedDir, pkg)
|
pkgDir := path.Join(installedDir, pkg)
|
||||||
|
|
||||||
localFile, err := os.OpenFile(path.Join(pkgDir, "local"), os.O_WRONLY|os.O_CREATE, 0644)
|
localFile, err := os.OpenFile(path.Join(pkgDir, "local.yml"), os.O_WRONLY|os.O_CREATE, 0644)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -332,10 +332,35 @@ func UpgradePersistentData(rootDir string) error {
|
|||||||
for _, entry := range dirEntries {
|
for _, entry := range dirEntries {
|
||||||
pkgDir := path.Join(persistentDataDir, "installed", entry.Name())
|
pkgDir := path.Join(persistentDataDir, "installed", entry.Name())
|
||||||
|
|
||||||
// Generate default local package information file
|
// Rename 'info' file to 'info.yml'
|
||||||
if _, err := os.Stat(path.Join(pkgDir, "local")); err != nil && !os.IsNotExist(err) {
|
if _, err := os.Stat(path.Join(pkgDir, "info")); err == nil {
|
||||||
|
fmt.Printf("Moving 'info' to 'info.yml' for package (%s)\n", entry.Name())
|
||||||
|
err := os.Rename(path.Join(pkgDir, "info"), path.Join(pkgDir, "info.yml"))
|
||||||
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
} else if os.IsNotExist(err) {
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rename 'files' file to 'files.txt'
|
||||||
|
if _, err := os.Stat(path.Join(pkgDir, "files")); err == nil {
|
||||||
|
fmt.Printf("Moving 'files' to 'files.txt' for package (%s)\n", entry.Name())
|
||||||
|
err := os.Rename(path.Join(pkgDir, "files"), path.Join(pkgDir, "files.txt"))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rename 'local' file to 'local.yml'
|
||||||
|
if _, err := os.Stat(path.Join(pkgDir, "local")); err == nil {
|
||||||
|
fmt.Printf("Moving 'local' to 'local.yml' for package (%s)\n", entry.Name())
|
||||||
|
err := os.Rename(path.Join(pkgDir, "local"), path.Join(pkgDir, "local.yml"))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate default local package information file
|
||||||
|
if _, err := os.Stat(path.Join(pkgDir, "local.yml")); os.IsNotExist(err) {
|
||||||
fmt.Printf("Generating local package information for package (%s)\n", entry.Name())
|
fmt.Printf("Generating local package information for package (%s)\n", entry.Name())
|
||||||
|
|
||||||
out, err := yaml.Marshal(PackageLocalInfo{
|
out, err := yaml.Marshal(PackageLocalInfo{
|
||||||
@@ -347,10 +372,12 @@ func UpgradePersistentData(rootDir string) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = os.WriteFile(path.Join(pkgDir, "local"), out, 0644)
|
err = os.WriteFile(path.Join(pkgDir, "local.yml"), out, 0644)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
} else if err != nil {
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Move installation reason to local package information file
|
// Move installation reason to local package information file
|
||||||
@@ -359,7 +386,7 @@ func UpgradePersistentData(rootDir string) error {
|
|||||||
} else if err == nil {
|
} else if err == nil {
|
||||||
fmt.Printf("Moving installation reason to local package information for package (%s)\n", entry.Name())
|
fmt.Printf("Moving installation reason to local package information for package (%s)\n", entry.Name())
|
||||||
|
|
||||||
data, err := os.ReadFile(path.Join(pkgDir, "local"))
|
data, err := os.ReadFile(path.Join(pkgDir, "local.yml"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -377,7 +404,7 @@ func UpgradePersistentData(rootDir string) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = os.WriteFile(path.Join(pkgDir, "local"), out, 0644)
|
err = os.WriteFile(path.Join(pkgDir, "local.yml"), out, 0644)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
+214
-124
@@ -4,6 +4,7 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
|
"maps"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
"slices"
|
"slices"
|
||||||
@@ -13,8 +14,8 @@ import (
|
|||||||
|
|
||||||
type BPMOperation struct {
|
type BPMOperation struct {
|
||||||
Actions []OperationAction
|
Actions []OperationAction
|
||||||
UnresolvedDepends []string
|
UnresolvedDepends map[string]string
|
||||||
Changes map[string]string
|
ModifiedFiles map[string]string
|
||||||
CompilationJobs int
|
CompilationJobs int
|
||||||
RunChecks bool
|
RunChecks bool
|
||||||
RootDir string
|
RootDir string
|
||||||
@@ -23,72 +24,6 @@ type BPMOperation struct {
|
|||||||
hasFetchedPackages bool
|
hasFetchedPackages bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (operation *BPMOperation) ActionsContainPackage(pkg string) bool {
|
|
||||||
for _, action := range operation.Actions {
|
|
||||||
if action.GetActionType() == "install" {
|
|
||||||
if action.(*InstallPackageAction).BpmPackage.PkgInfo.Name == pkg {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
} else if action.GetActionType() == "fetch" {
|
|
||||||
if action.(*FetchPackageAction).DatabaseEntry.Info.Name == pkg {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
} else if action.GetActionType() == "remove" {
|
|
||||||
if action.(*RemovePackageAction).BpmPackage.PkgInfo.Name == pkg {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (operation *BPMOperation) AppendAction(action OperationAction) {
|
|
||||||
operation.InsertActionAt(len(operation.Actions), action)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (operation *BPMOperation) InsertActionAt(index int, action OperationAction) {
|
|
||||||
if len(operation.Actions) == index { // nil or empty slice or after last element
|
|
||||||
operation.Actions = append(operation.Actions, action)
|
|
||||||
} else {
|
|
||||||
operation.Actions = append(operation.Actions[:index+1], operation.Actions[index:]...) // index < len(a)
|
|
||||||
operation.Actions[index] = action
|
|
||||||
}
|
|
||||||
|
|
||||||
if action.GetActionType() == "install" {
|
|
||||||
pkgInfo := action.(*InstallPackageAction).BpmPackage.PkgInfo
|
|
||||||
if !IsPackageInstalled(pkgInfo.Name, operation.RootDir) {
|
|
||||||
operation.Changes[pkgInfo.Name] = "install"
|
|
||||||
} else {
|
|
||||||
operation.Changes[pkgInfo.Name] = "upgrade"
|
|
||||||
}
|
|
||||||
} else if action.GetActionType() == "fetch" {
|
|
||||||
pkgInfo := action.(*FetchPackageAction).DatabaseEntry.Info
|
|
||||||
if !IsPackageInstalled(pkgInfo.Name, operation.RootDir) {
|
|
||||||
operation.Changes[pkgInfo.Name] = "install"
|
|
||||||
} else {
|
|
||||||
operation.Changes[pkgInfo.Name] = "upgrade"
|
|
||||||
}
|
|
||||||
} else if action.GetActionType() == "remove" {
|
|
||||||
operation.Changes[action.(*RemovePackageAction).BpmPackage.PkgInfo.Name] = "remove"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (operation *BPMOperation) RemoveAction(pkg, actionType string) {
|
|
||||||
operation.Actions = slices.DeleteFunc(operation.Actions, func(a OperationAction) bool {
|
|
||||||
if a.GetActionType() != actionType {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
if a.GetActionType() == "install" {
|
|
||||||
return a.(*InstallPackageAction).BpmPackage.PkgInfo.Name == pkg
|
|
||||||
} else if a.GetActionType() == "fetch" {
|
|
||||||
return a.(*FetchPackageAction).DatabaseEntry.Info.Name == pkg
|
|
||||||
} else if a.GetActionType() == "remove" {
|
|
||||||
return a.(*RemovePackageAction).BpmPackage.PkgInfo.Name == pkg
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (operation *BPMOperation) GetTotalDownloadSize() int64 {
|
func (operation *BPMOperation) GetTotalDownloadSize() int64 {
|
||||||
var ret int64 = 0
|
var ret int64 = 0
|
||||||
for _, action := range operation.Actions {
|
for _, action := range operation.Actions {
|
||||||
@@ -154,31 +89,35 @@ func (operation *BPMOperation) ResolveDependencies(installRuntimeDepends bool) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Discover all dependencies
|
// Discover all dependencies
|
||||||
pos := 0
|
newActions := make([]OperationAction, 0)
|
||||||
for _, value := range slices.Clone(operation.Actions) {
|
for _, value := range operation.Actions {
|
||||||
var pkgInfo *PackageInfo
|
var pkgInfo *PackageInfo
|
||||||
|
var flags map[string]string
|
||||||
if value.GetActionType() == "install" {
|
if value.GetActionType() == "install" {
|
||||||
action := value.(*InstallPackageAction)
|
action := value.(*InstallPackageAction)
|
||||||
pkgInfo = action.BpmPackage.PkgInfo
|
pkgInfo = action.BpmPackage.PkgInfo
|
||||||
|
flags = action.Flags
|
||||||
} else if value.GetActionType() == "fetch" {
|
} else if value.GetActionType() == "fetch" {
|
||||||
action := value.(*FetchPackageAction)
|
action := value.(*FetchPackageAction)
|
||||||
pkgInfo = action.DatabaseEntry.Info
|
pkgInfo = action.DatabaseEntry.Info
|
||||||
|
flags = action.Flags
|
||||||
} else {
|
} else {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
resolved, unresolved := ResolveDependencies(pkgInfo, resolvedVirtualPackages, installRuntimeDepends, operation.RootDir)
|
resolved, unresolved := ResolveDependencies(pkgInfo, flags, resolvedVirtualPackages, installRuntimeDepends, operation.RootDir)
|
||||||
|
|
||||||
// Append unresolved dependencies
|
// Copy unresolved dependencies
|
||||||
operation.UnresolvedDepends = append(operation.UnresolvedDepends, unresolved...)
|
maps.Copy(operation.UnresolvedDepends, unresolved)
|
||||||
operation.UnresolvedDepends = removeDuplicates(operation.UnresolvedDepends)
|
|
||||||
|
|
||||||
for _, resolvedPkg := range resolved {
|
for _, resolvedPkg := range resolved {
|
||||||
if !operation.ActionsContainPackage(resolvedPkg.DatabaseEntry.Info.Name) && resolvedPkg.DatabaseEntry.Info.Name != pkgInfo.Name {
|
if ActionSliceIndex(newActions, resolvedPkg.DatabaseEntry.Info.Name) == -1 { // Dependency not in actions slice
|
||||||
operation.InsertActionAt(pos, &FetchPackageAction{
|
var action OperationAction = &FetchPackageAction{
|
||||||
InstallationReason: resolvedPkg.InstallationReason,
|
InstallationReason: resolvedPkg.InstallationReason,
|
||||||
|
Flags: resolvedPkg.Flags,
|
||||||
DatabaseEntry: resolvedPkg.DatabaseEntry,
|
DatabaseEntry: resolvedPkg.DatabaseEntry,
|
||||||
})
|
}
|
||||||
|
newActions = append(newActions, action)
|
||||||
|
|
||||||
for _, vpkg := range resolvedPkg.DatabaseEntry.Info.Provides {
|
for _, vpkg := range resolvedPkg.DatabaseEntry.Info.Provides {
|
||||||
if _, ok := resolvedVirtualPackages[vpkg]; !ok {
|
if _, ok := resolvedVirtualPackages[vpkg]; !ok {
|
||||||
@@ -186,36 +125,19 @@ func (operation *BPMOperation) ResolveDependencies(installRuntimeDepends bool) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pos++
|
// Check if can move original action
|
||||||
|
if i := ActionSliceIndex(operation.Actions, resolvedPkg.DatabaseEntry.Info.Name); i != -1 {
|
||||||
|
newActions[len(newActions)-1] = operation.Actions[i]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pos++
|
if ActionSliceIndex(newActions, pkgInfo.Name) == -1 {
|
||||||
|
newActions = append(newActions, value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (operation *BPMOperation) RemoveNeededPackages() error {
|
operation.Actions = newActions
|
||||||
removeActions := make(map[string]*RemovePackageAction)
|
|
||||||
for _, action := range slices.Clone(operation.Actions) {
|
|
||||||
if action.GetActionType() == "remove" {
|
|
||||||
removeActions[action.(*RemovePackageAction).BpmPackage.PkgInfo.Name] = action.(*RemovePackageAction)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for pkg, action := range removeActions {
|
|
||||||
dependants := action.BpmPackage.PkgInfo.GetPackageDependants(operation.RootDir)
|
|
||||||
dependants = slices.DeleteFunc(dependants, func(d string) bool {
|
|
||||||
if _, ok := removeActions[d]; ok {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
})
|
|
||||||
if len(dependants) != 0 {
|
|
||||||
operation.RemoveAction(pkg, action.GetActionType())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (operation *BPMOperation) Cleanup(cleanupMakeDepends bool) error {
|
func (operation *BPMOperation) Cleanup(cleanupMakeDepends bool) error {
|
||||||
@@ -274,12 +196,18 @@ func (operation *BPMOperation) Cleanup(cleanupMakeDepends bool) error {
|
|||||||
|
|
||||||
// Loop through all dependencies
|
// Loop through all dependencies
|
||||||
for _, depend := range depends {
|
for _, depend := range depends {
|
||||||
|
// Deconstruct package string
|
||||||
|
d, err := DeconstructPackageString(depend)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("could not deconstruct package string: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
// Resolve dependency
|
// Resolve dependency
|
||||||
var dependPkgInfo *PackageInfo
|
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]
|
dependPkgInfo = providers[0]
|
||||||
} else {
|
} else {
|
||||||
dependPkgInfo = GetPackageInfo(depend, operation.RootDir)
|
dependPkgInfo = GetPackageInfo(d.PkgName, operation.RootDir)
|
||||||
}
|
}
|
||||||
if dependPkgInfo == nil {
|
if dependPkgInfo == nil {
|
||||||
continue
|
continue
|
||||||
@@ -304,7 +232,7 @@ func (operation *BPMOperation) Cleanup(cleanupMakeDepends bool) error {
|
|||||||
if !slices.Contains(visited, pkg) {
|
if !slices.Contains(visited, pkg) {
|
||||||
bpmpkg := GetPackage(pkg, operation.RootDir)
|
bpmpkg := GetPackage(pkg, operation.RootDir)
|
||||||
if bpmpkg == nil {
|
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})
|
operation.Actions = append(operation.Actions, &RemovePackageAction{BpmPackage: bpmpkg})
|
||||||
}
|
}
|
||||||
@@ -328,10 +256,11 @@ func (operation *BPMOperation) ReplaceObsoletePackages() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, r := range pkgInfo.Replaces {
|
for _, r := range pkgInfo.Replaces {
|
||||||
if bpmpkg := GetPackage(r, operation.RootDir); bpmpkg != nil && !operation.ActionsContainPackage(bpmpkg.PkgInfo.Name) {
|
if bpmpkg := GetPackage(r, operation.RootDir); bpmpkg != nil && ActionSliceIndex(operation.Actions, bpmpkg.PkgInfo.Name) == -1 {
|
||||||
operation.InsertActionAt(0, &RemovePackageAction{
|
var action OperationAction = &RemovePackageAction{
|
||||||
BpmPackage: bpmpkg,
|
BpmPackage: bpmpkg,
|
||||||
})
|
}
|
||||||
|
operation.Actions = slices.Insert(operation.Actions, 0, action)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -436,15 +365,30 @@ func (operation *BPMOperation) ShowOperationSummary() {
|
|||||||
|
|
||||||
for _, value := range operation.Actions {
|
for _, value := range operation.Actions {
|
||||||
var pkgInfo *PackageInfo
|
var pkgInfo *PackageInfo
|
||||||
|
var flagsStr string
|
||||||
var installationReason = InstallationReasonUnknown
|
var installationReason = InstallationReasonUnknown
|
||||||
if value.GetActionType() == "install" {
|
if value.GetActionType() == "install" {
|
||||||
installationReason = value.(*InstallPackageAction).InstallationReason
|
installationReason = value.(*InstallPackageAction).InstallationReason
|
||||||
pkgInfo = value.(*InstallPackageAction).BpmPackage.PkgInfo
|
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 != "" {
|
if value.(*InstallPackageAction).SplitPackageToInstall != "" {
|
||||||
pkgInfo = pkgInfo.GetSplitPackageInfo(value.(*InstallPackageAction).SplitPackageToInstall)
|
pkgInfo = pkgInfo.GetSplitPackageInfo(value.(*InstallPackageAction).SplitPackageToInstall)
|
||||||
}
|
}
|
||||||
} else if value.GetActionType() == "fetch" {
|
} else if value.GetActionType() == "fetch" {
|
||||||
installationReason = value.(*FetchPackageAction).InstallationReason
|
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
|
pkgInfo = value.(*FetchPackageAction).DatabaseEntry.Info
|
||||||
} else {
|
} else {
|
||||||
pkgInfo = value.(*RemovePackageAction).BpmPackage.PkgInfo
|
pkgInfo = value.(*RemovePackageAction).BpmPackage.PkgInfo
|
||||||
@@ -466,15 +410,15 @@ func (operation *BPMOperation) ShowOperationSummary() {
|
|||||||
|
|
||||||
installedInfo := GetPackageInfo(pkgInfo.Name, operation.RootDir)
|
installedInfo := GetPackageInfo(pkgInfo.Name, operation.RootDir)
|
||||||
if installedInfo == nil {
|
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 {
|
} else {
|
||||||
comparison := CompareVersions(pkgInfo.GetFullVersion(), installedInfo.GetFullVersion())
|
comparison := CompareVersions(pkgInfo.GetFullVersion(), installedInfo.GetFullVersion())
|
||||||
if comparison < 0 {
|
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 {
|
} 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 {
|
} 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")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -527,7 +471,7 @@ func (operation *BPMOperation) GetOptionalDependencies() (optionalDepends map[st
|
|||||||
optionalDepends = make(map[string][]string)
|
optionalDepends = make(map[string][]string)
|
||||||
|
|
||||||
// Find all optional dependencies
|
// Find all optional dependencies
|
||||||
for _, value := range slices.Clone(operation.Actions) {
|
for _, value := range operation.Actions {
|
||||||
var pkgInfo *PackageInfo
|
var pkgInfo *PackageInfo
|
||||||
if value.GetActionType() == "install" {
|
if value.GetActionType() == "install" {
|
||||||
action := value.(*InstallPackageAction)
|
action := value.(*InstallPackageAction)
|
||||||
@@ -540,24 +484,58 @@ func (operation *BPMOperation) GetOptionalDependencies() (optionalDepends map[st
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, depend := range pkgInfo.OptionalDepends {
|
for _, depend := range pkgInfo.OptionalDepends {
|
||||||
dependSplit := strings.SplitN(depend, ":", 2)
|
// Deconstruct package string
|
||||||
|
d, err := DeconstructPackageString(depend)
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
// Skip if dependency is already installed
|
// Skip if dependency is already installed
|
||||||
if IsPackageInstalled(dependSplit[0], operation.RootDir) {
|
if IsPackageInstalled(d.PkgName, operation.RootDir) || len(GetVirtualPackageInfo(d.PkgName, operation.RootDir)) > 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Skip if dependency is going to be installed
|
||||||
|
if slices.IndexFunc(operation.Actions, func(action OperationAction) bool {
|
||||||
|
var pkgInfo *PackageInfo
|
||||||
|
if action.GetActionType() == "install" {
|
||||||
|
action := action.(*InstallPackageAction)
|
||||||
|
pkgInfo = action.BpmPackage.PkgInfo
|
||||||
|
} else if action.GetActionType() == "fetch" {
|
||||||
|
action := action.(*FetchPackageAction)
|
||||||
|
pkgInfo = action.DatabaseEntry.Info
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if pkgInfo.Name == d.PkgName {
|
||||||
|
return true
|
||||||
|
} else if slices.Contains(pkgInfo.Provides, d.PkgName) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}) != -1 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
// Skip if not a new dependency of the package
|
// 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 {
|
if installedPkg := GetPackage(pkgInfo.Name, operation.RootDir); installedPkg != nil && slices.ContainsFunc(installedPkg.PkgInfo.OptionalDepends, func(n string) bool {
|
||||||
return strings.SplitN(n, ":", 2)[0] == dependSplit[0]
|
// Deconstruct package string
|
||||||
|
d2, err := DeconstructPackageString(depend)
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return d2.PkgName == d.PkgName
|
||||||
}) {
|
}) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(dependSplit) == 2 {
|
if d.Description != "" {
|
||||||
optionalDepends[pkgInfo.Name] = append(optionalDepends[pkgInfo.Name], fmt.Sprintf("%s (%s)", dependSplit[0], dependSplit[1]))
|
optionalDepends[pkgInfo.Name] = append(optionalDepends[pkgInfo.Name], fmt.Sprintf("%s (%s)", d.PkgName, d.Description))
|
||||||
} else {
|
} else {
|
||||||
optionalDepends[pkgInfo.Name] = append(optionalDepends[pkgInfo.Name], dependSplit[0])
|
optionalDepends[pkgInfo.Name] = append(optionalDepends[pkgInfo.Name], d.PkgName)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -565,7 +543,7 @@ func (operation *BPMOperation) GetOptionalDependencies() (optionalDepends map[st
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (operation *BPMOperation) RunHooks(verbose bool) error {
|
func (operation *BPMOperation) RunPreHooks(verbose bool) error {
|
||||||
// Return if hooks directory does not exist
|
// Return if hooks directory does not exist
|
||||||
if stat, err := os.Stat(path.Join(operation.RootDir, "var/lib/bpm/hooks")); err != nil || !stat.IsDir() {
|
if stat, err := os.Stat(path.Join(operation.RootDir, "var/lib/bpm/hooks")); err != nil || !stat.IsDir() {
|
||||||
return nil
|
return nil
|
||||||
@@ -585,7 +563,46 @@ func (operation *BPMOperation) RunHooks(verbose bool) error {
|
|||||||
log.Printf("Error while reading hook (%s): %s", entry.Name(), err)
|
log.Printf("Error while reading hook (%s): %s", entry.Name(), err)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = hook.Execute(operation.Changes, verbose, operation.RootDir)
|
if !hook.TriggerPreOperation {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
err = hook.Execute(operation.ModifiedFiles, false, verbose, operation.RootDir)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Warning: could not execute hook (%s): %s\n", entry.Name(), err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (operation *BPMOperation) RunPostHooks(verbose bool) error {
|
||||||
|
// Return if hooks directory does not exist
|
||||||
|
if stat, err := os.Stat(path.Join(operation.RootDir, "var/lib/bpm/hooks")); err != nil || !stat.IsDir() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get directory entries in hooks directory
|
||||||
|
dirEntries, err := os.ReadDir(path.Join(operation.RootDir, "var/lib/bpm/hooks"))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find all hooks, validate and execute them
|
||||||
|
for _, entry := range dirEntries {
|
||||||
|
if entry.Type().IsRegular() && strings.HasSuffix(entry.Name(), ".bpmhook") {
|
||||||
|
hook, err := createHook(path.Join(operation.RootDir, "var/lib/bpm/hooks", entry.Name()))
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Error while reading hook (%s): %s", entry.Name(), err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if hook.TriggerPreOperation {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
err = hook.Execute(operation.ModifiedFiles, false, verbose, operation.RootDir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Warning: could not execute hook (%s): %s\n", entry.Name(), err)
|
log.Printf("Warning: could not execute hook (%s): %s\n", entry.Name(), err)
|
||||||
continue
|
continue
|
||||||
@@ -655,6 +672,7 @@ func (operation *BPMOperation) FetchPackages() (err error) {
|
|||||||
operation.Actions[i] = &InstallPackageAction{
|
operation.Actions[i] = &InstallPackageAction{
|
||||||
File: fetchedPackages[entry.Filepath],
|
File: fetchedPackages[entry.Filepath],
|
||||||
InstallationReason: action.(*FetchPackageAction).InstallationReason,
|
InstallationReason: action.(*FetchPackageAction).InstallationReason,
|
||||||
|
Flags: action.(*FetchPackageAction).Flags,
|
||||||
BpmPackage: bpmpkg,
|
BpmPackage: bpmpkg,
|
||||||
SplitPackageToInstall: entry.Info.Name,
|
SplitPackageToInstall: entry.Info.Name,
|
||||||
}
|
}
|
||||||
@@ -662,6 +680,7 @@ func (operation *BPMOperation) FetchPackages() (err error) {
|
|||||||
operation.Actions[i] = &InstallPackageAction{
|
operation.Actions[i] = &InstallPackageAction{
|
||||||
File: fetchedPackages[entry.Filepath],
|
File: fetchedPackages[entry.Filepath],
|
||||||
InstallationReason: action.(*FetchPackageAction).InstallationReason,
|
InstallationReason: action.(*FetchPackageAction).InstallationReason,
|
||||||
|
Flags: action.(*FetchPackageAction).Flags,
|
||||||
BpmPackage: bpmpkg,
|
BpmPackage: bpmpkg,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -669,9 +688,40 @@ func (operation *BPMOperation) FetchPackages() (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
operation.hasFetchedPackages = true
|
operation.hasFetchedPackages = true
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (operation *BPMOperation) GetModifiedFiles() {
|
||||||
|
// Get modified files
|
||||||
|
for _, action := range operation.Actions {
|
||||||
|
if action.GetActionType() == "install" {
|
||||||
|
installAction := action.(*InstallPackageAction)
|
||||||
|
isUpgrade := IsPackageInstalled(installAction.BpmPackage.PkgInfo.Name, operation.RootDir)
|
||||||
|
|
||||||
|
if isUpgrade {
|
||||||
|
for _, pkgFile := range installAction.BpmPackage.PkgFiles {
|
||||||
|
operation.ModifiedFiles[pkgFile.Path] = "upgrade"
|
||||||
|
}
|
||||||
|
for _, pkgFile := range GetPackage(installAction.BpmPackage.PkgInfo.Name, operation.RootDir).PkgFiles {
|
||||||
|
operation.ModifiedFiles[pkgFile.Path] = "upgrade"
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for _, pkgFile := range installAction.BpmPackage.PkgFiles {
|
||||||
|
operation.ModifiedFiles[pkgFile.Path] = "install"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if action.GetActionType() == "remove" {
|
||||||
|
removeAction := action.(*RemovePackageAction)
|
||||||
|
|
||||||
|
for _, pkgFile := range removeAction.BpmPackage.PkgFiles {
|
||||||
|
operation.ModifiedFiles[pkgFile.Path] = "remove"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (operation *BPMOperation) Execute(verbose, force bool) (err error) {
|
func (operation *BPMOperation) Execute(verbose, force bool) (err error) {
|
||||||
// Fetch packages
|
// Fetch packages
|
||||||
if !operation.hasFetchedPackages {
|
if !operation.hasFetchedPackages {
|
||||||
@@ -711,6 +761,7 @@ func (operation *BPMOperation) Execute(verbose, force bool) (err error) {
|
|||||||
} else if action.GetActionType() == "install" {
|
} else if action.GetActionType() == "install" {
|
||||||
value := action.(*InstallPackageAction)
|
value := action.(*InstallPackageAction)
|
||||||
fileToInstall := value.File
|
fileToInstall := value.File
|
||||||
|
compilationFlags := value.Flags
|
||||||
bpmpkg := value.BpmPackage
|
bpmpkg := value.BpmPackage
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
@@ -735,7 +786,7 @@ func (operation *BPMOperation) Execute(verbose, force bool) (err error) {
|
|||||||
|
|
||||||
// Compile source package if not compiled already
|
// Compile source package if not compiled already
|
||||||
if _, ok := operation.compiledPackages[pkgNameToInstall]; !ok {
|
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 {
|
if err != nil {
|
||||||
return fmt.Errorf("could not compile source package (%s): %s\n", value.File, err)
|
return fmt.Errorf("could not compile source package (%s): %s\n", value.File, err)
|
||||||
}
|
}
|
||||||
@@ -755,16 +806,15 @@ func (operation *BPMOperation) Execute(verbose, force bool) (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if value.InstallationReason != InstallationReasonManual {
|
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 {
|
} else {
|
||||||
err = installPackage(fileToInstall, value.InstallationReason, operation.RootDir, verbose, force)
|
err = installPackage(fileToInstall, value.InstallationReason, value.Flags, operation.RootDir, verbose, force)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("could not install package (%s): %s\n", bpmpkg.PkgInfo.Name, err)
|
return fmt.Errorf("could not install package (%s): %s\n", bpmpkg.PkgInfo.Name, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fmt.Println("Operation complete!")
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -776,6 +826,7 @@ type OperationAction interface {
|
|||||||
type InstallPackageAction struct {
|
type InstallPackageAction struct {
|
||||||
File string
|
File string
|
||||||
InstallationReason InstallationReason
|
InstallationReason InstallationReason
|
||||||
|
Flags map[string]string
|
||||||
SplitPackageToInstall string
|
SplitPackageToInstall string
|
||||||
BpmPackage *BPMPackage
|
BpmPackage *BPMPackage
|
||||||
}
|
}
|
||||||
@@ -786,6 +837,7 @@ func (action *InstallPackageAction) GetActionType() string {
|
|||||||
|
|
||||||
type FetchPackageAction struct {
|
type FetchPackageAction struct {
|
||||||
InstallationReason InstallationReason
|
InstallationReason InstallationReason
|
||||||
|
Flags map[string]string
|
||||||
DatabaseEntry *BPMDatabaseEntry
|
DatabaseEntry *BPMDatabaseEntry
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -800,3 +852,41 @@ type RemovePackageAction struct {
|
|||||||
func (action *RemovePackageAction) GetActionType() string {
|
func (action *RemovePackageAction) GetActionType() string {
|
||||||
return "remove"
|
return "remove"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ActionSliceIndex(actions []OperationAction, pkg string) int {
|
||||||
|
for i, action := range actions {
|
||||||
|
if action.GetActionType() == "install" {
|
||||||
|
if action.(*InstallPackageAction).BpmPackage.PkgInfo.Name == pkg {
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
} else if action.GetActionType() == "fetch" {
|
||||||
|
if action.(*FetchPackageAction).DatabaseEntry.Info.Name == pkg {
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
} else if action.GetActionType() == "remove" {
|
||||||
|
if action.(*RemovePackageAction).BpmPackage.PkgInfo.Name == pkg {
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
|
||||||
|
func ActionSliceRemove(actions []OperationAction, pkg, actionType string) []OperationAction {
|
||||||
|
actions = slices.DeleteFunc(actions, func(a OperationAction) bool {
|
||||||
|
if a.GetActionType() != actionType {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if a.GetActionType() == "install" {
|
||||||
|
return a.(*InstallPackageAction).BpmPackage.PkgInfo.Name == pkg
|
||||||
|
} else if a.GetActionType() == "fetch" {
|
||||||
|
return a.(*FetchPackageAction).DatabaseEntry.Info.Name == pkg
|
||||||
|
} else if a.GetActionType() == "remove" {
|
||||||
|
return a.(*RemovePackageAction).BpmPackage.PkgInfo.Name == pkg
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
})
|
||||||
|
|
||||||
|
return actions
|
||||||
|
}
|
||||||
|
|||||||
+195
-41
@@ -10,6 +10,7 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"path"
|
"path"
|
||||||
|
"path/filepath"
|
||||||
"regexp"
|
"regexp"
|
||||||
"slices"
|
"slices"
|
||||||
"sort"
|
"sort"
|
||||||
@@ -48,10 +49,27 @@ type PackageInfo struct {
|
|||||||
Replaces []string `yaml:"replaces,omitempty"`
|
Replaces []string `yaml:"replaces,omitempty"`
|
||||||
Provides []string `yaml:"provides,omitempty"`
|
Provides []string `yaml:"provides,omitempty"`
|
||||||
Options []string `yaml:"options,omitempty"`
|
Options []string `yaml:"options,omitempty"`
|
||||||
|
Flags []PackageFlag `yaml:"flags,omitempty"`
|
||||||
Downloads []PackageDownload `yaml:"downloads,omitempty"`
|
Downloads []PackageDownload `yaml:"downloads,omitempty"`
|
||||||
SplitPackages []*PackageInfo `yaml:"split_packages,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 {
|
type PackageDownload struct {
|
||||||
Url string `yaml:"url"`
|
Url string `yaml:"url"`
|
||||||
Type string `yaml:"type,omitempty"`
|
Type string `yaml:"type,omitempty"`
|
||||||
@@ -79,6 +97,7 @@ type PackageFileEntry struct {
|
|||||||
|
|
||||||
type PackageLocalInfo struct {
|
type PackageLocalInfo struct {
|
||||||
InstallationReason string `yaml:"installation_reason"`
|
InstallationReason string `yaml:"installation_reason"`
|
||||||
|
Flags map[string]string `yaml:"flags"`
|
||||||
InstalledOn int64 `yaml:"installed_on"`
|
InstalledOn int64 `yaml:"installed_on"`
|
||||||
LastUpdatedOn int64 `yaml:"last_updated_on"`
|
LastUpdatedOn int64 `yaml:"last_updated_on"`
|
||||||
}
|
}
|
||||||
@@ -162,7 +181,7 @@ func GetPackageInfoRaw(filename string) (string, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
if header.Name == "pkg.info" {
|
if header.Name == "info.yml" {
|
||||||
bs, _ := io.ReadAll(tr)
|
bs, _ := io.ReadAll(tr)
|
||||||
err := file.Close()
|
err := file.Close()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -171,7 +190,7 @@ func GetPackageInfoRaw(filename string) (string, error) {
|
|||||||
return string(bs), nil
|
return string(bs), nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return "", errors.New("pkg.info not found in archive")
|
return "", errors.New("info.yml not found in archive")
|
||||||
}
|
}
|
||||||
|
|
||||||
func ReadPackage(filename string) (*BPMPackage, error) {
|
func ReadPackage(filename string) (*BPMPackage, error) {
|
||||||
@@ -197,13 +216,13 @@ func ReadPackage(filename string) (*BPMPackage, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if header.Name == "pkg.info" {
|
if header.Name == "info.yml" {
|
||||||
bs, _ := io.ReadAll(tr)
|
bs, _ := io.ReadAll(tr)
|
||||||
pkgInfo, err = ReadPackageInfo(string(bs))
|
pkgInfo, err = ReadPackageInfo(string(bs))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
} else if header.Name == "pkg.files" {
|
} else if header.Name == "files.txt" {
|
||||||
bs, _ := io.ReadAll(tr)
|
bs, _ := io.ReadAll(tr)
|
||||||
for _, line := range strings.Split(string(bs), "\n") {
|
for _, line := range strings.Split(string(bs), "\n") {
|
||||||
if strings.TrimSpace(line) == "" {
|
if strings.TrimSpace(line) == "" {
|
||||||
@@ -211,7 +230,7 @@ func ReadPackage(filename string) (*BPMPackage, error) {
|
|||||||
}
|
}
|
||||||
stringEntry := strings.Split(strings.TrimSpace(line), " ")
|
stringEntry := strings.Split(strings.TrimSpace(line), " ")
|
||||||
if len(stringEntry) < 5 {
|
if len(stringEntry) < 5 {
|
||||||
return nil, errors.New("pkg.files is not formatted correctly")
|
return nil, errors.New("files.txt is not formatted correctly")
|
||||||
}
|
}
|
||||||
octalPerms, err := strconv.ParseUint(stringEntry[len(stringEntry)-4], 8, 32)
|
octalPerms, err := strconv.ParseUint(stringEntry[len(stringEntry)-4], 8, 32)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -241,7 +260,7 @@ func ReadPackage(filename string) (*BPMPackage, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if pkgInfo == nil {
|
if pkgInfo == nil {
|
||||||
return nil, errors.New("pkg.info not found in archive")
|
return nil, errors.New("info.yml not found in archive")
|
||||||
}
|
}
|
||||||
return &BPMPackage{
|
return &BPMPackage{
|
||||||
PkgInfo: pkgInfo,
|
PkgInfo: pkgInfo,
|
||||||
@@ -594,6 +613,70 @@ func (pkgInfo *PackageInfo) CreateReadableInfo(rootDir string) string {
|
|||||||
}
|
}
|
||||||
builder.WriteString("Type: " + pkgInfo.Type + "\n")
|
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
|
// Dependencies
|
||||||
builderWriteDependencyArray("Dependencies", pkgInfo.Depends)
|
builderWriteDependencyArray("Dependencies", pkgInfo.Depends)
|
||||||
if pkgInfo.Type == "source" {
|
if pkgInfo.Type == "source" {
|
||||||
@@ -627,7 +710,7 @@ func (pkgInfo *PackageInfo) CreateReadableInfo(rootDir string) string {
|
|||||||
builder.WriteString("\n")
|
builder.WriteString("\n")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
builderWriteArray("Dependant packages", pkgInfo.GetPackageDependants(rootDir), true)
|
builderWriteArray("Dependant packages", pkgInfo.GetPackageDependants(rootDir, false), true)
|
||||||
builderWriteArray("Optionally dependant packages", pkgInfo.GetPackageOptionalDependants(rootDir), true)
|
builderWriteArray("Optionally dependant packages", pkgInfo.GetPackageOptionalDependants(rootDir), true)
|
||||||
|
|
||||||
// Other package relations
|
// Other package relations
|
||||||
@@ -698,6 +781,17 @@ func extractPackage(bpmpkg *BPMPackage, verbose bool, filename, rootDir string)
|
|||||||
extractFilename := path.Join(rootDir, header.Name)
|
extractFilename := path.Join(rootDir, header.Name)
|
||||||
switch header.Typeflag {
|
switch header.Typeflag {
|
||||||
case tar.TypeDir:
|
case tar.TypeDir:
|
||||||
|
// Check if path is set to be ignored
|
||||||
|
if ok := slices.ContainsFunc(MainBPMConfig.IgnorePaths, func(s string) bool {
|
||||||
|
matched, _ := filepath.Match(s, header.Name)
|
||||||
|
return matched
|
||||||
|
}); rootDir == "/" && ok {
|
||||||
|
if verbose {
|
||||||
|
fmt.Printf("Skipping Directory: %s (Path was ignored)\n", extractFilename)
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
if _, err := os.Stat(extractFilename); err == nil {
|
if _, err := os.Stat(extractFilename); err == nil {
|
||||||
if verbose {
|
if verbose {
|
||||||
fmt.Printf("Skipping Directory: %s (Directory already exists)\n", extractFilename)
|
fmt.Printf("Skipping Directory: %s (Directory already exists)\n", extractFilename)
|
||||||
@@ -725,6 +819,17 @@ func extractPackage(bpmpkg *BPMPackage, verbose bool, filename, rootDir string)
|
|||||||
}
|
}
|
||||||
bar.Add64(header.Size)
|
bar.Add64(header.Size)
|
||||||
case tar.TypeReg:
|
case tar.TypeReg:
|
||||||
|
// Check if path is set to be ignored
|
||||||
|
if ok := slices.ContainsFunc(MainBPMConfig.IgnorePaths, func(s string) bool {
|
||||||
|
matched, _ := filepath.Match(s, header.Name)
|
||||||
|
return matched
|
||||||
|
}); rootDir == "/" && ok {
|
||||||
|
if verbose {
|
||||||
|
fmt.Printf("Skipping File: %s (Path was ignored)\n", extractFilename)
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
skip := false
|
skip := false
|
||||||
if _, err := os.Stat(extractFilename); err == nil {
|
if _, err := os.Stat(extractFilename); err == nil {
|
||||||
for _, k := range bpmpkg.PkgInfo.Keep {
|
for _, k := range bpmpkg.PkgInfo.Keep {
|
||||||
@@ -782,6 +887,17 @@ func extractPackage(bpmpkg *BPMPackage, verbose bool, filename, rootDir string)
|
|||||||
}
|
}
|
||||||
bar.Add64(header.Size)
|
bar.Add64(header.Size)
|
||||||
case tar.TypeSymlink:
|
case tar.TypeSymlink:
|
||||||
|
// Check if path is set to be ignored
|
||||||
|
if ok := slices.ContainsFunc(MainBPMConfig.IgnorePaths, func(s string) bool {
|
||||||
|
matched, _ := filepath.Match(s, header.Name)
|
||||||
|
return matched
|
||||||
|
}); rootDir == "/" && ok {
|
||||||
|
if verbose {
|
||||||
|
fmt.Printf("Skipping Symlink: %s (Path was ignored)\n", extractFilename)
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
err := os.Remove(extractFilename)
|
err := os.Remove(extractFilename)
|
||||||
if err != nil && !os.IsNotExist(err) {
|
if err != nil && !os.IsNotExist(err) {
|
||||||
return err
|
return err
|
||||||
@@ -797,6 +913,17 @@ func extractPackage(bpmpkg *BPMPackage, verbose bool, filename, rootDir string)
|
|||||||
}
|
}
|
||||||
bar.Add64(header.Size)
|
bar.Add64(header.Size)
|
||||||
case tar.TypeLink:
|
case tar.TypeLink:
|
||||||
|
// Check if path is set to be ignored
|
||||||
|
if ok := slices.ContainsFunc(MainBPMConfig.IgnorePaths, func(s string) bool {
|
||||||
|
matched, _ := filepath.Match(s, header.Name)
|
||||||
|
return matched
|
||||||
|
}); rootDir == "/" && ok {
|
||||||
|
if verbose {
|
||||||
|
fmt.Printf("Skipping Hard Link: %s (Path was ignored)\n", extractFilename)
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
if verbose {
|
if verbose {
|
||||||
fmt.Println("Detected Hard Link: " + extractFilename + " -> " + path.Join(rootDir, strings.TrimPrefix(header.Linkname, "files/")))
|
fmt.Println("Detected Hard Link: " + extractFilename + " -> " + path.Join(rootDir, strings.TrimPrefix(header.Linkname, "files/")))
|
||||||
}
|
}
|
||||||
@@ -825,7 +952,7 @@ func extractPackage(bpmpkg *BPMPackage, verbose bool, filename, rootDir string)
|
|||||||
return nil
|
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) {
|
if _, err := os.Stat(filename); os.IsNotExist(err) {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -872,26 +999,39 @@ func installPackage(filename string, installationReason InstallationReason, root
|
|||||||
fmt.Printf("Removing old files for package (%s)...\n", bpmpkg.PkgInfo.Name)
|
fmt.Printf("Removing old files for package (%s)...\n", bpmpkg.PkgInfo.Name)
|
||||||
}
|
}
|
||||||
for _, entry := range fileEntries {
|
for _, entry := range fileEntries {
|
||||||
file := path.Join(rootDir, entry.Path)
|
finalPath := path.Join(rootDir, entry.Path)
|
||||||
stat, err := os.Lstat(file)
|
|
||||||
|
stat, err := os.Lstat(finalPath)
|
||||||
if os.IsNotExist(err) {
|
if os.IsNotExist(err) {
|
||||||
continue
|
continue
|
||||||
}
|
} else if err != nil {
|
||||||
if err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if len(files[entry.Path]) != 0 {
|
|
||||||
|
// Check if path is set to be ignored
|
||||||
|
if ok := slices.ContainsFunc(MainBPMConfig.IgnorePaths, func(s string) bool {
|
||||||
|
matched, _ := filepath.Match(s, entry.Path)
|
||||||
|
return matched
|
||||||
|
}); rootDir == "/" && ok {
|
||||||
if verbose {
|
if verbose {
|
||||||
fmt.Println("Skipping path: " + file + " (Path is managed by multiple packages)")
|
fmt.Printf("Skipping path: %s (Path was ignored)\n", finalPath)
|
||||||
}
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(files[entry.Path]) != 0 {
|
||||||
|
if verbose {
|
||||||
|
fmt.Println("Skipping path: " + finalPath + " (Path is managed by multiple packages)")
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
shouldContinue := false
|
shouldContinue := false
|
||||||
for _, value := range bpmpkg.PkgInfo.Keep {
|
for _, value := range bpmpkg.PkgInfo.Keep {
|
||||||
if strings.HasSuffix(value, "/") {
|
if strings.HasSuffix(value, "/") {
|
||||||
if strings.HasPrefix(entry.Path, value) || entry.Path == strings.TrimSuffix(value, "/") {
|
if strings.HasPrefix(entry.Path, value) || entry.Path == strings.TrimSuffix(value, "/") {
|
||||||
if verbose {
|
if verbose {
|
||||||
fmt.Println("Skipping path: " + file + " (Path is set to be kept during reinstalls/updates)")
|
fmt.Println("Skipping path: " + finalPath + " (Path is set to be kept during reinstalls/updates)")
|
||||||
}
|
}
|
||||||
shouldContinue = true
|
shouldContinue = true
|
||||||
continue
|
continue
|
||||||
@@ -899,7 +1039,7 @@ func installPackage(filename string, installationReason InstallationReason, root
|
|||||||
} else {
|
} else {
|
||||||
if entry.Path == value {
|
if entry.Path == value {
|
||||||
if verbose {
|
if verbose {
|
||||||
fmt.Println("Skipping path: " + file + " (Path is set to be kept during reinstalls/updates)")
|
fmt.Println("Skipping path: " + finalPath + " (Path is set to be kept during reinstalls/updates)")
|
||||||
}
|
}
|
||||||
shouldContinue = true
|
shouldContinue = true
|
||||||
continue
|
continue
|
||||||
@@ -911,37 +1051,37 @@ func installPackage(filename string, installationReason InstallationReason, root
|
|||||||
}
|
}
|
||||||
if stat.Mode()&os.ModeSymlink != 0 {
|
if stat.Mode()&os.ModeSymlink != 0 {
|
||||||
if verbose {
|
if verbose {
|
||||||
fmt.Println("Removing: " + file)
|
fmt.Println("Removing: " + finalPath)
|
||||||
}
|
}
|
||||||
err := os.Remove(file)
|
err := os.Remove(finalPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if stat.IsDir() {
|
if stat.IsDir() {
|
||||||
dir, err := os.ReadDir(file)
|
dir, err := os.ReadDir(finalPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if len(dir) != 0 {
|
if len(dir) != 0 {
|
||||||
if verbose {
|
if verbose {
|
||||||
fmt.Println("Skipping non-empty directory: " + file)
|
fmt.Println("Skipping non-empty directory: " + finalPath)
|
||||||
}
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if verbose {
|
if verbose {
|
||||||
fmt.Println("Removing: " + file)
|
fmt.Println("Removing: " + finalPath)
|
||||||
}
|
}
|
||||||
err = os.Remove(file)
|
err = os.Remove(finalPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if verbose {
|
if verbose {
|
||||||
fmt.Println("Removing: " + file)
|
fmt.Println("Removing: " + finalPath)
|
||||||
}
|
}
|
||||||
err := os.Remove(file)
|
err := os.Remove(finalPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -976,12 +1116,12 @@ func installPackage(filename string, installationReason InstallationReason, root
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
f, err := os.Create(path.Join(pkgDir, "files"))
|
f, err := os.Create(path.Join(pkgDir, "files.txt"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
tarballFile, err := readTarballFile(filename, "pkg.files")
|
tarballFile, err := readTarballFile(filename, "files.txt")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -992,7 +1132,7 @@ func installPackage(filename string, installationReason InstallationReason, root
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
f, err = os.Create(path.Join(pkgDir, "info"))
|
f, err = os.Create(path.Join(pkgDir, "info.yml"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -1016,6 +1156,7 @@ func installPackage(filename string, installationReason InstallationReason, root
|
|||||||
}
|
}
|
||||||
localInfo.LastUpdatedOn = time.Now().Unix()
|
localInfo.LastUpdatedOn = time.Now().Unix()
|
||||||
localInfo.InstallationReason = string(installationReason)
|
localInfo.InstallationReason = string(installationReason)
|
||||||
|
localInfo.Flags = flags
|
||||||
|
|
||||||
SetPackageLocalInfo(bpmpkg.PkgInfo.Name, localInfo, rootDir)
|
SetPackageLocalInfo(bpmpkg.PkgInfo.Name, localInfo, rootDir)
|
||||||
|
|
||||||
@@ -1111,31 +1252,44 @@ func removePackage(pkg string, verbose bool, rootDir string) error {
|
|||||||
// Removing package files
|
// Removing package files
|
||||||
for _, entry := range fileEntries {
|
for _, entry := range fileEntries {
|
||||||
bar.Add64(entry.SizeInBytes)
|
bar.Add64(entry.SizeInBytes)
|
||||||
file := path.Join(rootDir, entry.Path)
|
|
||||||
lstat, err := os.Lstat(file)
|
finalPath := path.Join(rootDir, entry.Path)
|
||||||
|
|
||||||
|
lstat, err := os.Lstat(finalPath)
|
||||||
if os.IsNotExist(err) {
|
if os.IsNotExist(err) {
|
||||||
continue
|
continue
|
||||||
}
|
} else if err != nil {
|
||||||
if err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check if path is set to be ignored
|
||||||
|
if ok := slices.ContainsFunc(MainBPMConfig.IgnorePaths, func(s string) bool {
|
||||||
|
matched, _ := filepath.Match(s, entry.Path)
|
||||||
|
return matched
|
||||||
|
}); rootDir == "/" && ok {
|
||||||
|
if verbose {
|
||||||
|
fmt.Printf("Skipping path: %s (Path was ignored)\n", finalPath)
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
if len(files[entry.Path]) != 0 {
|
if len(files[entry.Path]) != 0 {
|
||||||
if verbose {
|
if verbose {
|
||||||
fmt.Println("Skipping path: " + file + "(Path is managed by multiple packages)")
|
fmt.Println("Skipping path: " + finalPath + "(Path is managed by multiple packages)")
|
||||||
}
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if lstat.Mode()&os.ModeSymlink != 0 {
|
if lstat.Mode()&os.ModeSymlink != 0 {
|
||||||
if verbose {
|
if verbose {
|
||||||
fmt.Println("Removing: " + file)
|
fmt.Println("Removing: " + finalPath)
|
||||||
}
|
}
|
||||||
err := os.Remove(file)
|
err := os.Remove(finalPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
stat, err := os.Stat(file)
|
stat, err := os.Stat(finalPath)
|
||||||
if os.IsNotExist(err) {
|
if os.IsNotExist(err) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@@ -1143,28 +1297,28 @@ func removePackage(pkg string, verbose bool, rootDir string) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if stat.IsDir() {
|
if stat.IsDir() {
|
||||||
dir, err := os.ReadDir(file)
|
dir, err := os.ReadDir(finalPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if len(dir) != 0 {
|
if len(dir) != 0 {
|
||||||
if verbose {
|
if verbose {
|
||||||
fmt.Println("Skipping non-empty directory: " + file)
|
fmt.Println("Skipping non-empty directory: " + finalPath)
|
||||||
}
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if verbose {
|
if verbose {
|
||||||
fmt.Println("Removing: " + file)
|
fmt.Println("Removing: " + finalPath)
|
||||||
}
|
}
|
||||||
err = os.Remove(file)
|
err = os.Remove(finalPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if verbose {
|
if verbose {
|
||||||
fmt.Println("Removing: " + file)
|
fmt.Println("Removing: " + finalPath)
|
||||||
}
|
}
|
||||||
err := os.Remove(file)
|
err := os.Remove(finalPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user