mirror of
https://github.com/EnumeratedDev/bpm.git
synced 2026-09-16 02:26:12 +00:00
Change remove subcommand behaviour to show error when breaking installed package dependencies
This commit is contained in:
+9
-3
@@ -92,7 +92,6 @@ func main() {
|
|||||||
currentFlagSet.BoolP("verbose", "v", false, "Show additional information about the current operation")
|
currentFlagSet.BoolP("verbose", "v", false, "Show additional information about the current operation")
|
||||||
currentFlagSet.BoolP("force", "f", false, "Bypass warnings during package removal")
|
currentFlagSet.BoolP("force", "f", false, "Bypass warnings during package removal")
|
||||||
currentFlagSet.BoolP("yes", "y", false, "Enter 'yes' in all prompts")
|
currentFlagSet.BoolP("yes", "y", false, "Enter 'yes' in all prompts")
|
||||||
currentFlagSet.BoolP("unused", "u", false, "Remove packages only if they are not required as dependencies")
|
|
||||||
currentFlagSet.BoolP("cleanup", "n", false, "Additionally remove all unused dependencies")
|
currentFlagSet.BoolP("cleanup", "n", false, "Additionally remove all unused dependencies")
|
||||||
setupFlagsAndHelp(currentFlagSet, fmt.Sprintf("bpm %s <options>", subcommand), "Remove the specified packages", os.Args[2:])
|
setupFlagsAndHelp(currentFlagSet, fmt.Sprintf("bpm %s <options>", subcommand), "Remove the specified packages", os.Args[2:])
|
||||||
|
|
||||||
@@ -496,7 +495,6 @@ func removePackages() {
|
|||||||
verbose, _ := currentFlagSet.GetBool("verbose")
|
verbose, _ := currentFlagSet.GetBool("verbose")
|
||||||
force, _ := currentFlagSet.GetBool("force")
|
force, _ := currentFlagSet.GetBool("force")
|
||||||
yesAll, _ := currentFlagSet.GetBool("yes")
|
yesAll, _ := currentFlagSet.GetBool("yes")
|
||||||
removeUnused, _ := currentFlagSet.GetBool("unused")
|
|
||||||
cleanupPackages, _ := currentFlagSet.GetBool("cleanup")
|
cleanupPackages, _ := currentFlagSet.GetBool("cleanup")
|
||||||
|
|
||||||
// Get packages
|
// Get packages
|
||||||
@@ -527,8 +525,16 @@ func removePackages() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Create remove operation
|
// Create remove operation
|
||||||
operation, err := bpmlib.RemovePackages(rootDir, removeUnused, cleanupPackages, packages...)
|
operation, err := bpmlib.RemovePackages(rootDir, force, cleanupPackages, packages...)
|
||||||
if errors.As(err, &bpmlib.PackageNotFoundErr{}) || errors.As(err, &bpmlib.DependencyNotFoundErr{}) || errors.As(err, &bpmlib.PackageConflictErr{}) {
|
if errors.As(err, &bpmlib.PackageNotFoundErr{}) || errors.As(err, &bpmlib.DependencyNotFoundErr{}) || errors.As(err, &bpmlib.PackageConflictErr{}) {
|
||||||
|
log.Printf("Error: %s", err)
|
||||||
|
exitCode = 1
|
||||||
|
return
|
||||||
|
} else if errors.As(err, &bpmlib.PackageRemovalDependencyErr{}) {
|
||||||
|
for pkg, dependants := range err.(bpmlib.PackageRemovalDependencyErr).RequiredPackages {
|
||||||
|
fmt.Printf("The following packages depend on package (%s): %s\n", pkg, strings.Join(dependants, ", "))
|
||||||
|
}
|
||||||
|
|
||||||
log.Printf("Error: %s", err)
|
log.Printf("Error: %s", err)
|
||||||
exitCode = 1
|
exitCode = 1
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -198,12 +198,9 @@ func GetPackageDependants(pkgName string, rootDir string) ([]string, error) {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get installed package dependencies
|
|
||||||
dependencies := installedPkg.PkgInfo.GetDependencies(false, true)
|
|
||||||
|
|
||||||
// Add installed package to list if its dependencies include pkgName
|
// Add installed package to list if its dependencies include pkgName
|
||||||
if slices.ContainsFunc(dependencies, func(p pkgInstallationReason) bool {
|
if slices.ContainsFunc(installedPkg.PkgInfo.Depends, func(n string) bool {
|
||||||
return p.PkgName == pkgName
|
return n == pkgName
|
||||||
}) {
|
}) {
|
||||||
ret = append(ret, installedPkgName)
|
ret = append(ret, installedPkgName)
|
||||||
continue
|
continue
|
||||||
@@ -212,8 +209,8 @@ func GetPackageDependants(pkgName string, rootDir string) ([]string, error) {
|
|||||||
// Loop through each virtual package
|
// Loop through each virtual package
|
||||||
for _, vpkg := range pkg.PkgInfo.Provides {
|
for _, vpkg := range pkg.PkgInfo.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(dependencies, func(p pkgInstallationReason) bool {
|
if slices.ContainsFunc(installedPkg.PkgInfo.Depends, func(n string) bool {
|
||||||
return p.PkgName == vpkg
|
return n == vpkg
|
||||||
}) {
|
}) {
|
||||||
ret = append(ret, installedPkgName)
|
ret = append(ret, installedPkgName)
|
||||||
break
|
break
|
||||||
|
|||||||
@@ -40,3 +40,11 @@ type PackageScriptErr struct {
|
|||||||
func (e PackageScriptErr) Error() string {
|
func (e PackageScriptErr) Error() string {
|
||||||
return fmt.Sprintf("could not execute package script (%s) for package (%s): %s", e.packageScript, e.packageName, e.err)
|
return fmt.Sprintf("could not execute package script (%s) for package (%s): %s", e.packageScript, e.packageName, e.err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type PackageRemovalDependencyErr struct {
|
||||||
|
RequiredPackages map[string][]string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e PackageRemovalDependencyErr) Error() string {
|
||||||
|
return "removing these package would break other installed packages"
|
||||||
|
}
|
||||||
|
|||||||
+36
-9
@@ -4,6 +4,7 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
|
"maps"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
"slices"
|
"slices"
|
||||||
@@ -186,7 +187,7 @@ func InstallPackages(rootDir string, forceInstallationReason InstallationReason,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// RemovePackages removes the specified packages from the given root directory
|
// RemovePackages removes the specified packages from the given root directory
|
||||||
func RemovePackages(rootDir string, removeUnusedPackagesOnly, cleanupDependencies bool, packages ...string) (operation *BPMOperation, err error) {
|
func RemovePackages(rootDir string, force, cleanupDependencies bool, packages ...string) (operation *BPMOperation, err error) {
|
||||||
operation = &BPMOperation{
|
operation = &BPMOperation{
|
||||||
Actions: make([]OperationAction, 0),
|
Actions: make([]OperationAction, 0),
|
||||||
UnresolvedDepends: make([]string, 0),
|
UnresolvedDepends: make([]string, 0),
|
||||||
@@ -204,14 +205,6 @@ func RemovePackages(rootDir string, removeUnusedPackagesOnly, cleanupDependencie
|
|||||||
operation.AppendAction(&RemovePackageAction{BpmPackage: bpmpkg})
|
operation.AppendAction(&RemovePackageAction{BpmPackage: bpmpkg})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Do not remove packages which other packages depend on
|
|
||||||
if removeUnusedPackagesOnly {
|
|
||||||
err := operation.RemoveNeededPackages()
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("could not skip needed packages: %s", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Do package cleanup
|
// Do package cleanup
|
||||||
if cleanupDependencies {
|
if cleanupDependencies {
|
||||||
err := operation.Cleanup(true)
|
err := operation.Cleanup(true)
|
||||||
@@ -219,6 +212,40 @@ func RemovePackages(rootDir string, removeUnusedPackagesOnly, cleanupDependencie
|
|||||||
return nil, fmt.Errorf("could not perform cleanup for operation: %s", err)
|
return nil, fmt.Errorf("could not perform cleanup for operation: %s", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Return error if other packages depend on removed ones
|
||||||
|
if !force {
|
||||||
|
// Get packages and their dependants
|
||||||
|
packageDepndants := make(map[string][]string, 0)
|
||||||
|
for _, action := range operation.Actions {
|
||||||
|
dependants, err := GetPackageDependants(action.(*RemovePackageAction).BpmPackage.PkgInfo.Name, rootDir)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("could not get package dependants: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
packageDepndants[action.(*RemovePackageAction).BpmPackage.PkgInfo.Name] = dependants
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove dependant packages from map if they are to be removed by this operation
|
||||||
|
for pkg, required := range packageDepndants {
|
||||||
|
required = slices.DeleteFunc(required, func(pkgName string) bool {
|
||||||
|
_, ok := packageDepndants[pkgName]
|
||||||
|
return ok
|
||||||
|
})
|
||||||
|
packageDepndants[pkg] = required
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove empty keys from map
|
||||||
|
maps.DeleteFunc(packageDepndants, func(pkg string, required []string) bool {
|
||||||
|
return len(required) == 0
|
||||||
|
})
|
||||||
|
|
||||||
|
// Return error
|
||||||
|
if len(packageDepndants) != 0 {
|
||||||
|
return nil, PackageRemovalDependencyErr{RequiredPackages: packageDepndants}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return operation, nil
|
return operation, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user