clean.go 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
  1. package main
  2. import (
  3. "fmt"
  4. "io/ioutil"
  5. "os"
  6. "path/filepath"
  7. "github.com/leonelquinteros/gotext"
  8. "github.com/Jguer/yay/v10/pkg/db"
  9. "github.com/Jguer/yay/v10/pkg/dep"
  10. "github.com/Jguer/yay/v10/pkg/query"
  11. "github.com/Jguer/yay/v10/pkg/settings"
  12. "github.com/Jguer/yay/v10/pkg/stringset"
  13. "github.com/Jguer/yay/v10/pkg/text"
  14. )
  15. // CleanDependencies removes all dangling dependencies in system
  16. func cleanDependencies(cmdArgs *settings.Arguments, dbExecutor db.Executor, removeOptional bool) error {
  17. hanging := hangingPackages(removeOptional, dbExecutor)
  18. if len(hanging) != 0 {
  19. return cleanRemove(cmdArgs, hanging)
  20. }
  21. return nil
  22. }
  23. // CleanRemove sends a full removal command to pacman with the pkgName slice
  24. func cleanRemove(cmdArgs *settings.Arguments, pkgNames []string) error {
  25. if len(pkgNames) == 0 {
  26. return nil
  27. }
  28. arguments := cmdArgs.CopyGlobal()
  29. _ = arguments.AddArg("R")
  30. arguments.AddTarget(pkgNames...)
  31. return config.Runtime.CmdRunner.Show(passToPacman(arguments))
  32. }
  33. func syncClean(cmdArgs *settings.Arguments, dbExecutor db.Executor) error {
  34. keepInstalled := false
  35. keepCurrent := false
  36. _, removeAll, _ := cmdArgs.GetArg("c", "clean")
  37. for _, v := range config.Runtime.PacmanConf.CleanMethod {
  38. if v == "KeepInstalled" {
  39. keepInstalled = true
  40. } else if v == "KeepCurrent" {
  41. keepCurrent = true
  42. }
  43. }
  44. if config.Runtime.Mode == settings.ModeRepo || config.Runtime.Mode == settings.ModeAny {
  45. if err := config.Runtime.CmdRunner.Show(passToPacman(cmdArgs)); err != nil {
  46. return err
  47. }
  48. }
  49. if !(config.Runtime.Mode == settings.ModeAUR || config.Runtime.Mode == settings.ModeAny) {
  50. return nil
  51. }
  52. var question string
  53. if removeAll {
  54. question = gotext.Get("Do you want to remove ALL AUR packages from cache?")
  55. } else {
  56. question = gotext.Get("Do you want to remove all other AUR packages from cache?")
  57. }
  58. fmt.Println(gotext.Get("\nBuild directory:"), config.BuildDir)
  59. if text.ContinueTask(question, true, settings.NoConfirm) {
  60. if err := cleanAUR(keepInstalled, keepCurrent, removeAll, dbExecutor); err != nil {
  61. return err
  62. }
  63. }
  64. if removeAll {
  65. return nil
  66. }
  67. if text.ContinueTask(gotext.Get("Do you want to remove ALL untracked AUR files?"), true, settings.NoConfirm) {
  68. return cleanUntracked()
  69. }
  70. return nil
  71. }
  72. func cleanAUR(keepInstalled, keepCurrent, removeAll bool, dbExecutor db.Executor) error {
  73. fmt.Println(gotext.Get("removing AUR packages from cache..."))
  74. installedBases := make(stringset.StringSet)
  75. inAURBases := make(stringset.StringSet)
  76. remotePackages, _ := query.GetRemotePackages(dbExecutor)
  77. files, err := ioutil.ReadDir(config.BuildDir)
  78. if err != nil {
  79. return err
  80. }
  81. cachedPackages := make([]string, 0, len(files))
  82. for _, file := range files {
  83. if !file.IsDir() {
  84. continue
  85. }
  86. cachedPackages = append(cachedPackages, file.Name())
  87. }
  88. // Most people probably don't use keep current and that is the only
  89. // case where this is needed.
  90. // Querying the AUR is slow and needs internet so don't do it if we
  91. // don't need to.
  92. if keepCurrent {
  93. info, errInfo := query.AURInfo(cachedPackages, &query.AURWarnings{}, config.RequestSplitN)
  94. if errInfo != nil {
  95. return errInfo
  96. }
  97. for _, pkg := range info {
  98. inAURBases.Set(pkg.PackageBase)
  99. }
  100. }
  101. for _, pkg := range remotePackages {
  102. if pkg.Base() != "" {
  103. installedBases.Set(pkg.Base())
  104. } else {
  105. installedBases.Set(pkg.Name())
  106. }
  107. }
  108. for _, file := range files {
  109. if !file.IsDir() {
  110. continue
  111. }
  112. if !removeAll {
  113. if keepInstalled && installedBases.Get(file.Name()) {
  114. continue
  115. }
  116. if keepCurrent && inAURBases.Get(file.Name()) {
  117. continue
  118. }
  119. }
  120. err = os.RemoveAll(filepath.Join(config.BuildDir, file.Name()))
  121. if err != nil {
  122. return nil
  123. }
  124. }
  125. return nil
  126. }
  127. func cleanUntracked() error {
  128. fmt.Println(gotext.Get("removing untracked AUR files from cache..."))
  129. files, err := ioutil.ReadDir(config.BuildDir)
  130. if err != nil {
  131. return err
  132. }
  133. for _, file := range files {
  134. if !file.IsDir() {
  135. continue
  136. }
  137. dir := filepath.Join(config.BuildDir, file.Name())
  138. if isGitRepository(dir) {
  139. if err := config.Runtime.CmdRunner.Show(config.Runtime.CmdBuilder.BuildGitCmd(dir, "clean", "-fx")); err != nil {
  140. text.Warnln(gotext.Get("Unable to clean:"), dir)
  141. return err
  142. }
  143. }
  144. }
  145. return nil
  146. }
  147. func isGitRepository(dir string) bool {
  148. _, err := os.Stat(filepath.Join(dir, ".git"))
  149. return !os.IsNotExist(err)
  150. }
  151. func cleanAfter(bases []dep.Base) {
  152. fmt.Println(gotext.Get("removing untracked AUR files from cache..."))
  153. for i, base := range bases {
  154. dir := filepath.Join(config.BuildDir, base.Pkgbase())
  155. if !isGitRepository(dir) {
  156. continue
  157. }
  158. text.OperationInfoln(gotext.Get("Cleaning (%d/%d): %s", i+1, len(bases), text.Cyan(dir)))
  159. _, stderr, err := config.Runtime.CmdRunner.Capture(config.Runtime.CmdBuilder.BuildGitCmd(dir, "reset", "--hard", "HEAD"), 0)
  160. if err != nil {
  161. text.Errorln(gotext.Get("error resetting %s: %s", base.String(), stderr))
  162. }
  163. if err := config.Runtime.CmdRunner.Show(config.Runtime.CmdBuilder.BuildGitCmd(dir, "clean", "-fx", "--exclude='*.pkg.*'")); err != nil {
  164. fmt.Fprintln(os.Stderr, err)
  165. }
  166. }
  167. }
  168. func cleanBuilds(bases []dep.Base) {
  169. for i, base := range bases {
  170. dir := filepath.Join(config.BuildDir, base.Pkgbase())
  171. text.OperationInfoln(gotext.Get("Deleting (%d/%d): %s", i+1, len(bases), text.Cyan(dir)))
  172. if err := os.RemoveAll(dir); err != nil {
  173. fmt.Fprintln(os.Stderr, err)
  174. }
  175. }
  176. }