upgrade.go 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251
  1. package main
  2. import (
  3. "context"
  4. "fmt"
  5. "sort"
  6. "strings"
  7. "sync"
  8. aur "github.com/Jguer/aur"
  9. alpm "github.com/Jguer/go-alpm/v2"
  10. "github.com/leonelquinteros/gotext"
  11. "github.com/Jguer/yay/v11/pkg/db"
  12. "github.com/Jguer/yay/v11/pkg/intrange"
  13. "github.com/Jguer/yay/v11/pkg/multierror"
  14. "github.com/Jguer/yay/v11/pkg/query"
  15. "github.com/Jguer/yay/v11/pkg/settings"
  16. "github.com/Jguer/yay/v11/pkg/stringset"
  17. "github.com/Jguer/yay/v11/pkg/text"
  18. "github.com/Jguer/yay/v11/pkg/upgrade"
  19. )
  20. func filterUpdateList(list []db.Upgrade, filter upgrade.Filter) []db.Upgrade {
  21. tmp := list[:0]
  22. for _, pkg := range list {
  23. if filter(pkg) {
  24. tmp = append(tmp, pkg)
  25. }
  26. }
  27. return tmp
  28. }
  29. // upList returns lists of packages to upgrade from each source.
  30. func upList(ctx context.Context, warnings *query.AURWarnings, dbExecutor db.Executor, enableDowngrade bool,
  31. filter upgrade.Filter,
  32. ) (aurUp, repoUp upgrade.UpSlice, err error) {
  33. remote, remoteNames := query.GetRemotePackages(dbExecutor)
  34. var (
  35. wg sync.WaitGroup
  36. develUp upgrade.UpSlice
  37. repoSlice []db.Upgrade
  38. errs multierror.MultiError
  39. )
  40. aurdata := make(map[string]*aur.Pkg)
  41. for _, pkg := range remote {
  42. if pkg.ShouldIgnore() {
  43. warnings.Ignore.Set(pkg.Name())
  44. }
  45. }
  46. if config.Runtime.Mode.AtLeastRepo() {
  47. text.OperationInfoln(gotext.Get("Searching databases for updates..."))
  48. wg.Add(1)
  49. go func() {
  50. repoSlice, err = dbExecutor.RepoUpgrades(enableDowngrade)
  51. errs.Add(err)
  52. wg.Done()
  53. }()
  54. }
  55. if config.Runtime.Mode.AtLeastAUR() {
  56. text.OperationInfoln(gotext.Get("Searching AUR for updates..."))
  57. var _aurdata []*aur.Pkg
  58. _aurdata, err = query.AURInfo(ctx, config.Runtime.AURClient, remoteNames, warnings, config.RequestSplitN)
  59. errs.Add(err)
  60. if err == nil {
  61. for _, pkg := range _aurdata {
  62. aurdata[pkg.Name] = pkg
  63. }
  64. wg.Add(1)
  65. go func() {
  66. aurUp = upgrade.UpAUR(remote, aurdata, config.TimeUpdate)
  67. wg.Done()
  68. }()
  69. if config.Devel {
  70. text.OperationInfoln(gotext.Get("Checking development packages..."))
  71. wg.Add(1)
  72. go func() {
  73. develUp = upgrade.UpDevel(ctx, remote, aurdata, config.Runtime.VCSStore)
  74. wg.Done()
  75. }()
  76. }
  77. }
  78. }
  79. wg.Wait()
  80. printLocalNewerThanAUR(remote, aurdata)
  81. names := make(stringset.StringSet)
  82. for _, up := range develUp.Up {
  83. names.Set(up.Name)
  84. }
  85. for _, up := range aurUp.Up {
  86. if !names.Get(up.Name) {
  87. develUp.Up = append(develUp.Up, up)
  88. }
  89. }
  90. aurUp = develUp
  91. aurUp.Repos = []string{"aur", "devel"}
  92. repoUp = upgrade.UpSlice{Up: repoSlice, Repos: dbExecutor.Repos()}
  93. aurUp.Up = filterUpdateList(aurUp.Up, filter)
  94. repoUp.Up = filterUpdateList(repoUp.Up, filter)
  95. return aurUp, repoUp, errs.Return()
  96. }
  97. func printLocalNewerThanAUR(
  98. remote []alpm.IPackage, aurdata map[string]*aur.Pkg,
  99. ) {
  100. for _, pkg := range remote {
  101. aurPkg, ok := aurdata[pkg.Name()]
  102. if !ok {
  103. continue
  104. }
  105. left, right := upgrade.GetVersionDiff(pkg.Version(), aurPkg.Version)
  106. if !isDevelPackage(pkg) && db.VerCmp(pkg.Version(), aurPkg.Version) > 0 {
  107. text.Warnln(gotext.Get("%s: local (%s) is newer than AUR (%s)",
  108. text.Cyan(pkg.Name()),
  109. left, right,
  110. ))
  111. }
  112. }
  113. }
  114. func isDevelName(name string) bool {
  115. for _, suffix := range []string{"git", "svn", "hg", "bzr", "nightly", "insiders-bin"} {
  116. if strings.HasSuffix(name, "-"+suffix) {
  117. return true
  118. }
  119. }
  120. return strings.Contains(name, "-always-")
  121. }
  122. func isDevelPackage(pkg alpm.IPackage) bool {
  123. return isDevelName(pkg.Name()) || isDevelName(pkg.Base())
  124. }
  125. // upgradePkgsMenu handles updating the cache and installing updates.
  126. func upgradePkgsMenu(aurUp, repoUp upgrade.UpSlice) (stringset.StringSet, []string, error) {
  127. ignore := make(stringset.StringSet)
  128. targets := []string{}
  129. allUpLen := len(repoUp.Up) + len(aurUp.Up)
  130. if allUpLen == 0 {
  131. return ignore, nil, nil
  132. }
  133. if !config.UpgradeMenu {
  134. for _, pkg := range aurUp.Up {
  135. targets = append(targets, pkg.Name)
  136. }
  137. return ignore, targets, nil
  138. }
  139. sort.Sort(repoUp)
  140. sort.Sort(aurUp)
  141. allUp := upgrade.UpSlice{Up: append(repoUp.Up, aurUp.Up...), Repos: append(repoUp.Repos, aurUp.Repos...)}
  142. fmt.Printf("%s"+text.Bold(" %d ")+"%s\n", text.Bold(text.Cyan("::")), allUpLen, text.Bold(gotext.Get("Packages to upgrade.")))
  143. allUp.Print()
  144. text.Infoln(gotext.Get("Packages to exclude: (eg: \"1 2 3\", \"1-3\", \"^4\" or repo name)"))
  145. numbers, err := text.GetInput(config.AnswerUpgrade, settings.NoConfirm)
  146. if err != nil {
  147. return nil, nil, err
  148. }
  149. // upgrade menu asks you which packages to NOT upgrade so in this case
  150. // include and exclude are kind of swapped
  151. include, exclude, otherInclude, otherExclude := intrange.ParseNumberMenu(numbers)
  152. isInclude := len(exclude) == 0 && len(otherExclude) == 0
  153. for i, pkg := range repoUp.Up {
  154. if isInclude && otherInclude.Get(pkg.Repository) {
  155. ignore.Set(pkg.Name)
  156. }
  157. if isInclude && !include.Get(len(repoUp.Up)-i+len(aurUp.Up)) {
  158. targets = append(targets, pkg.Name)
  159. continue
  160. }
  161. if !isInclude && (exclude.Get(len(repoUp.Up)-i+len(aurUp.Up)) || otherExclude.Get(pkg.Repository)) {
  162. targets = append(targets, pkg.Name)
  163. continue
  164. }
  165. ignore.Set(pkg.Name)
  166. }
  167. for i, pkg := range aurUp.Up {
  168. if isInclude && otherInclude.Get(pkg.Repository) {
  169. continue
  170. }
  171. if isInclude && !include.Get(len(aurUp.Up)-i) {
  172. targets = append(targets, "aur/"+pkg.Name)
  173. }
  174. if !isInclude && (exclude.Get(len(aurUp.Up)-i) || otherExclude.Get(pkg.Repository)) {
  175. targets = append(targets, "aur/"+pkg.Name)
  176. }
  177. }
  178. return ignore, targets, err
  179. }
  180. // Targets for sys upgrade.
  181. func sysupgradeTargets(ctx context.Context, dbExecutor db.Executor,
  182. enableDowngrade bool,
  183. ) (stringset.StringSet, []string, error) {
  184. warnings := query.NewWarnings()
  185. aurUp, repoUp, err := upList(ctx, warnings, dbExecutor, enableDowngrade,
  186. func(upgrade.Upgrade) bool { return true })
  187. if err != nil {
  188. return nil, nil, err
  189. }
  190. warnings.Print()
  191. return upgradePkgsMenu(aurUp, repoUp)
  192. }