Add recursive removal of packages

This commit is contained in:
Reeto Chatterjee 2018-03-23 23:45:46 +00:00
parent 8a0bade6cd
commit 1b704a869d
3 changed files with 76 additions and 17 deletions

View File

@ -20,16 +20,13 @@ func removeVCSPackage(pkgs []string) {
}
// CleanDependencies removes all dangling dependencies in system
func cleanDependencies() error {
hanging, err := hangingPackages()
func cleanDependencies(removeOptional bool) error {
hanging, err := hangingPackages(removeOptional)
if err != nil {
return err
}
if len(hanging) != 0 {
if !continueTask("Confirm Removal?", "nN") {
return nil
}
err = cleanRemove(hanging)
}
@ -42,12 +39,9 @@ func cleanRemove(pkgNames []string) (err error) {
return nil
}
oldvalue := config.NoConfirm
config.NoConfirm = true
arguments := makeArguments()
arguments.addArg("R")
arguments.addTarget(pkgNames...)
err = passToPacman(arguments)
config.NoConfirm = oldvalue
return err
}

4
cmd.go
View File

@ -291,8 +291,10 @@ func handleYay() (err error) {
if err != nil {
return
}
} else if cmdArgs.existsDouble("c") {
err = cleanDependencies(true)
} else if cmdArgs.existsArg("c", "clean") {
err = cleanDependencies()
err = cleanDependencies(false)
} else if len(cmdArgs.targets) > 0 {
err = handleYogurt()
}

View File

@ -274,26 +274,89 @@ func packageSlices(toCheck []string) (aur []string, repo []string, err error) {
// HangingPackages returns a list of packages installed as deps
// and unneeded by the system
func hangingPackages() (hanging []string, err error) {
// removeOptional decides whether optional dependencies are counted or not
func hangingPackages(removeOptional bool) (hanging []string, err error) {
localDb, err := alpmHandle.LocalDb()
if err != nil {
return
}
f := func(pkg alpm.Package) error {
if pkg.Reason() != alpm.PkgReasonDepend {
// safePackages represents every package in the system in one of 3 states
// State = 0 - Remove package from the system
// State = 1 - Keep package in the system; need to iterate over dependencies
// State = 2 - Keep package and have iterated over dependencies
safePackages := make(map[string]uint8)
// provides stores a mapping from the provides name back to the original package name
// Assumption - multiple installed packages don't provide the same dependency
provides := make(map[string]string)
packages := localDb.PkgCache()
// Mark explicit dependencies and enumerate the provides list
setupResources := func(pkg alpm.Package) error {
if pkg.Reason() == alpm.PkgReasonExplicit {
safePackages[pkg.Name()] = 1
} else {
safePackages[pkg.Name()] = 0
}
pkg.Provides().ForEach(func(dep alpm.Depend) error {
provides[dep.Name] = pkg.Name()
return nil
})
return nil
}
packages.ForEach(setupResources)
iterateAgain := true
processDependencies := func(pkg alpm.Package) error {
if state, _ := safePackages[pkg.Name()]; state == 0 || state == 2 {
return nil
}
requiredby := pkg.ComputeRequiredBy()
if len(requiredby) == 0 {
hanging = append(hanging, pkg.Name())
fmt.Println(pkg.Name() + ": " + magenta(human(pkg.ISize())))
safePackages[pkg.Name()] = 2
// Update state for dependencies
markDependencies := func(dep alpm.Depend) error {
// Don't assume a dependency is installed
state, ok := safePackages[dep.Name]
if !ok {
// Check if dep is a provides rather than actual package name
if p, ok2 := provides[dep.Name]; ok2 {
iterateAgain = true
safePackages[p] = 1
}
return nil
}
if state == 0 {
iterateAgain = true
safePackages[dep.Name] = 1
}
return nil
}
pkg.Depends().ForEach(markDependencies)
if !removeOptional {
pkg.OptionalDepends().ForEach(markDependencies)
}
return nil
}
err = localDb.PkgCache().ForEach(f)
for iterateAgain {
iterateAgain = false
packages.ForEach(processDependencies)
}
// Build list of packages to be removed
packages.ForEach(func(pkg alpm.Package) error {
if safePackages[pkg.Name()] == 0 {
hanging = append(hanging, pkg.Name())
}
return nil
})
return
}