3 Commits
8 changed files with 461 additions and 173 deletions
+72 -16
View File
@@ -662,6 +662,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 +687,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 +704,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
@@ -801,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 // Execute operation
err = operation.Execute(verbose, force) err = operation.Execute(verbose, force)
if err != nil { if err != nil {
@@ -809,14 +835,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() {
@@ -922,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 // Execute operation
err = operation.Execute(verbose, force) err = operation.Execute(verbose, force)
if err != nil { if err != nil {
@@ -930,14 +970,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!")
} }
} }
@@ -1083,6 +1125,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()
@@ -1105,6 +1150,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 {
@@ -1113,15 +1167,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
+1
View File
@@ -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"`
+15 -2
View File
@@ -311,6 +311,7 @@ func (entry *BPMDatabaseEntry) GetEntryDependants() (dependants []string) {
// Add installed package to list if its dependencies include pkgName // Add installed package to list if its dependencies include pkgName
if slices.ContainsFunc(e.Info.Depends, func(n string) bool { if slices.ContainsFunc(e.Info.Depends, func(n string) bool {
n, _, _ = SplitPkgNameAndVersion(n)
return n == entry.Info.Name return n == entry.Info.Name
}) { }) {
dependantsMap[e.Info.Name] = append(dependantsMap[e.Info.Name], db.Name) dependantsMap[e.Info.Name] = append(dependantsMap[e.Info.Name], db.Name)
@@ -319,6 +320,7 @@ func (entry *BPMDatabaseEntry) GetEntryDependants() (dependants []string) {
// 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(e.Info.RuntimeDepends, func(n string) bool { if slices.ContainsFunc(e.Info.RuntimeDepends, func(n string) bool {
n, _, _ = SplitPkgNameAndVersion(n)
return n == entry.Info.Name return n == entry.Info.Name
}) { }) {
dependantsMap[e.Info.Name] = append(dependantsMap[e.Info.Name], db.Name) dependantsMap[e.Info.Name] = append(dependantsMap[e.Info.Name], db.Name)
@@ -329,6 +331,7 @@ func (entry *BPMDatabaseEntry) GetEntryDependants() (dependants []string) {
for _, vpkg := range entry.Info.Provides { for _, vpkg := range entry.Info.Provides {
// 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(e.Info.Depends, func(n string) bool { if slices.ContainsFunc(e.Info.Depends, func(n string) bool {
n, _, _ = SplitPkgNameAndVersion(n)
return n == vpkg return n == vpkg
}) { }) {
dependantsMap[e.Info.Name] = append(dependantsMap[e.Info.Name], db.Name) dependantsMap[e.Info.Name] = append(dependantsMap[e.Info.Name], db.Name)
@@ -337,6 +340,7 @@ func (entry *BPMDatabaseEntry) GetEntryDependants() (dependants []string) {
// 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(e.Info.RuntimeDepends, func(n string) bool { if slices.ContainsFunc(e.Info.RuntimeDepends, func(n string) bool {
n, _, _ = SplitPkgNameAndVersion(n)
return n == vpkg return n == vpkg
}) { }) {
dependantsMap[e.Info.Name] = append(dependantsMap[e.Info.Name], db.Name) dependantsMap[e.Info.Name] = append(dependantsMap[e.Info.Name], db.Name)
@@ -370,7 +374,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 // 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) dependantsMap[e.Info.Name] = append(dependantsMap[e.Info.Name], e.Database.Name)
} }
@@ -400,7 +410,10 @@ 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 {
n, _, _ = SplitPkgNameAndVersion(n)
return n == 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)
} }
} }
+91 -7
View File
@@ -21,6 +21,7 @@ func (pkgInfo *PackageInfo) GetPackageDependants(rootDir string, skipMultiplePro
// 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 {
n, _, _ = SplitPkgNameAndVersion(n)
return n == pkgInfo.Name return n == pkgInfo.Name
}) { }) {
dependants = append(dependants, installedPkg.Name) dependants = append(dependants, installedPkg.Name)
@@ -29,6 +30,7 @@ func (pkgInfo *PackageInfo) GetPackageDependants(rootDir string, skipMultiplePro
// 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 {
n, _, _ = SplitPkgNameAndVersion(n)
return n == pkgInfo.Name return n == pkgInfo.Name
}) { }) {
dependants = append(dependants, installedPkg.Name) dependants = append(dependants, installedPkg.Name)
@@ -43,6 +45,7 @@ func (pkgInfo *PackageInfo) GetPackageDependants(rootDir string, skipMultiplePro
// 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 {
n, _, _ = SplitPkgNameAndVersion(n)
return n == vpkg return n == vpkg
}) { }) {
dependants = append(dependants, installedPkg.Name) dependants = append(dependants, installedPkg.Name)
@@ -51,6 +54,7 @@ func (pkgInfo *PackageInfo) GetPackageDependants(rootDir string, skipMultiplePro
// 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 {
n, _, _ = SplitPkgNameAndVersion(n)
return n == vpkg return n == vpkg
}) { }) {
dependants = append(dependants, installedPkg.Name) dependants = append(dependants, installedPkg.Name)
@@ -78,7 +82,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 // 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) dependants = append(dependants, installedPkg.Name)
continue continue
@@ -88,7 +98,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 // Remove optional dependency comment
n = strings.SplitN(n, ":", 2)[0]
// Remove required version
n, _, _ = SplitPkgNameAndVersion(n)
return n == vpkg
}) { }) {
dependants = append(dependants, installedPkg.Name) dependants = append(dependants, installedPkg.Name)
break break
@@ -111,20 +127,23 @@ func ResolveDependencies(pkgInfo *PackageInfo, resolvedVirtualPackages map[strin
dfs = func(pkgInfo *PackageInfo) { dfs = func(pkgInfo *PackageInfo) {
checkDependencies := func(dependencies []string, installationReason InstallationReason) { checkDependencies := func(dependencies []string, installationReason InstallationReason) {
for _, depend := range dependencies { for _, depend := range dependencies {
// Split dependency name and required version
dependName, _, _ := SplitPkgNameAndVersion(depend)
// Ignore if package is already installed // Ignore if package is already installed
if IsPackageInstalled(depend, rootDir) { if IsPackageInstalled(dependName, rootDir) && EvaluateDependency(depend, GetPackageInfo(dependName, rootDir).Version) {
continue continue
} else if providers := GetVirtualPackageInfo(depend, rootDir); len(providers) > 0 { } else if providers := GetVirtualPackageInfo(dependName, rootDir); len(providers) > 0 {
continue continue
} }
// Find database entry for dependency // Find database entry for dependency
var dependEntry *BPMDatabaseEntry var dependEntry *BPMDatabaseEntry
if resolvedVpkg, ok := resolvedVirtualPackages[depend]; ok { if resolvedVpkg, ok := resolvedVirtualPackages[dependName]; ok {
dependEntry, _, _ = GetDatabaseEntry(resolvedVpkg) dependEntry, _, _ = GetDatabaseEntry(resolvedVpkg)
} else if entry, _, _ := GetDatabaseEntry(depend); entry != nil { } else if entry, _, _ := GetDatabaseEntry(dependName); entry != nil {
dependEntry = entry dependEntry = entry
} else if providers := GetDatabaseVirtualPackageEntry(depend); len(providers) > 0 { } else if providers := GetDatabaseVirtualPackageEntry(dependName); len(providers) > 0 {
dependEntry = providers[0] dependEntry = providers[0]
} }
@@ -133,6 +152,12 @@ func ResolveDependencies(pkgInfo *PackageInfo, resolvedVirtualPackages map[strin
continue continue
} }
// Ensure entry has required version
if !EvaluateDependency(depend, dependEntry.Info.Version) {
unresolved = append(unresolved, depend)
continue
}
// Skip ignored packages in config // Skip ignored packages in config
if slices.Contains(MainBPMConfig.IgnorePackages, dependEntry.Info.Name) { if slices.Contains(MainBPMConfig.IgnorePackages, dependEntry.Info.Name) {
continue continue
@@ -161,3 +186,62 @@ func ResolveDependencies(pkgInfo *PackageInfo, resolvedVirtualPackages map[strin
return resolved, unresolved 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
}
}
+54 -26
View File
@@ -17,7 +17,7 @@ func InstallPackages(rootDir string, forceInstallationReason InstallationReason,
operation = &BPMOperation{ operation = &BPMOperation{
Actions: make([]OperationAction, 0), Actions: make([]OperationAction, 0),
UnresolvedDepends: make([]string, 0), UnresolvedDepends: make([]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),
@@ -81,22 +81,31 @@ func InstallPackages(rootDir string, forceInstallationReason InstallationReason,
BpmPackage: bpmpkg, BpmPackage: bpmpkg,
}) })
} else { } else {
// Split package name and required version
pkgName, _, _ := SplitPkgNameAndVersion(pkg)
var entry *BPMDatabaseEntry var entry *BPMDatabaseEntry
if e, _, err := GetDatabaseEntry(pkg); err == nil { if e, _, err := GetDatabaseEntry(pkgName); err == nil {
entry = e 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) entry, _, err = GetDatabaseEntry(providers[0].Name)
if err != nil { if err != nil {
pkgsNotFound = append(pkgsNotFound, pkg) pkgsNotFound = append(pkgsNotFound, pkg)
continue continue
} }
} else if providers := GetDatabaseVirtualPackageEntry(pkg); len(providers) > 0 { } else if providers := GetDatabaseVirtualPackageEntry(pkgName); len(providers) > 0 {
entry = providers[0] entry = providers[0]
} else { } else {
pkgsNotFound = append(pkgsNotFound, pkg) pkgsNotFound = append(pkgsNotFound, pkg)
continue 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() { if !reinstallPackages && IsPackageInstalled(entry.Info.Name, rootDir) && GetPackageInfo(entry.Info.Name, rootDir).GetFullVersion() == entry.Info.GetFullVersion() {
continue continue
} }
@@ -180,7 +189,7 @@ func RemovePackages(rootDir string, force, cleanupDependencies bool, packages ..
operation = &BPMOperation{ operation = &BPMOperation{
Actions: make([]OperationAction, 0), Actions: make([]OperationAction, 0),
UnresolvedDepends: make([]string, 0), UnresolvedDepends: make([]string, 0),
Changes: make(map[string]string), ModifiedFiles: make(map[string]string),
RootDir: rootDir, RootDir: rootDir,
compiledPackages: make(map[string]string), compiledPackages: make(map[string]string),
} }
@@ -258,7 +267,7 @@ func CleanupPackages(cleanupMakeDepends bool, rootDir string) (operation *BPMOpe
operation = &BPMOperation{ operation = &BPMOperation{
Actions: make([]OperationAction, 0), Actions: make([]OperationAction, 0),
UnresolvedDepends: make([]string, 0), UnresolvedDepends: make([]string, 0),
Changes: make(map[string]string), ModifiedFiles: make(map[string]string),
RootDir: rootDir, RootDir: rootDir,
compiledPackages: make(map[string]string), compiledPackages: make(map[string]string),
} }
@@ -386,7 +395,7 @@ 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([]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),
@@ -419,72 +428,91 @@ func UpdatePackages(rootDir string, syncDatabase, allowDowngrades, forceInstalla
} }
// Check for missing dependencies // Check for missing dependencies
for _, dep := range entry.Info.Depends { for _, depend := range entry.Info.Depends {
if IsPackageInstalled(dep, rootDir) { // Split package name and required version
dependName, _, _ := SplitPkgNameAndVersion(depend)
if IsPackageInstalled(dependName, rootDir) && EvaluateDependency(depend, GetPackageInfo(dependName, rootDir).Version) {
continue continue
} }
if len(GetVirtualPackageInfo(dep, rootDir)) > 0 { if len(GetVirtualPackageInfo(dependName, rootDir)) > 0 {
continue continue
} }
// Find database entry for missing dependency // Find database entry for missing dependency
depEntry, _, err := GetDatabaseEntry(dep) dependEntry, _, err := GetDatabaseEntry(dependName)
if err != nil { if err != nil {
providers := GetDatabaseVirtualPackageEntry(dep) providers := GetDatabaseVirtualPackageEntry(dependName)
if len(providers) == 0 { if len(providers) == 0 {
pkgsNotFound = append(pkgsNotFound, dep) pkgsNotFound = append(pkgsNotFound, depend)
continue continue
} }
depEntry = providers[0] dependEntry = providers[0]
} }
// Skip dependency if action already exists // Skip dependency if action already exists
if operation.ActionsContainPackage(depEntry.Info.Name) { if operation.ActionsContainPackage(dependEntry.Info.Name) {
continue continue
} }
// Skip dependency if ignored in config // Skip dependency if ignored in config
if slices.Contains(MainBPMConfig.IgnorePackages, depEntry.Info.Name) { 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 continue
} }
// Fetch dependency // Fetch dependency
operation.AppendAction(&FetchPackageAction{ operation.AppendAction(&FetchPackageAction{
InstallationReason: InstallationReasonDependency, InstallationReason: InstallationReasonDependency,
DatabaseEntry: depEntry, DatabaseEntry: dependEntry,
}) })
} }
// Check for missing runtime dependencies // Check for missing runtime dependencies
for _, dep := range entry.Info.RuntimeDepends { for _, depend := range entry.Info.RuntimeDepends {
if IsPackageInstalled(dep, rootDir) { // Split package name and required version
dependName, _, _ := SplitPkgNameAndVersion(depend)
if IsPackageInstalled(dependName, rootDir) && EvaluateDependency(depend, GetPackageInfo(dependName, rootDir).Version) {
continue continue
} }
if len(GetVirtualPackageInfo(dep, rootDir)) > 0 { if len(GetVirtualPackageInfo(dependName, rootDir)) > 0 {
continue continue
} }
// Find database entry for missing dependency // Find database entry for missing dependency
depEntry, _, err := GetDatabaseEntry(dep) dependEntry, _, err := GetDatabaseEntry(dependName)
if err != nil { if err != nil {
providers := GetDatabaseVirtualPackageEntry(dep) providers := GetDatabaseVirtualPackageEntry(dependName)
if len(providers) == 0 { if len(providers) == 0 {
pkgsNotFound = append(pkgsNotFound, dep) pkgsNotFound = append(pkgsNotFound, depend)
continue continue
} }
depEntry = providers[0] dependEntry = providers[0]
} }
// Skip dependency if ignored in config // Skip dependency if ignored in config
if slices.Contains(MainBPMConfig.IgnorePackages, depEntry.Info.Name) { 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 continue
} }
// Fetch dependency // Fetch dependency
operation.AppendAction(&FetchPackageAction{ operation.AppendAction(&FetchPackageAction{
InstallationReason: InstallationReasonDependency, InstallationReason: InstallationReasonDependency,
DatabaseEntry: depEntry, DatabaseEntry: dependEntry,
}) })
} }
} }
+46 -67
View File
@@ -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
@@ -33,13 +34,11 @@ func createHook(sourcePath string) (*BPMHook, error) {
// Create base hook structure // Create base hook structure
hook := &BPMHook{ hook := &BPMHook{
SourcePath: sourcePath, SourcePath: sourcePath,
SourceContent: string(bytes), SourceContent: string(bytes),
TriggerOperations: nil, TriggerActions: nil,
TargetType: "", Targets: nil,
Targets: nil, Run: "",
Depends: nil,
Run: "",
} }
// Unmarshal yaml string // Unmarshal yaml string
@@ -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) {
if hook.TargetType == "package" { continue
for change, operation := range packageChanges {
if target == change && slices.Contains(hook.TriggerOperations, operation) {
targetMet = true
break
}
} }
} else {
glob, err := filepath.Glob(path.Join(rootDir, target)) // Check if file has already been checked
if err != nil { if slices.Contains(targetsMet, modifiedFile) {
return err continue
} }
for _, change := range modifiedFiles {
if slices.Contains(glob, path.Join(rootDir, change.Path)) { if matched, _ := filepath.Match(target, modifiedFile); !matched {
targetMet = true continue
break
}
} }
targetsMet = append(targetsMet, modifiedFile)
} }
} }
if !targetMet {
if len(targetsMet) == 0 {
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
} }
+81 -25
View File
@@ -14,7 +14,7 @@ import (
type BPMOperation struct { type BPMOperation struct {
Actions []OperationAction Actions []OperationAction
UnresolvedDepends []string UnresolvedDepends []string
Changes map[string]string ModifiedFiles map[string]string
CompilationJobs int CompilationJobs int
RunChecks bool RunChecks bool
RootDir string 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 = append(operation.Actions[:index+1], operation.Actions[index:]...) // index < len(a)
operation.Actions[index] = action 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) { func (operation *BPMOperation) RemoveAction(pkg, actionType string) {
@@ -250,6 +232,9 @@ func (operation *BPMOperation) Cleanup(cleanupMakeDepends bool) error {
// Loop through all dependencies // Loop through all dependencies
for _, depend := range depends { for _, depend := range depends {
// Remove required version
depend, _, _ = SplitPkgNameAndVersion(depend)
// Resolve dependency // Resolve dependency
var dependPkgInfo *PackageInfo var dependPkgInfo *PackageInfo
if providers := GetVirtualPackageInfo(depend, operation.RootDir); len(providers) > 0 { if providers := GetVirtualPackageInfo(depend, operation.RootDir); len(providers) > 0 {
@@ -516,16 +501,24 @@ func (operation *BPMOperation) GetOptionalDependencies() (optionalDepends map[st
} }
for _, depend := range pkgInfo.OptionalDepends { for _, depend := range pkgInfo.OptionalDepends {
// Get optional dependency name
dependSplit := strings.SplitN(depend, ":", 2) dependSplit := strings.SplitN(depend, ":", 2)
dependName, _, _ := SplitPkgNameAndVersion(dependSplit[0])
// Skip if dependency is already installed // Skip if dependency is already installed
if IsPackageInstalled(dependSplit[0], operation.RootDir) { if IsPackageInstalled(dependName, operation.RootDir) {
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] // Remove optional dependency comment
n = strings.SplitN(n, ":", 2)[0]
// Remove required version
n, _, _ = SplitPkgNameAndVersion(n)
return n == dependName
}) { }) {
continue continue
} }
@@ -533,7 +526,7 @@ func (operation *BPMOperation) GetOptionalDependencies() (optionalDepends map[st
if len(dependSplit) == 2 { if len(dependSplit) == 2 {
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)", dependSplit[0], dependSplit[1]))
} else { } else {
optionalDepends[pkgInfo.Name] = append(optionalDepends[pkgInfo.Name], dependSplit[0]) optionalDepends[pkgInfo.Name] = append(optionalDepends[pkgInfo.Name], dependName)
} }
} }
} }
@@ -541,7 +534,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
@@ -561,7 +554,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
@@ -645,9 +677,34 @@ 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)
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) { func (operation *BPMOperation) Execute(verbose, force bool) (err error) {
// Fetch packages // Fetch packages
if !operation.hasFetchedPackages { if !operation.hasFetchedPackages {
@@ -740,7 +797,6 @@ func (operation *BPMOperation) Execute(verbose, force bool) (err error) {
} }
} }
} }
fmt.Println("Operation complete!")
return nil return nil
} }
+101 -30
View File
@@ -10,6 +10,7 @@ import (
"os" "os"
"os/exec" "os/exec"
"path" "path"
"path/filepath"
"regexp" "regexp"
"slices" "slices"
"sort" "sort"
@@ -698,6 +699,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
}); 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 +737,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
}); 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 +805,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
}); 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 +831,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
}); 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/")))
} }
@@ -872,26 +917,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
}); 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 +957,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 +969,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
} }
@@ -1111,31 +1169,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
}); 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 +1214,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
} }