Просмотр исходного кода

Merge pull request #275 from ratorx/master

Recursively remove dependencies when using yay -Yc
Morgana 7 лет назад
Родитель
Сommit
13ef6f66ab
5 измененных файлов с 94 добавлено и 18 удалено
  1. 1 1
      Gopkg.lock
  2. 2 8
      clean.go
  3. 3 1
      cmd.go
  4. 73 8
      query.go
  5. 15 0
      vendor/github.com/jguer/go-alpm/package.go

+ 1 - 1
Gopkg.lock

@@ -5,7 +5,7 @@
   branch = "master"
   name = "github.com/jguer/go-alpm"
   packages = ["."]
-  revision = "ec031c9cd5f6050edc3c2f23df2bff3bbb9511cc"
+  revision = "bc954af9b2ced79e4db54ce6ab3c6a24d769e98b"
 
 [[projects]]
   branch = "master"

+ 2 - 8
clean.go

@@ -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
 }

+ 3 - 1
cmd.go

@@ -323,8 +323,10 @@ func handleYay() (err error) {
 	//_, options, targets := cmdArgs.formatArgs()
 	if cmdArgs.existsArg("gendb") {
 		err = createDevelDB()
+	} 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()
 	}

+ 73 - 8
query.go

@@ -313,26 +313,91 @@ 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
+	provides := make(map[string]stringSet)
+	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 {
+			addMapStringSet(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 pset, ok2 := provides[dep.Name]; ok2 {
+					for p := range pset {
+						if safePackages[p] == 0 {
+							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
 }
 

+ 15 - 0
vendor/github.com/jguer/go-alpm/package.go

@@ -282,6 +282,21 @@ func (pkg Package) ComputeRequiredBy() []string {
 	return requiredby
 }
 
+// ComputeOptionalFor returns the names of packages that optionally require the given package
+func (pkg Package) ComputeOptionalFor() []string {
+	result := C.alpm_pkg_compute_optionalfor(pkg.pmpkg)
+	optionalfor := make([]string, 0)
+	for i := (*list)(unsafe.Pointer(result)); i != nil; i = i.Next {
+		defer C.free(unsafe.Pointer(i))
+		if i.Data != nil {
+			defer C.free(unsafe.Pointer(i.Data))
+			name := C.GoString((*C.char)(unsafe.Pointer(i.Data)))
+			optionalfor = append(optionalfor, name)
+		}
+	}
+	return optionalfor
+}
+
 // NewVersion checks if there is a new version of the package in the Synced DBs.
 func (pkg Package) NewVersion(l DbList) *Package {
 	ptr := C.alpm_sync_newversion(pkg.pmpkg,