mirror of
https://github.com/EnumeratedDev/bpm.git
synced 2026-09-22 05:26:12 +00:00
Compare commits
13
Commits
3f23580d16
..
0.7.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
dc8959c2f8
|
||
|
|
9122ffb9ca
|
||
|
|
a4e20b7d88
|
||
|
|
a03c9ad9ce
|
||
|
|
3f205ec412
|
||
|
|
2f9487affe
|
||
|
|
596d8753a7
|
||
|
|
2de4eea7a4
|
||
|
|
5d0312856d
|
||
|
|
248359c02f
|
||
|
|
1d81690bff
|
||
|
|
618916cd22
|
||
|
|
8e4177c899
|
+86
-69
@@ -89,7 +89,6 @@ func main() {
|
||||
currentFlagSet.BoolP("force", "f", false, "Bypass warnings during package installation")
|
||||
currentFlagSet.BoolP("yes", "y", false, "Enter 'yes' in all prompts")
|
||||
currentFlagSet.Bool("runtime", true, "Install all runtime dependencies")
|
||||
currentFlagSet.BoolP("optional", "o", false, "Install all optional dependencies")
|
||||
currentFlagSet.String("installation-reason", "", "Specify the installation reason to use for 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")
|
||||
@@ -142,7 +141,6 @@ func main() {
|
||||
currentFlagSet.BoolP("yes", "y", false, "Enter 'yes' in all prompts")
|
||||
currentFlagSet.BoolP("no-sync", "n", false, "Do not sync databases")
|
||||
currentFlagSet.Bool("allow-downgrades", false, "Allow package downgrades")
|
||||
currentFlagSet.BoolP("optional", "o", false, "Install all optional dependencies")
|
||||
currentFlagSet.BoolP("skip-checks", "s", false, "Skip the check function in source.sh scripts")
|
||||
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:])
|
||||
@@ -154,7 +152,7 @@ func main() {
|
||||
currentFlagSet.StringP("root", "R", "/", "Operate on specified root directory")
|
||||
setupFlagsAndHelp(currentFlagSet, fmt.Sprintf("bpm %s <options>", subcommand), "Show what packages own the specified paths", os.Args[2:])
|
||||
|
||||
getFileOwner()
|
||||
getPathOwners()
|
||||
case "c", "compile":
|
||||
// Setup flags and help
|
||||
currentFlagSet = flag.NewFlagSet("compile", flag.ExitOnError)
|
||||
@@ -558,7 +556,6 @@ func installPackages() {
|
||||
force, _ := currentFlagSet.GetBool("force")
|
||||
yesAll, _ := currentFlagSet.GetBool("yes")
|
||||
installRuntime, _ := currentFlagSet.GetBool("runtime")
|
||||
installOptional, _ := currentFlagSet.GetBool("optional")
|
||||
installationReason, _ := currentFlagSet.GetString("installation-reason")
|
||||
reinstallPackages, _ := currentFlagSet.GetBool("reinstall")
|
||||
skipChecks, _ := currentFlagSet.GetBool("skip-checks")
|
||||
@@ -620,7 +617,7 @@ func installPackages() {
|
||||
}
|
||||
|
||||
// Create installation operation
|
||||
operation, err := bpmlib.InstallPackages(rootDir, ir, reinstallPackages, installRuntime, installOptional, 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{}) {
|
||||
log.Printf("Error: %s", err)
|
||||
exitCode = 1
|
||||
@@ -665,6 +662,9 @@ func installPackages() {
|
||||
return
|
||||
}
|
||||
|
||||
// Get files that will be modifie during this operation
|
||||
operation.GetModifiedFiles()
|
||||
|
||||
if bpmlib.MainBPMConfig.ShowSourcePackageContents == "always" || bpmlib.MainBPMConfig.ShowSourcePackageContents == "install-only" {
|
||||
// Show source package contents
|
||||
sourcePackagesShown, err := operation.ShowSourcePackageContent()
|
||||
@@ -687,6 +687,15 @@ func installPackages() {
|
||||
// Get optional dependencies
|
||||
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
|
||||
err = operation.Execute(verbose, force)
|
||||
if err != nil {
|
||||
@@ -695,17 +704,19 @@ func installPackages() {
|
||||
return
|
||||
}
|
||||
|
||||
// Executing hooks
|
||||
fmt.Println("Running hooks...")
|
||||
err = operation.RunHooks(verbose)
|
||||
// Executing post-operation hooks
|
||||
fmt.Println("Running post-operation hooks...")
|
||||
err = operation.RunPostHooks(verbose)
|
||||
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
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println("Operation complete!")
|
||||
|
||||
// Show optional dependencies
|
||||
if !installOptional && len(optionalDepends) != 0 {
|
||||
if len(optionalDepends) != 0 {
|
||||
// List optional dependencies
|
||||
fmt.Println("The following optional dependenices have been discovered:")
|
||||
for dependant, depends := range optionalDepends {
|
||||
@@ -768,6 +779,7 @@ func removePackages() {
|
||||
return
|
||||
} else if errors.As(err, &bpmlib.PackageRemovalDependencyErr{}) {
|
||||
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, ", "))
|
||||
}
|
||||
|
||||
@@ -803,6 +815,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
|
||||
err = operation.Execute(verbose, force)
|
||||
if err != nil {
|
||||
@@ -811,14 +835,16 @@ func removePackages() {
|
||||
return
|
||||
}
|
||||
|
||||
// Executing hooks
|
||||
fmt.Println("Running hooks...")
|
||||
err = operation.RunHooks(verbose)
|
||||
// Executing post-operation hooks
|
||||
fmt.Println("Running post-operation hooks...")
|
||||
err = operation.RunPostHooks(verbose)
|
||||
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
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println("Operation complete!")
|
||||
}
|
||||
|
||||
func doCleanup() {
|
||||
@@ -924,6 +950,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
|
||||
err = operation.Execute(verbose, force)
|
||||
if err != nil {
|
||||
@@ -932,14 +970,16 @@ func doCleanup() {
|
||||
return
|
||||
}
|
||||
|
||||
// Executing hooks
|
||||
fmt.Println("Running hooks...")
|
||||
err = operation.RunHooks(verbose)
|
||||
// Executing post-operation hooks
|
||||
fmt.Println("Running post-operation hooks...")
|
||||
err = operation.RunPostHooks(verbose)
|
||||
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
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println("Operation complete!")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -993,7 +1033,6 @@ func updatePackages() {
|
||||
yesAll, _ := currentFlagSet.GetBool("yes")
|
||||
noSync, _ := currentFlagSet.GetBool("no-sync")
|
||||
allowDowngrades, _ := currentFlagSet.GetBool("allow-downgrades")
|
||||
installOptional, _ := currentFlagSet.GetBool("optional")
|
||||
skipChecks, _ := currentFlagSet.GetBool("skip-checks")
|
||||
compilationJobs, _ := currentFlagSet.GetInt("jobs")
|
||||
|
||||
@@ -1041,7 +1080,7 @@ func updatePackages() {
|
||||
}
|
||||
|
||||
// Create update operation
|
||||
operation, err := bpmlib.UpdatePackages(rootDir, !noSync, allowDowngrades, installOptional, 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{}) {
|
||||
log.Printf("Error: %s", err)
|
||||
exitCode = 1
|
||||
@@ -1086,6 +1125,9 @@ func updatePackages() {
|
||||
return
|
||||
}
|
||||
|
||||
// Get files that will be modifie during this operation
|
||||
operation.GetModifiedFiles()
|
||||
|
||||
if bpmlib.MainBPMConfig.ShowSourcePackageContents == "always" {
|
||||
// Show source package contents
|
||||
sourcePackagesShown, err := operation.ShowSourcePackageContent()
|
||||
@@ -1108,6 +1150,15 @@ func updatePackages() {
|
||||
// Get optional dependencies
|
||||
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
|
||||
err = operation.Execute(verbose, force)
|
||||
if err != nil {
|
||||
@@ -1116,17 +1167,19 @@ func updatePackages() {
|
||||
return
|
||||
}
|
||||
|
||||
// Executing hooks
|
||||
fmt.Println("Running hooks...")
|
||||
err = operation.RunHooks(verbose)
|
||||
// Executing post-operation hooks
|
||||
fmt.Println("Running post-operation hooks...")
|
||||
err = operation.RunPostHooks(verbose)
|
||||
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
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println("Operation complete!")
|
||||
|
||||
// Show optional dependencies
|
||||
if !installOptional && len(optionalDepends) != 0 {
|
||||
if len(optionalDepends) != 0 {
|
||||
// List optional dependencies
|
||||
fmt.Println("The following optional dependenices have been discovered:")
|
||||
for dependant, depends := range optionalDepends {
|
||||
@@ -1138,7 +1191,7 @@ func updatePackages() {
|
||||
}
|
||||
}
|
||||
|
||||
func getFileOwner() {
|
||||
func getPathOwners() {
|
||||
// Get flags
|
||||
rootDir, _ := currentFlagSet.GetString("root")
|
||||
|
||||
@@ -1161,7 +1214,7 @@ func getFileOwner() {
|
||||
// Ensure file exists
|
||||
stat, err := os.Lstat(path)
|
||||
if os.IsNotExist(err) {
|
||||
log.Printf("Error: file (%s) does not exist!\n", path)
|
||||
log.Printf("Error: %s", err)
|
||||
exitCode = 1
|
||||
return
|
||||
}
|
||||
@@ -1174,57 +1227,21 @@ func getFileOwner() {
|
||||
pathType = "Symlink"
|
||||
}
|
||||
|
||||
// Get absolte path to path
|
||||
absPath, err := filepath.Abs(path)
|
||||
pathOwners, err := bpmlib.GetPathOwners(path, rootDir)
|
||||
if err != nil {
|
||||
log.Printf("Error: could not get absolute path of file (%s)\n", path)
|
||||
log.Printf("Error: %s", err)
|
||||
exitCode = 1
|
||||
return
|
||||
}
|
||||
|
||||
// Get path relative to rootDir
|
||||
if !strings.HasPrefix(absPath, rootDir) {
|
||||
log.Printf("Error: could not get path of file (%s) relative to root path", absPath)
|
||||
exitCode = 1
|
||||
return
|
||||
}
|
||||
absPath, err = filepath.Rel(rootDir, absPath)
|
||||
if err != nil {
|
||||
log.Printf("Error: could not get path of file (%s) relative to root path", absPath)
|
||||
exitCode = 1
|
||||
return
|
||||
}
|
||||
|
||||
// Trim leading and trailing slashes
|
||||
absPath = strings.TrimLeft(absPath, "/")
|
||||
absPath = strings.TrimRight(absPath, "/")
|
||||
|
||||
// Get installed packages
|
||||
pkgs, err := bpmlib.GetInstalledPackages(rootDir)
|
||||
if err != nil {
|
||||
log.Printf("Error: could not get installed packages: %s\n", err.Error())
|
||||
exitCode = 1
|
||||
return
|
||||
}
|
||||
|
||||
// Add packages that own path to list
|
||||
var pkgList []string
|
||||
for _, pkg := range pkgs {
|
||||
if slices.ContainsFunc(bpmlib.GetPackage(pkg, rootDir).PkgFiles, func(entry *bpmlib.PackageFileEntry) bool {
|
||||
return entry.Path == absPath
|
||||
}) {
|
||||
pkgList = append(pkgList, pkg)
|
||||
}
|
||||
}
|
||||
|
||||
// Print packages
|
||||
if len(pkgList) == 0 {
|
||||
fmt.Printf("%s (%s) is not owned by any packages!\n", absPath, pathType)
|
||||
if len(pathOwners) == 0 {
|
||||
fmt.Printf("%s (%s) is not owned by any packages!\n", path, pathType)
|
||||
exitCode = 1
|
||||
return
|
||||
} else {
|
||||
fmt.Printf("%s (%s) is owned by the following packages:\n", absPath, pathType)
|
||||
for _, pkg := range pkgList {
|
||||
fmt.Printf("%s (%s) is owned by the following packages:\n", path, pathType)
|
||||
for _, pkg := range pathOwners {
|
||||
fmt.Println("- " + pkg)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
|
||||
type MainBPMConfigStruct struct {
|
||||
IgnorePackages []string `yaml:"ignore_packages"`
|
||||
IgnorePaths []string `yaml:"ignore_paths"`
|
||||
ShowSourcePackageContents string `yaml:"show_source_package_contents"`
|
||||
CleanupMakeDependencies bool `yaml:"cleanup_make_dependencies"`
|
||||
Databases []configDatabase `yaml:"databases"`
|
||||
|
||||
+94
-3
@@ -300,10 +300,52 @@ func (db *BPMDatabase) FetchPackage(pkg string) (string, error) {
|
||||
|
||||
func (entry *BPMDatabaseEntry) GetEntryDependants() (dependants []string) {
|
||||
dependantsMap := make(map[string][]string)
|
||||
|
||||
// Loop through all entries
|
||||
for _, db := range BPMDatabases {
|
||||
for _, e := range db.Entries {
|
||||
if slices.Contains(e.Info.Depends, entry.Info.Name) {
|
||||
dependantsMap[e.Info.Name] = append(dependantsMap[e.Info.Name], e.Database.Name)
|
||||
// Skip iteration if comparing the same packages
|
||||
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 {
|
||||
n, _, _ = SplitPkgNameAndVersion(n)
|
||||
return n == 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 {
|
||||
n, _, _ = SplitPkgNameAndVersion(n)
|
||||
return n == 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 {
|
||||
n, _, _ = SplitPkgNameAndVersion(n)
|
||||
return n == 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 {
|
||||
n, _, _ = SplitPkgNameAndVersion(n)
|
||||
return n == vpkg
|
||||
}) {
|
||||
dependantsMap[e.Info.Name] = append(dependantsMap[e.Info.Name], db.Name)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -332,7 +374,45 @@ func (entry *BPMDatabaseEntry) GetEntryOptionalDependants() (dependants []string
|
||||
for _, db := range BPMDatabases {
|
||||
for _, e := range db.Entries {
|
||||
if slices.ContainsFunc(e.Info.OptionalDepends, func(n string) bool {
|
||||
return strings.SplitN(n, ":", 2)[0] == entry.Info.Name
|
||||
// Remove optional dependency comment
|
||||
n = strings.SplitN(n, ":", 2)[0]
|
||||
|
||||
// Remove required version
|
||||
n, _, _ = SplitPkgNameAndVersion(n)
|
||||
|
||||
return n == entry.Info.Name
|
||||
}) {
|
||||
dependantsMap[e.Info.Name] = append(dependantsMap[e.Info.Name], e.Database.Name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Get keys
|
||||
keySlice := slices.Collect(maps.Keys(dependantsMap))
|
||||
slices.Sort(keySlice)
|
||||
|
||||
// Add all dependant entries to slice in alphabetical order
|
||||
for _, entryName := range keySlice {
|
||||
dbs := dependantsMap[entryName]
|
||||
if len(dbs) > 1 {
|
||||
for _, db := range dbs {
|
||||
dependants = append(dependants, db+"/"+entryName)
|
||||
}
|
||||
} else {
|
||||
dependants = append(dependants, entryName)
|
||||
}
|
||||
}
|
||||
|
||||
return dependants
|
||||
}
|
||||
|
||||
func (entry *BPMDatabaseEntry) GetEntryMakeDependants() (dependants []string) {
|
||||
dependantsMap := make(map[string][]string)
|
||||
for _, db := range BPMDatabases {
|
||||
for _, e := range db.Entries {
|
||||
if slices.ContainsFunc(e.Info.MakeDepends, func(n string) bool {
|
||||
n, _, _ = SplitPkgNameAndVersion(n)
|
||||
return n == entry.Info.Name
|
||||
}) {
|
||||
dependantsMap[e.Info.Name] = append(dependantsMap[e.Info.Name], e.Database.Name)
|
||||
}
|
||||
@@ -458,6 +538,7 @@ func (entry *BPMDatabaseEntry) CreateReadableInfo(rootDir string, showBytes bool
|
||||
}
|
||||
builderWriteArray("Dependant packages", entry.GetEntryDependants(), true)
|
||||
builderWriteArray("Optionally dependant packages", entry.GetEntryOptionalDependants(), true)
|
||||
builderWriteArray("Make dependant packages", entry.GetEntryMakeDependants(), true)
|
||||
|
||||
// Other package relations
|
||||
builderWriteArray("Conflicting packages", entry.Info.Conflicts, true)
|
||||
@@ -490,6 +571,16 @@ func (entry *BPMDatabaseEntry) CreateReadableInfo(rootDir string, showBytes bool
|
||||
builder.WriteString("Installation reason: " + installationReasonString + "\n")
|
||||
}
|
||||
|
||||
// Download size
|
||||
downloadSize := entry.DownloadSize
|
||||
var downloadSizeStr string
|
||||
if showBytes {
|
||||
downloadSizeStr = strconv.FormatInt(downloadSize, 10)
|
||||
} else {
|
||||
downloadSizeStr = BytesToHumanReadable(downloadSize)
|
||||
}
|
||||
builder.WriteString("Download size: " + downloadSizeStr + "\n")
|
||||
|
||||
// Installed size
|
||||
if entry.Info.Type == "binary" {
|
||||
installedSize := entry.InstalledSize
|
||||
|
||||
+102
-12
@@ -5,7 +5,7 @@ import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
func (pkgInfo *PackageInfo) GetPackageDependants(rootDir string) (dependants []string) {
|
||||
func (pkgInfo *PackageInfo) GetPackageDependants(rootDir string, skipMultipleProviders bool) (dependants []string) {
|
||||
// Get installed package names
|
||||
pkgs, ok := localPackageInformation[rootDir]
|
||||
if !ok {
|
||||
@@ -21,6 +21,7 @@ func (pkgInfo *PackageInfo) GetPackageDependants(rootDir string) (dependants []s
|
||||
|
||||
// Add installed package to list if its dependencies include pkgName
|
||||
if slices.ContainsFunc(installedPkg.Depends, func(n string) bool {
|
||||
n, _, _ = SplitPkgNameAndVersion(n)
|
||||
return n == pkgInfo.Name
|
||||
}) {
|
||||
dependants = append(dependants, installedPkg.Name)
|
||||
@@ -29,6 +30,7 @@ func (pkgInfo *PackageInfo) GetPackageDependants(rootDir string) (dependants []s
|
||||
|
||||
// Add installed package to list if its runtime dependencies include pkgName
|
||||
if slices.ContainsFunc(installedPkg.RuntimeDepends, func(n string) bool {
|
||||
n, _, _ = SplitPkgNameAndVersion(n)
|
||||
return n == pkgInfo.Name
|
||||
}) {
|
||||
dependants = append(dependants, installedPkg.Name)
|
||||
@@ -37,8 +39,13 @@ func (pkgInfo *PackageInfo) GetPackageDependants(rootDir string) (dependants []s
|
||||
|
||||
// Loop through each virtual package
|
||||
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
|
||||
if slices.ContainsFunc(installedPkg.Depends, func(n string) bool {
|
||||
n, _, _ = SplitPkgNameAndVersion(n)
|
||||
return n == vpkg
|
||||
}) {
|
||||
dependants = append(dependants, installedPkg.Name)
|
||||
@@ -47,6 +54,7 @@ func (pkgInfo *PackageInfo) GetPackageDependants(rootDir string) (dependants []s
|
||||
|
||||
// Add installed package to list if its runtime dependencies contain a provided virtual package
|
||||
if slices.ContainsFunc(installedPkg.RuntimeDepends, func(n string) bool {
|
||||
n, _, _ = SplitPkgNameAndVersion(n)
|
||||
return n == vpkg
|
||||
}) {
|
||||
dependants = append(dependants, installedPkg.Name)
|
||||
@@ -74,7 +82,13 @@ func (pkgInfo *PackageInfo) GetPackageOptionalDependants(rootDir string) (depend
|
||||
|
||||
// Add installed package to list if its optional dependencies include pkgName
|
||||
if slices.ContainsFunc(installedPkg.OptionalDepends, func(n string) bool {
|
||||
return strings.SplitN(n, ":", 2)[0] == pkgInfo.Name
|
||||
// Remove optional dependency comment
|
||||
n = strings.SplitN(n, ":", 2)[0]
|
||||
|
||||
// Remove required version
|
||||
n, _, _ = SplitPkgNameAndVersion(n)
|
||||
|
||||
return n == pkgInfo.Name
|
||||
}) {
|
||||
dependants = append(dependants, installedPkg.Name)
|
||||
continue
|
||||
@@ -84,7 +98,13 @@ func (pkgInfo *PackageInfo) GetPackageOptionalDependants(rootDir string) (depend
|
||||
for _, vpkg := range pkgInfo.Provides {
|
||||
// Add installed package to list if its optional dependencies contain a provided virtual package
|
||||
if slices.ContainsFunc(installedPkg.OptionalDepends, func(n string) bool {
|
||||
return strings.SplitN(n, ":", 2)[0] == vpkg
|
||||
// Remove optional dependency comment
|
||||
n = strings.SplitN(n, ":", 2)[0]
|
||||
|
||||
// Remove required version
|
||||
n, _, _ = SplitPkgNameAndVersion(n)
|
||||
|
||||
return n == vpkg
|
||||
}) {
|
||||
dependants = append(dependants, installedPkg.Name)
|
||||
break
|
||||
@@ -100,27 +120,30 @@ type ResolvedPackage struct {
|
||||
InstallationReason InstallationReason
|
||||
}
|
||||
|
||||
func ResolveDependencies(pkgInfo *PackageInfo, resolvedVirtualPackages map[string]string, includeRuntimeDepends, includeOptionalDepends bool, rootDir string) (resolved []ResolvedPackage, unresolved []string) {
|
||||
func ResolveDependencies(pkgInfo *PackageInfo, resolvedVirtualPackages map[string]string, includeRuntimeDepends bool, rootDir string) (resolved []ResolvedPackage, unresolved []string) {
|
||||
visited := make([]string, 0)
|
||||
|
||||
var dfs func(resolvedPkg *PackageInfo)
|
||||
dfs = func(pkgInfo *PackageInfo) {
|
||||
checkDependencies := func(dependencies []string, installationReason InstallationReason) {
|
||||
for _, depend := range dependencies {
|
||||
// Split dependency name and required version
|
||||
dependName, _, _ := SplitPkgNameAndVersion(depend)
|
||||
|
||||
// Ignore if package is already installed
|
||||
if IsPackageInstalled(depend, rootDir) {
|
||||
if IsPackageInstalled(dependName, rootDir) && EvaluateDependency(depend, GetPackageInfo(dependName, rootDir).Version) {
|
||||
continue
|
||||
} else if providers := GetVirtualPackageInfo(depend, rootDir); len(providers) > 0 {
|
||||
} else if providers := GetVirtualPackageInfo(dependName, rootDir); len(providers) > 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
// Find database entry for dependency
|
||||
var dependEntry *BPMDatabaseEntry
|
||||
if resolvedVpkg, ok := resolvedVirtualPackages[depend]; ok {
|
||||
if resolvedVpkg, ok := resolvedVirtualPackages[dependName]; ok {
|
||||
dependEntry, _, _ = GetDatabaseEntry(resolvedVpkg)
|
||||
} else if entry, _, _ := GetDatabaseEntry(depend); entry != nil {
|
||||
} else if entry, _, _ := GetDatabaseEntry(dependName); entry != nil {
|
||||
dependEntry = entry
|
||||
} else if providers := GetDatabaseVirtualPackageEntry(depend); len(providers) > 0 {
|
||||
} else if providers := GetDatabaseVirtualPackageEntry(dependName); len(providers) > 0 {
|
||||
dependEntry = providers[0]
|
||||
}
|
||||
|
||||
@@ -129,6 +152,17 @@ func ResolveDependencies(pkgInfo *PackageInfo, resolvedVirtualPackages map[strin
|
||||
continue
|
||||
}
|
||||
|
||||
// Ensure entry has required version
|
||||
if !EvaluateDependency(depend, dependEntry.Info.Version) {
|
||||
unresolved = append(unresolved, depend)
|
||||
continue
|
||||
}
|
||||
|
||||
// Skip ignored packages in config
|
||||
if slices.Contains(MainBPMConfig.IgnorePackages, dependEntry.Info.Name) {
|
||||
continue
|
||||
}
|
||||
|
||||
if !slices.Contains(visited, dependEntry.Info.Name) {
|
||||
dfs(dependEntry.Info)
|
||||
resolved = append(resolved, ResolvedPackage{DatabaseEntry: dependEntry, InstallationReason: installationReason})
|
||||
@@ -146,12 +180,68 @@ func ResolveDependencies(pkgInfo *PackageInfo, resolvedVirtualPackages map[strin
|
||||
checkDependencies(pkgInfo.MakeDepends, InstallationReasonMakeDependency)
|
||||
checkDependencies(pkgInfo.CheckDepends, InstallationReasonMakeDependency)
|
||||
}
|
||||
if includeOptionalDepends {
|
||||
checkDependencies(pkgInfo.OptionalDepends, InstallationReasonManual)
|
||||
}
|
||||
}
|
||||
|
||||
dfs(pkgInfo)
|
||||
|
||||
return resolved, unresolved
|
||||
}
|
||||
|
||||
func SplitPkgNameAndVersion(pkg string) (string, string, string) {
|
||||
if strings.Contains(pkg, ">=") {
|
||||
pkgSplit := strings.SplitN(pkg, ">=", 2)
|
||||
pkgName := pkgSplit[0]
|
||||
pkgVersion := pkgSplit[1]
|
||||
|
||||
return pkgName, ">=", pkgVersion
|
||||
} else if strings.Contains(pkg, ">") {
|
||||
pkgSplit := strings.SplitN(pkg, ">", 2)
|
||||
pkgName := pkgSplit[0]
|
||||
pkgVersion := pkgSplit[1]
|
||||
|
||||
return pkgName, ">", pkgVersion
|
||||
} else if strings.Contains(pkg, "<=") {
|
||||
pkgSplit := strings.SplitN(pkg, "<=", 2)
|
||||
pkgName := pkgSplit[0]
|
||||
pkgVersion := pkgSplit[1]
|
||||
|
||||
return pkgName, "<=", pkgVersion
|
||||
} else if strings.Contains(pkg, "<") {
|
||||
pkgSplit := strings.SplitN(pkg, "<", 2)
|
||||
pkgName := pkgSplit[0]
|
||||
pkgVersion := pkgSplit[1]
|
||||
|
||||
return pkgName, "<", pkgVersion
|
||||
} else if strings.Contains(pkg, "=") {
|
||||
pkgSplit := strings.SplitN(pkg, "=", 2)
|
||||
pkgName := pkgSplit[0]
|
||||
pkgVersion := pkgSplit[1]
|
||||
|
||||
return pkgName, "=", pkgVersion
|
||||
}
|
||||
|
||||
return pkg, "", ""
|
||||
}
|
||||
|
||||
func EvaluateDependency(pkg, matchVersion string) bool {
|
||||
_, comparisonSymbol, pkgVersion := SplitPkgNameAndVersion(pkg)
|
||||
|
||||
switch comparisonSymbol {
|
||||
case ">=":
|
||||
return CompareVersions(matchVersion, pkgVersion) >= 0
|
||||
case ">":
|
||||
return CompareVersions(matchVersion, pkgVersion) > 0
|
||||
case "<=":
|
||||
return CompareVersions(matchVersion, pkgVersion) <= 0
|
||||
case "<":
|
||||
return CompareVersions(matchVersion, pkgVersion) < 0
|
||||
case "=":
|
||||
if cutPkgVersion, ok := strings.CutSuffix(pkgVersion, "*"); ok {
|
||||
return strings.HasPrefix(matchVersion, cutPkgVersion)
|
||||
} else {
|
||||
return CompareVersions(matchVersion, pkgVersion) == 0
|
||||
}
|
||||
default:
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package bpmlib
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"slices"
|
||||
"strings"
|
||||
)
|
||||
|
||||
@@ -10,6 +11,7 @@ type PackageNotFoundErr struct {
|
||||
}
|
||||
|
||||
func (e PackageNotFoundErr) Error() string {
|
||||
slices.Sort(e.packages)
|
||||
return "The following packages were not found in any databases: " + strings.Join(e.packages, ", ")
|
||||
}
|
||||
|
||||
@@ -18,6 +20,7 @@ type DependencyNotFoundErr struct {
|
||||
}
|
||||
|
||||
func (e DependencyNotFoundErr) Error() string {
|
||||
slices.Sort(e.dependencies)
|
||||
return "The following dependencies were not found in any databases: " + strings.Join(e.dependencies, ", ")
|
||||
}
|
||||
|
||||
@@ -27,6 +30,7 @@ type PackageConflictErr struct {
|
||||
}
|
||||
|
||||
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, ", "))
|
||||
|
||||
}
|
||||
|
||||
+114
-20
@@ -12,12 +12,12 @@ import (
|
||||
)
|
||||
|
||||
// InstallPackages installs the specified packages into the given root directory by fetching them from databases or directly from local bpm archives
|
||||
func InstallPackages(rootDir string, forceInstallationReason InstallationReason, reinstallPackages bool, installRuntimeDependencies, installOptionalDependencies, forceInstallation, runChecks bool, verbose bool, packages ...string) (operation *BPMOperation, err error) {
|
||||
func InstallPackages(rootDir string, forceInstallationReason InstallationReason, reinstallPackages bool, installRuntimeDependencies, forceInstallation, runChecks bool, verbose bool, packages ...string) (operation *BPMOperation, err error) {
|
||||
// Setup operation struct
|
||||
operation = &BPMOperation{
|
||||
Actions: make([]OperationAction, 0),
|
||||
UnresolvedDepends: make([]string, 0),
|
||||
Changes: make(map[string]string),
|
||||
ModifiedFiles: make(map[string]string),
|
||||
RunChecks: runChecks,
|
||||
RootDir: rootDir,
|
||||
compiledPackages: make(map[string]string),
|
||||
@@ -81,22 +81,31 @@ func InstallPackages(rootDir string, forceInstallationReason InstallationReason,
|
||||
BpmPackage: bpmpkg,
|
||||
})
|
||||
} else {
|
||||
// Split package name and required version
|
||||
pkgName, _, _ := SplitPkgNameAndVersion(pkg)
|
||||
|
||||
var entry *BPMDatabaseEntry
|
||||
|
||||
if e, _, err := GetDatabaseEntry(pkg); err == nil {
|
||||
if e, _, err := GetDatabaseEntry(pkgName); err == nil {
|
||||
entry = e
|
||||
} else if providers := GetVirtualPackageInfo(pkg, rootDir); len(providers) > 0 {
|
||||
} else if providers := GetVirtualPackageInfo(pkgName, rootDir); len(providers) > 0 {
|
||||
entry, _, err = GetDatabaseEntry(providers[0].Name)
|
||||
if err != nil {
|
||||
pkgsNotFound = append(pkgsNotFound, pkg)
|
||||
continue
|
||||
}
|
||||
} else if providers := GetDatabaseVirtualPackageEntry(pkg); len(providers) > 0 {
|
||||
} else if providers := GetDatabaseVirtualPackageEntry(pkgName); len(providers) > 0 {
|
||||
entry = providers[0]
|
||||
} else {
|
||||
pkgsNotFound = append(pkgsNotFound, pkg)
|
||||
continue
|
||||
}
|
||||
|
||||
if !EvaluateDependency(pkg, entry.Info.Version) {
|
||||
pkgsNotFound = append(pkgsNotFound, pkg)
|
||||
continue
|
||||
}
|
||||
|
||||
if !reinstallPackages && IsPackageInstalled(entry.Info.Name, rootDir) && GetPackageInfo(entry.Info.Name, rootDir).GetFullVersion() == entry.Info.GetFullVersion() {
|
||||
continue
|
||||
}
|
||||
@@ -124,7 +133,7 @@ func InstallPackages(rootDir string, forceInstallationReason InstallationReason,
|
||||
}
|
||||
|
||||
// Resolve dependencies
|
||||
operation.ResolveDependencies(installRuntimeDependencies, installOptionalDependencies)
|
||||
operation.ResolveDependencies(installRuntimeDependencies)
|
||||
if len(operation.UnresolvedDepends) != 0 {
|
||||
if !forceInstallation {
|
||||
return nil, DependencyNotFoundErr{operation.UnresolvedDepends}
|
||||
@@ -180,7 +189,7 @@ func RemovePackages(rootDir string, force, cleanupDependencies bool, packages ..
|
||||
operation = &BPMOperation{
|
||||
Actions: make([]OperationAction, 0),
|
||||
UnresolvedDepends: make([]string, 0),
|
||||
Changes: make(map[string]string),
|
||||
ModifiedFiles: make(map[string]string),
|
||||
RootDir: rootDir,
|
||||
compiledPackages: make(map[string]string),
|
||||
}
|
||||
@@ -213,12 +222,12 @@ func RemovePackages(rootDir string, force, cleanupDependencies bool, packages ..
|
||||
// Get packages and their dependants
|
||||
packageDepndants := make(map[string][]string, 0)
|
||||
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) {
|
||||
continue
|
||||
}
|
||||
|
||||
dependants := action.(*RemovePackageAction).BpmPackage.PkgInfo.GetPackageDependants(rootDir)
|
||||
dependants := action.(*RemovePackageAction).BpmPackage.PkgInfo.GetPackageDependants(rootDir, true)
|
||||
packageDepndants[action.(*RemovePackageAction).BpmPackage.PkgInfo.Name] = dependants
|
||||
}
|
||||
|
||||
@@ -258,7 +267,7 @@ func CleanupPackages(cleanupMakeDepends bool, rootDir string) (operation *BPMOpe
|
||||
operation = &BPMOperation{
|
||||
Actions: make([]OperationAction, 0),
|
||||
UnresolvedDepends: make([]string, 0),
|
||||
Changes: make(map[string]string),
|
||||
ModifiedFiles: make(map[string]string),
|
||||
RootDir: rootDir,
|
||||
compiledPackages: make(map[string]string),
|
||||
}
|
||||
@@ -355,7 +364,7 @@ func CleanupCache(rootDir string, cleanupCompilationFiles, cleanupCompiledPackag
|
||||
}
|
||||
|
||||
// UpdatePackages fetches the newest versions of all installed packages from
|
||||
func UpdatePackages(rootDir string, syncDatabase bool, allowDowngrades bool, installOptionalDependencies, forceInstallation, runChecks, verbose bool) (operation *BPMOperation, err error) {
|
||||
func UpdatePackages(rootDir string, syncDatabase, allowDowngrades, forceInstallation, runChecks, verbose bool) (operation *BPMOperation, err error) {
|
||||
// Sync databases
|
||||
if syncDatabase {
|
||||
err := SyncDatabase(verbose)
|
||||
@@ -386,13 +395,14 @@ func UpdatePackages(rootDir string, syncDatabase bool, allowDowngrades bool, ins
|
||||
operation = &BPMOperation{
|
||||
Actions: make([]OperationAction, 0),
|
||||
UnresolvedDepends: make([]string, 0),
|
||||
Changes: make(map[string]string),
|
||||
ModifiedFiles: make(map[string]string),
|
||||
RunChecks: runChecks,
|
||||
RootDir: rootDir,
|
||||
compiledPackages: make(map[string]string),
|
||||
}
|
||||
|
||||
// Search for packages
|
||||
pkgsNotFound := make([]string, 0)
|
||||
for _, pkg := range pkgs {
|
||||
if slices.Contains(MainBPMConfig.IgnorePackages, pkg) {
|
||||
continue
|
||||
@@ -416,17 +426,101 @@ func UpdatePackages(rootDir string, syncDatabase bool, allowDowngrades bool, ins
|
||||
DatabaseEntry: entry,
|
||||
})
|
||||
}
|
||||
|
||||
// Check for missing dependencies
|
||||
for _, depend := range entry.Info.Depends {
|
||||
// Split package name and required version
|
||||
dependName, _, _ := SplitPkgNameAndVersion(depend)
|
||||
|
||||
if IsPackageInstalled(dependName, rootDir) && EvaluateDependency(depend, GetPackageInfo(dependName, rootDir).Version) {
|
||||
continue
|
||||
}
|
||||
if len(GetVirtualPackageInfo(dependName, rootDir)) > 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
// Find database entry for missing dependency
|
||||
dependEntry, _, err := GetDatabaseEntry(dependName)
|
||||
if err != nil {
|
||||
providers := GetDatabaseVirtualPackageEntry(dependName)
|
||||
if len(providers) == 0 {
|
||||
pkgsNotFound = append(pkgsNotFound, depend)
|
||||
continue
|
||||
}
|
||||
|
||||
dependEntry = providers[0]
|
||||
}
|
||||
|
||||
// Skip dependency if action already exists
|
||||
if operation.ActionsContainPackage(dependEntry.Info.Name) {
|
||||
continue
|
||||
}
|
||||
|
||||
// Skip dependency if ignored in config
|
||||
if slices.Contains(MainBPMConfig.IgnorePackages, dependEntry.Info.Name) {
|
||||
continue
|
||||
}
|
||||
|
||||
// Ensure entry has required version
|
||||
if !EvaluateDependency(depend, dependEntry.Info.Version) {
|
||||
pkgsNotFound = append(pkgsNotFound, depend)
|
||||
continue
|
||||
}
|
||||
|
||||
// Fetch dependency
|
||||
operation.AppendAction(&FetchPackageAction{
|
||||
InstallationReason: InstallationReasonDependency,
|
||||
DatabaseEntry: dependEntry,
|
||||
})
|
||||
}
|
||||
|
||||
// Check for missing runtime dependencies
|
||||
for _, depend := range entry.Info.RuntimeDepends {
|
||||
// Split package name and required version
|
||||
dependName, _, _ := SplitPkgNameAndVersion(depend)
|
||||
|
||||
if IsPackageInstalled(dependName, rootDir) && EvaluateDependency(depend, GetPackageInfo(dependName, rootDir).Version) {
|
||||
continue
|
||||
}
|
||||
if len(GetVirtualPackageInfo(dependName, rootDir)) > 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
// Find database entry for missing dependency
|
||||
dependEntry, _, err := GetDatabaseEntry(dependName)
|
||||
if err != nil {
|
||||
providers := GetDatabaseVirtualPackageEntry(dependName)
|
||||
if len(providers) == 0 {
|
||||
pkgsNotFound = append(pkgsNotFound, depend)
|
||||
continue
|
||||
}
|
||||
|
||||
dependEntry = providers[0]
|
||||
}
|
||||
|
||||
// Skip dependency if ignored in config
|
||||
if slices.Contains(MainBPMConfig.IgnorePackages, dependEntry.Info.Name) {
|
||||
continue
|
||||
}
|
||||
|
||||
// Ensure entry has required version
|
||||
if !EvaluateDependency(depend, dependEntry.Info.Version) {
|
||||
pkgsNotFound = append(pkgsNotFound, depend)
|
||||
continue
|
||||
}
|
||||
|
||||
// Fetch dependency
|
||||
operation.AppendAction(&FetchPackageAction{
|
||||
InstallationReason: InstallationReasonDependency,
|
||||
DatabaseEntry: dependEntry,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check for new dependencies in updated packages
|
||||
operation.ResolveDependencies(true, installOptionalDependencies)
|
||||
if len(operation.UnresolvedDepends) != 0 {
|
||||
if !forceInstallation {
|
||||
return nil, DependencyNotFoundErr{operation.UnresolvedDepends}
|
||||
} else if verbose {
|
||||
log.Printf("Warning: %s", DependencyNotFoundErr{operation.UnresolvedDepends})
|
||||
}
|
||||
// Return error if not all packages are found
|
||||
if len(pkgsNotFound) != 0 {
|
||||
return nil, PackageNotFoundErr{pkgsNotFound}
|
||||
}
|
||||
|
||||
// Replace obsolete packages
|
||||
|
||||
+40
-61
@@ -1,26 +1,27 @@
|
||||
package bpmlib
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"gopkg.in/yaml.v3"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"slices"
|
||||
"strings"
|
||||
"syscall"
|
||||
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
type BPMHook struct {
|
||||
SourcePath string
|
||||
SourceContent string
|
||||
TriggerOperations []string `yaml:"trigger_operations"`
|
||||
TargetType string `yaml:"target_type"`
|
||||
TriggerActions []string `yaml:"trigger_actions"`
|
||||
TriggerPreOperation bool `yaml:"trigger_pre_operation"`
|
||||
Targets []string `yaml:"targets"`
|
||||
Depends []string `yaml:"depends"`
|
||||
Run string `yaml:"run"`
|
||||
PassTargets bool `yaml:"pass_targets"`
|
||||
}
|
||||
|
||||
// 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{
|
||||
SourcePath: sourcePath,
|
||||
SourceContent: string(bytes),
|
||||
TriggerOperations: nil,
|
||||
TargetType: "",
|
||||
TriggerActions: nil,
|
||||
Targets: nil,
|
||||
Depends: nil,
|
||||
Run: "",
|
||||
}
|
||||
|
||||
@@ -61,19 +60,15 @@ func (hook *BPMHook) IsValid() error {
|
||||
ValidOperations := []string{"install", "upgrade", "remove"}
|
||||
|
||||
// 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")
|
||||
}
|
||||
for _, operation := range hook.TriggerOperations {
|
||||
for _, operation := range hook.TriggerActions {
|
||||
if !slices.Contains(ValidOperations, operation) {
|
||||
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 {
|
||||
return errors.New("command to run is empty")
|
||||
}
|
||||
@@ -83,55 +78,30 @@ func (hook *BPMHook) IsValid() error {
|
||||
}
|
||||
|
||||
// Execute hook if all conditions are met
|
||||
func (hook *BPMHook) Execute(packageChanges map[string]string, 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...)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func (hook *BPMHook) Execute(modifiedFiles map[string]string, preOperation bool, verbose bool, rootDir string) error {
|
||||
// Check if any targets are met
|
||||
targetMet := false
|
||||
targetsMet := make([]string, 0)
|
||||
for _, target := range hook.Targets {
|
||||
if targetMet {
|
||||
break
|
||||
for modifiedFile, action := range modifiedFiles {
|
||||
// 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 {
|
||||
if target == change && slices.Contains(hook.TriggerOperations, operation) {
|
||||
targetMet = true
|
||||
break
|
||||
|
||||
// Check if file has already been checked
|
||||
if slices.Contains(targetsMet, modifiedFile) {
|
||||
continue
|
||||
}
|
||||
|
||||
if matched, _ := filepath.Match(target, modifiedFile); !matched {
|
||||
continue
|
||||
}
|
||||
|
||||
targetsMet = append(targetsMet, modifiedFile)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
glob, err := filepath.Glob(path.Join(rootDir, target))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, change := range modifiedFiles {
|
||||
if slices.Contains(glob, path.Join(rootDir, change.Path)) {
|
||||
targetMet = true
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if !targetMet {
|
||||
|
||||
if len(targetsMet) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -140,16 +110,25 @@ func (hook *BPMHook) Execute(packageChanges map[string]string, verbose bool, roo
|
||||
cmd := exec.Command(splitCommand[0], splitCommand[1:]...)
|
||||
// Setup subprocess environment
|
||||
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
|
||||
if rootDir != "/" {
|
||||
cmd.SysProcAttr = &syscall.SysProcAttr{Chroot: rootDir}
|
||||
}
|
||||
|
||||
if verbose {
|
||||
fmt.Printf("Running hook (%s) with run command: %s\n", hook.SourcePath, strings.Join(splitCommand, " "))
|
||||
if !verbose {
|
||||
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 {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"slices"
|
||||
"strconv"
|
||||
"strings"
|
||||
@@ -103,6 +104,41 @@ func GetInstalledPackages(rootDir string) (ret []string, err error) {
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func GetPathOwners(path, rootDir string) (ret []string, err error) {
|
||||
// Get absolte path to path
|
||||
path, err = filepath.Abs(path)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
path, err = filepath.Rel(rootDir, path)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Trim leading and trailing slashes
|
||||
path = strings.TrimLeft(path, "/")
|
||||
path = strings.TrimRight(path, "/")
|
||||
|
||||
// Get installed packages
|
||||
pkgs, err := GetInstalledPackages(rootDir)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Add packages that own path to list
|
||||
for _, pkg := range pkgs {
|
||||
pkgFiles := getPackageFiles(pkg, rootDir)
|
||||
if slices.ContainsFunc(pkgFiles, func(entry *PackageFileEntry) bool {
|
||||
return entry.Path == path
|
||||
}) {
|
||||
ret = append(ret, pkg)
|
||||
}
|
||||
}
|
||||
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func IsPackageInstalled(pkg, rootDir string) bool {
|
||||
// Initialize local package information
|
||||
err := InitializeLocalPackageInformation(rootDir)
|
||||
|
||||
+83
-51
@@ -14,7 +14,7 @@ import (
|
||||
type BPMOperation struct {
|
||||
Actions []OperationAction
|
||||
UnresolvedDepends []string
|
||||
Changes map[string]string
|
||||
ModifiedFiles map[string]string
|
||||
CompilationJobs int
|
||||
RunChecks bool
|
||||
RootDir string
|
||||
@@ -53,24 +53,6 @@ func (operation *BPMOperation) InsertActionAt(index int, action OperationAction)
|
||||
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) {
|
||||
@@ -131,7 +113,7 @@ func (operation *BPMOperation) GetFinalActionSize(rootDir string) int64 {
|
||||
return ret
|
||||
}
|
||||
|
||||
func (operation *BPMOperation) ResolveDependencies(installRuntimeDepends, installOptionalDependencies bool) {
|
||||
func (operation *BPMOperation) ResolveDependencies(installRuntimeDepends bool) {
|
||||
// Discover resolved virtual packages
|
||||
resolvedVirtualPackages := make(map[string]string)
|
||||
for _, value := range slices.Clone(operation.Actions) {
|
||||
@@ -167,7 +149,7 @@ func (operation *BPMOperation) ResolveDependencies(installRuntimeDepends, instal
|
||||
continue
|
||||
}
|
||||
|
||||
resolved, unresolved := ResolveDependencies(pkgInfo, resolvedVirtualPackages, installRuntimeDepends, installOptionalDependencies, operation.RootDir)
|
||||
resolved, unresolved := ResolveDependencies(pkgInfo, resolvedVirtualPackages, installRuntimeDepends, operation.RootDir)
|
||||
|
||||
// Append unresolved dependencies
|
||||
operation.UnresolvedDepends = append(operation.UnresolvedDepends, unresolved...)
|
||||
@@ -194,30 +176,6 @@ func (operation *BPMOperation) ResolveDependencies(installRuntimeDepends, instal
|
||||
}
|
||||
}
|
||||
|
||||
func (operation *BPMOperation) RemoveNeededPackages() error {
|
||||
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 {
|
||||
// Get all installed packages
|
||||
installedPackageNames, err := GetInstalledPackages(operation.RootDir)
|
||||
@@ -274,6 +232,9 @@ func (operation *BPMOperation) Cleanup(cleanupMakeDepends bool) error {
|
||||
|
||||
// Loop through all dependencies
|
||||
for _, depend := range depends {
|
||||
// Remove required version
|
||||
depend, _, _ = SplitPkgNameAndVersion(depend)
|
||||
|
||||
// Resolve dependency
|
||||
var dependPkgInfo *PackageInfo
|
||||
if providers := GetVirtualPackageInfo(depend, operation.RootDir); len(providers) > 0 {
|
||||
@@ -540,16 +501,24 @@ func (operation *BPMOperation) GetOptionalDependencies() (optionalDepends map[st
|
||||
}
|
||||
|
||||
for _, depend := range pkgInfo.OptionalDepends {
|
||||
// Get optional dependency name
|
||||
dependSplit := strings.SplitN(depend, ":", 2)
|
||||
dependName, _, _ := SplitPkgNameAndVersion(dependSplit[0])
|
||||
|
||||
// Skip if dependency is already installed
|
||||
if IsPackageInstalled(dependSplit[0], operation.RootDir) {
|
||||
if IsPackageInstalled(dependName, operation.RootDir) {
|
||||
continue
|
||||
}
|
||||
|
||||
// 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 {
|
||||
return strings.SplitN(n, ":", 2)[0] == dependSplit[0]
|
||||
// Remove optional dependency comment
|
||||
n = strings.SplitN(n, ":", 2)[0]
|
||||
|
||||
// Remove required version
|
||||
n, _, _ = SplitPkgNameAndVersion(n)
|
||||
|
||||
return n == dependName
|
||||
}) {
|
||||
continue
|
||||
}
|
||||
@@ -557,7 +526,7 @@ func (operation *BPMOperation) GetOptionalDependencies() (optionalDepends map[st
|
||||
if len(dependSplit) == 2 {
|
||||
optionalDepends[pkgInfo.Name] = append(optionalDepends[pkgInfo.Name], fmt.Sprintf("%s (%s)", dependSplit[0], dependSplit[1]))
|
||||
} else {
|
||||
optionalDepends[pkgInfo.Name] = append(optionalDepends[pkgInfo.Name], dependSplit[0])
|
||||
optionalDepends[pkgInfo.Name] = append(optionalDepends[pkgInfo.Name], dependName)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -565,7 +534,7 @@ func (operation *BPMOperation) GetOptionalDependencies() (optionalDepends map[st
|
||||
return
|
||||
}
|
||||
|
||||
func (operation *BPMOperation) RunHooks(verbose bool) error {
|
||||
func (operation *BPMOperation) RunPreHooks(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
|
||||
@@ -585,7 +554,46 @@ func (operation *BPMOperation) RunHooks(verbose bool) error {
|
||||
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 {
|
||||
log.Printf("Warning: could not execute hook (%s): %s\n", entry.Name(), err)
|
||||
continue
|
||||
@@ -669,9 +677,34 @@ func (operation *BPMOperation) FetchPackages() (err error) {
|
||||
}
|
||||
|
||||
operation.hasFetchedPackages = true
|
||||
|
||||
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)
|
||||
|
||||
for _, pkgFile := range installAction.BpmPackage.PkgFiles {
|
||||
operation.ModifiedFiles[pkgFile.Path] = "install"
|
||||
if isUpgrade {
|
||||
operation.ModifiedFiles[pkgFile.Path] = "upgrade"
|
||||
}
|
||||
}
|
||||
}
|
||||
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) {
|
||||
// Fetch packages
|
||||
if !operation.hasFetchedPackages {
|
||||
@@ -764,7 +797,6 @@ func (operation *BPMOperation) Execute(verbose, force bool) (err error) {
|
||||
}
|
||||
}
|
||||
}
|
||||
fmt.Println("Operation complete!")
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
+102
-31
@@ -10,6 +10,7 @@ import (
|
||||
"os"
|
||||
"os/exec"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"slices"
|
||||
"sort"
|
||||
@@ -627,7 +628,7 @@ func (pkgInfo *PackageInfo) CreateReadableInfo(rootDir string) string {
|
||||
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)
|
||||
|
||||
// Other package relations
|
||||
@@ -698,6 +699,17 @@ func extractPackage(bpmpkg *BPMPackage, verbose bool, filename, rootDir string)
|
||||
extractFilename := path.Join(rootDir, header.Name)
|
||||
switch header.Typeflag {
|
||||
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
|
||||
}); ok {
|
||||
if verbose {
|
||||
fmt.Printf("Skipping Directory: %s (Path was ignored)\n", extractFilename)
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
if _, err := os.Stat(extractFilename); err == nil {
|
||||
if verbose {
|
||||
fmt.Printf("Skipping Directory: %s (Directory already exists)\n", extractFilename)
|
||||
@@ -725,6 +737,17 @@ func extractPackage(bpmpkg *BPMPackage, verbose bool, filename, rootDir string)
|
||||
}
|
||||
bar.Add64(header.Size)
|
||||
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
|
||||
}); ok {
|
||||
if verbose {
|
||||
fmt.Printf("Skipping File: %s (Path was ignored)\n", extractFilename)
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
skip := false
|
||||
if _, err := os.Stat(extractFilename); err == nil {
|
||||
for _, k := range bpmpkg.PkgInfo.Keep {
|
||||
@@ -782,6 +805,17 @@ func extractPackage(bpmpkg *BPMPackage, verbose bool, filename, rootDir string)
|
||||
}
|
||||
bar.Add64(header.Size)
|
||||
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
|
||||
}); ok {
|
||||
if verbose {
|
||||
fmt.Printf("Skipping Symlink: %s (Path was ignored)\n", extractFilename)
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
err := os.Remove(extractFilename)
|
||||
if err != nil && !os.IsNotExist(err) {
|
||||
return err
|
||||
@@ -797,6 +831,17 @@ func extractPackage(bpmpkg *BPMPackage, verbose bool, filename, rootDir string)
|
||||
}
|
||||
bar.Add64(header.Size)
|
||||
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
|
||||
}); ok {
|
||||
if verbose {
|
||||
fmt.Printf("Skipping Hard Link: %s (Path was ignored)\n", extractFilename)
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
if verbose {
|
||||
fmt.Println("Detected Hard Link: " + extractFilename + " -> " + path.Join(rootDir, strings.TrimPrefix(header.Linkname, "files/")))
|
||||
}
|
||||
@@ -872,26 +917,39 @@ func installPackage(filename string, installationReason InstallationReason, root
|
||||
fmt.Printf("Removing old files for package (%s)...\n", bpmpkg.PkgInfo.Name)
|
||||
}
|
||||
for _, entry := range fileEntries {
|
||||
file := path.Join(rootDir, entry.Path)
|
||||
stat, err := os.Lstat(file)
|
||||
finalPath := path.Join(rootDir, entry.Path)
|
||||
|
||||
stat, err := os.Lstat(finalPath)
|
||||
if os.IsNotExist(err) {
|
||||
continue
|
||||
}
|
||||
if err != nil {
|
||||
} else if err != nil {
|
||||
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
|
||||
}); ok {
|
||||
if verbose {
|
||||
fmt.Println("Skipping path: " + file + " (Path is managed by multiple packages)")
|
||||
fmt.Printf("Skipping path: %s (Path was ignored)\n", finalPath)
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
if len(files[entry.Path]) != 0 {
|
||||
if verbose {
|
||||
fmt.Println("Skipping path: " + finalPath + " (Path is managed by multiple packages)")
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
shouldContinue := false
|
||||
for _, value := range bpmpkg.PkgInfo.Keep {
|
||||
if strings.HasSuffix(value, "/") {
|
||||
if strings.HasPrefix(entry.Path, value) || entry.Path == strings.TrimSuffix(value, "/") {
|
||||
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
|
||||
continue
|
||||
@@ -899,7 +957,7 @@ func installPackage(filename string, installationReason InstallationReason, root
|
||||
} else {
|
||||
if entry.Path == value {
|
||||
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
|
||||
continue
|
||||
@@ -911,37 +969,37 @@ func installPackage(filename string, installationReason InstallationReason, root
|
||||
}
|
||||
if stat.Mode()&os.ModeSymlink != 0 {
|
||||
if verbose {
|
||||
fmt.Println("Removing: " + file)
|
||||
fmt.Println("Removing: " + finalPath)
|
||||
}
|
||||
err := os.Remove(file)
|
||||
err := os.Remove(finalPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
continue
|
||||
}
|
||||
if stat.IsDir() {
|
||||
dir, err := os.ReadDir(file)
|
||||
dir, err := os.ReadDir(finalPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(dir) != 0 {
|
||||
if verbose {
|
||||
fmt.Println("Skipping non-empty directory: " + file)
|
||||
fmt.Println("Skipping non-empty directory: " + finalPath)
|
||||
}
|
||||
continue
|
||||
}
|
||||
if verbose {
|
||||
fmt.Println("Removing: " + file)
|
||||
fmt.Println("Removing: " + finalPath)
|
||||
}
|
||||
err = os.Remove(file)
|
||||
err = os.Remove(finalPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
if verbose {
|
||||
fmt.Println("Removing: " + file)
|
||||
fmt.Println("Removing: " + finalPath)
|
||||
}
|
||||
err := os.Remove(file)
|
||||
err := os.Remove(finalPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -1111,31 +1169,44 @@ func removePackage(pkg string, verbose bool, rootDir string) error {
|
||||
// Removing package files
|
||||
for _, entry := range fileEntries {
|
||||
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) {
|
||||
continue
|
||||
}
|
||||
if err != nil {
|
||||
} else if err != nil {
|
||||
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
|
||||
}); ok {
|
||||
if verbose {
|
||||
fmt.Printf("Skipping path: %s (Path was ignored)\n", finalPath)
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
if len(files[entry.Path]) != 0 {
|
||||
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
|
||||
}
|
||||
if lstat.Mode()&os.ModeSymlink != 0 {
|
||||
if verbose {
|
||||
fmt.Println("Removing: " + file)
|
||||
fmt.Println("Removing: " + finalPath)
|
||||
}
|
||||
err := os.Remove(file)
|
||||
err := os.Remove(finalPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
continue
|
||||
}
|
||||
stat, err := os.Stat(file)
|
||||
stat, err := os.Stat(finalPath)
|
||||
if os.IsNotExist(err) {
|
||||
continue
|
||||
}
|
||||
@@ -1143,28 +1214,28 @@ func removePackage(pkg string, verbose bool, rootDir string) error {
|
||||
return err
|
||||
}
|
||||
if stat.IsDir() {
|
||||
dir, err := os.ReadDir(file)
|
||||
dir, err := os.ReadDir(finalPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(dir) != 0 {
|
||||
if verbose {
|
||||
fmt.Println("Skipping non-empty directory: " + file)
|
||||
fmt.Println("Skipping non-empty directory: " + finalPath)
|
||||
}
|
||||
continue
|
||||
}
|
||||
if verbose {
|
||||
fmt.Println("Removing: " + file)
|
||||
fmt.Println("Removing: " + finalPath)
|
||||
}
|
||||
err = os.Remove(file)
|
||||
err = os.Remove(finalPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
if verbose {
|
||||
fmt.Println("Removing: " + file)
|
||||
fmt.Println("Removing: " + finalPath)
|
||||
}
|
||||
err := os.Remove(file)
|
||||
err := os.Remove(finalPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user