depCheck.go 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293
  1. package main
  2. import (
  3. "fmt"
  4. "os"
  5. "strings"
  6. "sync"
  7. alpm "github.com/Jguer/go-alpm"
  8. "github.com/leonelquinteros/gotext"
  9. "github.com/Jguer/yay/v10/pkg/stringset"
  10. "github.com/Jguer/yay/v10/pkg/text"
  11. )
  12. func (dp *depPool) checkInnerConflict(name, conflict string, conflicts stringset.MapStringSet) {
  13. for _, pkg := range dp.Aur {
  14. if pkg.Name == name {
  15. continue
  16. }
  17. if satisfiesAur(conflict, pkg) {
  18. conflicts.Add(name, pkg.Name)
  19. }
  20. }
  21. for _, pkg := range dp.Repo {
  22. if pkg.Name() == name {
  23. continue
  24. }
  25. if satisfiesRepo(conflict, pkg) {
  26. conflicts.Add(name, pkg.Name())
  27. }
  28. }
  29. }
  30. func (dp *depPool) checkForwardConflict(name, conflict string, conflicts stringset.MapStringSet) {
  31. _ = dp.LocalDB.PkgCache().ForEach(func(pkg alpm.Package) error {
  32. if pkg.Name() == name || dp.hasPackage(pkg.Name()) {
  33. return nil
  34. }
  35. if satisfiesRepo(conflict, &pkg) {
  36. n := pkg.Name()
  37. if n != conflict {
  38. n += " (" + conflict + ")"
  39. }
  40. conflicts.Add(name, n)
  41. }
  42. return nil
  43. })
  44. }
  45. func (dp *depPool) checkReverseConflict(name, conflict string, conflicts stringset.MapStringSet) {
  46. for _, pkg := range dp.Aur {
  47. if pkg.Name == name {
  48. continue
  49. }
  50. if satisfiesAur(conflict, pkg) {
  51. if name != conflict {
  52. name += " (" + conflict + ")"
  53. }
  54. conflicts.Add(pkg.Name, name)
  55. }
  56. }
  57. for _, pkg := range dp.Repo {
  58. if pkg.Name() == name {
  59. continue
  60. }
  61. if satisfiesRepo(conflict, pkg) {
  62. if name != conflict {
  63. name += " (" + conflict + ")"
  64. }
  65. conflicts.Add(pkg.Name(), name)
  66. }
  67. }
  68. }
  69. func (dp *depPool) checkInnerConflicts(conflicts stringset.MapStringSet) {
  70. for _, pkg := range dp.Aur {
  71. for _, conflict := range pkg.Conflicts {
  72. dp.checkInnerConflict(pkg.Name, conflict, conflicts)
  73. }
  74. }
  75. for _, pkg := range dp.Repo {
  76. _ = pkg.Conflicts().ForEach(func(conflict alpm.Depend) error {
  77. dp.checkInnerConflict(pkg.Name(), conflict.String(), conflicts)
  78. return nil
  79. })
  80. }
  81. }
  82. func (dp *depPool) checkForwardConflicts(conflicts stringset.MapStringSet) {
  83. for _, pkg := range dp.Aur {
  84. for _, conflict := range pkg.Conflicts {
  85. dp.checkForwardConflict(pkg.Name, conflict, conflicts)
  86. }
  87. }
  88. for _, pkg := range dp.Repo {
  89. _ = pkg.Conflicts().ForEach(func(conflict alpm.Depend) error {
  90. dp.checkForwardConflict(pkg.Name(), conflict.String(), conflicts)
  91. return nil
  92. })
  93. }
  94. }
  95. func (dp *depPool) checkReverseConflicts(conflicts stringset.MapStringSet) {
  96. _ = dp.LocalDB.PkgCache().ForEach(func(pkg alpm.Package) error {
  97. if dp.hasPackage(pkg.Name()) {
  98. return nil
  99. }
  100. _ = pkg.Conflicts().ForEach(func(conflict alpm.Depend) error {
  101. dp.checkReverseConflict(pkg.Name(), conflict.String(), conflicts)
  102. return nil
  103. })
  104. return nil
  105. })
  106. }
  107. func (dp *depPool) CheckConflicts() (stringset.MapStringSet, error) {
  108. var wg sync.WaitGroup
  109. innerConflicts := make(stringset.MapStringSet)
  110. conflicts := make(stringset.MapStringSet)
  111. wg.Add(2)
  112. text.OperationInfoln(gotext.Get("Checking for conflicts..."))
  113. go func() {
  114. dp.checkForwardConflicts(conflicts)
  115. dp.checkReverseConflicts(conflicts)
  116. wg.Done()
  117. }()
  118. text.OperationInfoln(gotext.Get("Checking for inner conflicts..."))
  119. go func() {
  120. dp.checkInnerConflicts(innerConflicts)
  121. wg.Done()
  122. }()
  123. wg.Wait()
  124. if len(innerConflicts) != 0 {
  125. text.Errorln(gotext.Get("\nInner conflicts found:"))
  126. for name, pkgs := range innerConflicts {
  127. str := red(bold(smallArrow)) + " " + name + ":"
  128. for pkg := range pkgs {
  129. str += " " + cyan(pkg) + ","
  130. }
  131. str = strings.TrimSuffix(str, ",")
  132. fmt.Println(str)
  133. }
  134. }
  135. if len(conflicts) != 0 {
  136. text.Errorln(gotext.Get("\nPackage conflicts found:"))
  137. for name, pkgs := range conflicts {
  138. str := gotext.Get("%s Installing %s will remove:", red(bold(smallArrow)), cyan(name))
  139. for pkg := range pkgs {
  140. str += " " + cyan(pkg) + ","
  141. }
  142. str = strings.TrimSuffix(str, ",")
  143. fmt.Println(str)
  144. }
  145. }
  146. // Add the inner conflicts to the conflicts
  147. // These are used to decide what to pass --ask to (if set) or don't pass --noconfirm to
  148. // As we have no idea what the order is yet we add every inner conflict to the slice
  149. for name, pkgs := range innerConflicts {
  150. conflicts[name] = make(stringset.StringSet)
  151. for pkg := range pkgs {
  152. conflicts[pkg] = make(stringset.StringSet)
  153. }
  154. }
  155. if len(conflicts) > 0 {
  156. if !config.UseAsk {
  157. if config.NoConfirm {
  158. return nil, fmt.Errorf(gotext.Get("package conflicts can not be resolved with noconfirm, aborting"))
  159. }
  160. text.Errorln(gotext.Get("Conflicting packages will have to be confirmed manually"))
  161. }
  162. }
  163. return conflicts, nil
  164. }
  165. type missing struct {
  166. Good stringset.StringSet
  167. Missing map[string][][]string
  168. }
  169. func (dp *depPool) _checkMissing(dep string, stack []string, missing *missing) {
  170. if missing.Good.Get(dep) {
  171. return
  172. }
  173. if trees, ok := missing.Missing[dep]; ok {
  174. for _, tree := range trees {
  175. if stringSliceEqual(tree, stack) {
  176. return
  177. }
  178. }
  179. missing.Missing[dep] = append(missing.Missing[dep], stack)
  180. return
  181. }
  182. aurPkg := dp.findSatisfierAur(dep)
  183. if aurPkg != nil {
  184. missing.Good.Set(dep)
  185. for _, deps := range [3][]string{aurPkg.Depends, aurPkg.MakeDepends, aurPkg.CheckDepends} {
  186. for _, aurDep := range deps {
  187. if _, err := dp.LocalDB.PkgCache().FindSatisfier(aurDep); err == nil {
  188. missing.Good.Set(aurDep)
  189. continue
  190. }
  191. dp._checkMissing(aurDep, append(stack, aurPkg.Name), missing)
  192. }
  193. }
  194. return
  195. }
  196. repoPkg := dp.findSatisfierRepo(dep)
  197. if repoPkg != nil {
  198. missing.Good.Set(dep)
  199. _ = repoPkg.Depends().ForEach(func(repoDep alpm.Depend) error {
  200. if _, err := dp.LocalDB.PkgCache().FindSatisfier(repoDep.String()); err == nil {
  201. missing.Good.Set(repoDep.String())
  202. return nil
  203. }
  204. dp._checkMissing(repoDep.String(), append(stack, repoPkg.Name()), missing)
  205. return nil
  206. })
  207. return
  208. }
  209. missing.Missing[dep] = [][]string{stack}
  210. }
  211. func (dp *depPool) CheckMissing() error {
  212. missing := &missing{
  213. make(stringset.StringSet),
  214. make(map[string][][]string),
  215. }
  216. for _, target := range dp.Targets {
  217. dp._checkMissing(target.DepString(), make([]string, 0), missing)
  218. }
  219. if len(missing.Missing) == 0 {
  220. return nil
  221. }
  222. text.Errorln(gotext.Get("Could not find all required packages:"))
  223. for dep, trees := range missing.Missing {
  224. for _, tree := range trees {
  225. fmt.Fprintf(os.Stderr, "\t%s", cyan(dep))
  226. if len(tree) == 0 {
  227. fmt.Fprint(os.Stderr, gotext.Get(" (Target"))
  228. } else {
  229. fmt.Fprint(os.Stderr, gotext.Get(" (Wanted by: "))
  230. for n := 0; n < len(tree)-1; n++ {
  231. fmt.Fprint(os.Stderr, cyan(tree[n]), " -> ")
  232. }
  233. fmt.Fprint(os.Stderr, cyan(tree[len(tree)-1]))
  234. }
  235. fmt.Fprintln(os.Stderr, ")")
  236. }
  237. }
  238. return fmt.Errorf("")
  239. }