diff --git a/actions.go b/actions.go index db06c743..fac7cdaa 100644 --- a/actions.go +++ b/actions.go @@ -113,13 +113,19 @@ func NumberMenu(pkgName string, flags []string) (err error) { q.MissingPackage(aurInstall) } + var finalrm []string for _, aurpkg := range q { - err = aurpkg.Install(flags) + finalmdeps, err := aurpkg.Install(flags) + finalrm = append(finalrm, finalmdeps...) if err != nil { // Do not abandon program, we might still be able to install the rest fmt.Println(err) } } + + if len(finalrm) != 0 { + aur.RemoveMakeDeps(finalrm) + } } return nil @@ -139,13 +145,19 @@ func Install(pkgs []string, flags []string) error { fmt.Println("Unable to get info on some packages") } + var finalrm []string for _, aurpkg := range q { - err = aurpkg.Install(flags) + finalmdeps, err := aurpkg.Install(flags) + finalrm = append(finalrm, finalmdeps...) if err != nil { fmt.Println("Error installing", aurpkg.Name, ":", err) } } + if len(finalrm) != 0 { + aur.RemoveMakeDeps(finalrm) + } + return nil } @@ -305,3 +317,43 @@ func PassToPacman(op string, pkgs []string, flags []string) error { err := cmd.Run() return err } + +// CleanDependencies removels all dangling dependencies in system +func CleanDependencies(pkgs []string) error { + hanging, err := pac.HangingPackages() + if err != nil { + return err + } + + if len(hanging) != 0 { + if !continueTask("Confirm Removal?", "nN") { + return nil + } + err = pac.CleanRemove(hanging) + } + + return err +} + +func continueTask(s string, def string) (cont bool) { + if NoConfirm { + return true + } + var postFix string + + if def == "nN" { + postFix = "(Y/n)" + } else { + postFix = "(y/N)" + } + + var response string + fmt.Printf("\x1b[1;32m==> %s\x1b[1;37m %s\x1b[0m\n", s, postFix) + + fmt.Scanln(&response) + if response == string(def[0]) || response == string(def[1]) { + return false + } + + return true +} diff --git a/aur/result.go b/aur/result.go index ed154b67..e188afad 100644 --- a/aur/result.go +++ b/aur/result.go @@ -89,8 +89,8 @@ func printDeps(repoDeps []string, aurDeps []string) { } } -// Install handles install from Info Result -func (a *Result) Install(flags []string) (err error) { +// Install handles install from Info Result. +func (a *Result) Install(flags []string) (finalmdeps []string, err error) { fmt.Printf("\x1b[1;32m==> Installing\x1b[33m %s\x1b[0m\n", a.Name) if a.Maintainer == "" { fmt.Println("\x1b[1;31;40m==> Warning:\x1b[0;;40m This package is orphaned.\x1b[0m") @@ -101,10 +101,15 @@ func (a *Result) Install(flags []string) (err error) { if err = a.setupWorkspace(); err != nil { return } + } else { + if !continueTask("Directory exists. Clean Build?", "yY") { + os.RemoveAll(BaseDir + a.PackageBase) + if err = a.setupWorkspace(); err != nil { + return + } + } } - // defer os.RemoveAll(BaseDir + a.PackageBase) - if !continueTask("Edit PKGBUILD?", "yY") { editcmd := exec.Command(Editor, dir+"PKGBUILD") editcmd.Stdin, editcmd.Stdout, editcmd.Stderr = os.Stdin, os.Stdout, os.Stderr @@ -118,10 +123,12 @@ func (a *Result) Install(flags []string) (err error) { repoDeps := append(runDeps[0], makeDeps[0]...) aurDeps := append(runDeps[1], makeDeps[1]...) + finalmdeps = append(finalmdeps, makeDeps[0]...) + finalmdeps = append(finalmdeps, makeDeps[1]...) if len(aurDeps) != 0 || len(repoDeps) != 0 { if !continueTask("Continue?", "nN") { - return fmt.Errorf("user did not like the dependencies") + return finalmdeps, fmt.Errorf("user did not like the dependencies") } } @@ -129,15 +136,7 @@ func (a *Result) Install(flags []string) (err error) { if n != len(aurDeps) { aurQ.MissingPackage(aurDeps) if !continueTask("Continue?", "nN") { - return fmt.Errorf("unable to install dependencies") - } - } - - // Handle AUR dependencies first - for _, dep := range aurQ { - errA := dep.Install([]string{"--asdeps", "--noconfirm"}) - if errA != nil { - return errA + return finalmdeps, fmt.Errorf("unable to install dependencies") } } @@ -145,8 +144,19 @@ func (a *Result) Install(flags []string) (err error) { if len(repoDeps) != 0 { errR := pacman.Install(repoDeps, []string{"--asdeps", "--noconfirm"}) if errR != nil { + return finalmdeps, errR + } + } + + // Handle AUR dependencies first + for _, dep := range aurQ { + finalmdepsR, errA := dep.Install([]string{"--asdeps", "--noconfirm"}) + finalmdeps = append(finalmdeps, finalmdepsR...) + + if errA != nil { + pacman.CleanRemove(repoDeps) pacman.CleanRemove(aurDeps) - return errR + return finalmdeps, errA } } @@ -165,7 +175,7 @@ func (a *Result) Install(flags []string) (err error) { return } -// PrintInfo prints package info like pacman -Si +// PrintInfo prints package info like pacman -Si. func (a *Result) PrintInfo() { fmt.Println("\x1b[1;37mRepository :\x1b[0m", "aur") fmt.Println("\x1b[1;37mName :\x1b[0m", a.Name) @@ -222,6 +232,21 @@ func (a *Result) PrintInfo() { } +// RemoveMakeDeps receives a make dependency list and removes those +// that are no longer necessary. +func RemoveMakeDeps(depS []string) (err error) { + hanging := pacman.SliceHangingPackages(depS) + + if len(hanging) != 0 { + if !continueTask("Confirm Removal?", "nN") { + return nil + } + err = pacman.CleanRemove(hanging) + } + + return +} + func (a *Result) setupWorkspace() (err error) { // No need to use filepath.separators because it won't run on inferior platforms err = os.MkdirAll(BaseDir+"builds", 0755) diff --git a/cmd/yay/yay.go b/cmd/yay/yay.go index 3b30d1c8..f6610d98 100644 --- a/cmd/yay/yay.go +++ b/cmd/yay/yay.go @@ -80,6 +80,8 @@ func main() { yay.Config() switch op { + case "-Cd": + err = yay.CleanDependencies(pkgs) case "-Qstats": err = yay.LocalStatistics(version) case "-Ss": diff --git a/pacman/pacman.go b/pacman/pacman.go index 173293df..d00715db 100644 --- a/pacman/pacman.go +++ b/pacman/pacman.go @@ -348,6 +348,7 @@ func CleanRemove(pkgName []string) (err error) { var args []string args = append(args, "pacman", "-Rnsc") args = append(args, pkgName...) + args = append(args, "--noconfirm") cmd = exec.Command("sudo", args...) cmd.Stdin, cmd.Stdout, cmd.Stderr = os.Stdin, os.Stdout, os.Stderr @@ -468,3 +469,72 @@ func BiggestPackages() { } // Could implement size here as well, but we just want the general idea } + +// HangingPackages returns a list of packages installed as deps +// and unneeded by the system +func HangingPackages() (hanging []string, err error) { + h, err := conf.CreateHandle() + defer h.Release() + if err != nil { + return + } + + localDb, err := h.LocalDb() + if err != nil { + return + } + + f := func(pkg alpm.Package) error { + if pkg.Reason() != alpm.PkgReasonDepend { + return nil + } + requiredby := pkg.ComputeRequiredBy() + if len(requiredby) == 0 { + hanging = append(hanging, pkg.Name()) + fmt.Printf("%s: \x1B[0;33m%dMB\x1B[0m\n", pkg.Name(), pkg.ISize()/(1024*1024)) + + } + return nil + } + + err = localDb.PkgCache().ForEach(f) + return +} + +// SliceHangingPackages returns a list of packages installed as deps +// and unneeded by the system from a provided list of package names. +func SliceHangingPackages(pkgS []string) (hanging []string) { + h, err := conf.CreateHandle() + defer h.Release() + if err != nil { + return + } + + localDb, err := h.LocalDb() + if err != nil { + return + } + +big: + for _, pkgName := range pkgS { + for _, hangN := range hanging { + if hangN == pkgName { + continue big + } + } + + pkg, err := localDb.PkgByName(pkgName) + if err == nil { + if pkg.Reason() != alpm.PkgReasonDepend { + continue + } + + requiredby := pkg.ComputeRequiredBy() + if len(requiredby) == 0 { + hanging = append(hanging, pkgName) + fmt.Printf("%s: \x1B[0;33m%dMB\x1B[0m\n", pkg.Name(), pkg.ISize()/(1024*1024)) + } + } + } + return +}