conflicts.go 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354
  1. package main
  2. import (
  3. "fmt"
  4. "strings"
  5. "sync"
  6. alpm "github.com/jguer/go-alpm"
  7. gopkg "github.com/mikkeloscar/gopkgbuild"
  8. )
  9. // Checks a single conflict against every other to be installed package's
  10. // name and its provides.
  11. func checkInnerConflict(name string, conflict string, conflicts map[string]stringSet, dc *depCatagories) {
  12. deps, err := gopkg.ParseDeps([]string{conflict})
  13. if err != nil {
  14. return
  15. }
  16. dep := deps[0]
  17. for _, pkg := range dc.Aur {
  18. if name == pkg.Name {
  19. continue
  20. }
  21. version, err := gopkg.NewCompleteVersion(pkg.Version)
  22. if err != nil {
  23. return
  24. }
  25. if dep.Name == pkg.Name && version.Satisfies(dep) {
  26. addMapStringSet(conflicts, name, pkg.Name)
  27. continue
  28. }
  29. for _, provide := range pkg.Provides {
  30. // Provides are not versioned unless explicitly defined as
  31. // such. If a conflict is versioned but a provide is
  32. // not it can not conflict.
  33. if (dep.MaxVer != nil || dep.MinVer != nil) && !strings.ContainsAny(provide, "><=") {
  34. continue
  35. }
  36. var version *gopkg.CompleteVersion
  37. var err error
  38. pname, pversion := splitNameFromDep(provide)
  39. if dep.Name != pname {
  40. continue
  41. }
  42. if pversion != "" {
  43. version, err = gopkg.NewCompleteVersion(provide)
  44. if err != nil {
  45. return
  46. }
  47. }
  48. if version != nil && version.Satisfies(dep) {
  49. addMapStringSet(conflicts, name, pkg.Name)
  50. break
  51. }
  52. }
  53. }
  54. for _, pkg := range dc.Repo {
  55. if name == pkg.Name() {
  56. continue
  57. }
  58. version, err := gopkg.NewCompleteVersion(pkg.Version())
  59. if err != nil {
  60. return
  61. }
  62. if dep.Name == pkg.Name() && version.Satisfies(dep) {
  63. addMapStringSet(conflicts, name, pkg.Name())
  64. continue
  65. }
  66. pkg.Provides().ForEach(func(provide alpm.Depend) error {
  67. // Provides are not versioned unless explicitly defined as
  68. // such. If a conflict is versioned but a provide is
  69. // not it can not conflict.
  70. if (dep.MaxVer != nil || dep.MinVer != nil) && provide.Mod == alpm.DepModAny {
  71. return nil
  72. }
  73. if dep.Name != pkg.Name() {
  74. return nil
  75. }
  76. if provide.Mod == alpm.DepModAny {
  77. addMapStringSet(conflicts, name, pkg.Name())
  78. return fmt.Errorf("")
  79. }
  80. version, err := gopkg.NewCompleteVersion(provide.Version)
  81. if err != nil {
  82. return nil
  83. }
  84. if version.Satisfies(dep) {
  85. addMapStringSet(conflicts, name, pkg.Name())
  86. return fmt.Errorf("")
  87. }
  88. return nil
  89. })
  90. }
  91. }
  92. // Checks every to be installed package's conflicts against every other to be
  93. // installed package and its provides.
  94. func checkForInnerConflicts(dc *depCatagories) map[string]stringSet {
  95. conflicts := make(map[string]stringSet)
  96. for _, pkg := range dc.Aur {
  97. for _, cpkg := range pkg.Conflicts {
  98. checkInnerConflict(pkg.Name, cpkg, conflicts, dc)
  99. }
  100. }
  101. for _, pkg := range dc.Repo {
  102. pkg.Conflicts().ForEach(func(conflict alpm.Depend) error {
  103. checkInnerConflict(pkg.Name(), conflict.String(), conflicts, dc)
  104. return nil
  105. })
  106. }
  107. return conflicts
  108. }
  109. // Checks a provide or packagename from a to be installed package
  110. // against every already installed package's conflicts
  111. func checkReverseConflict(name string, provide string, conflicts map[string]stringSet) error {
  112. var version *gopkg.CompleteVersion
  113. var err error
  114. localDb, err := alpmHandle.LocalDb()
  115. if err != nil {
  116. return err
  117. }
  118. pname, pversion := splitNameFromDep(provide)
  119. if pversion != "" {
  120. version, err = gopkg.NewCompleteVersion(pversion)
  121. if err != nil {
  122. return nil
  123. }
  124. }
  125. localDb.PkgCache().ForEach(func(pkg alpm.Package) error {
  126. if name == pkg.Name() {
  127. return nil
  128. }
  129. pkg.Conflicts().ForEach(func(conflict alpm.Depend) error {
  130. deps, err := gopkg.ParseDeps([]string{conflict.String()})
  131. if err != nil {
  132. return nil
  133. }
  134. dep := deps[0]
  135. // Provides are not versioned unless explicitly defined as
  136. // such. If a conflict is versioned but a provide is
  137. // not it can not conflict.
  138. if (dep.MaxVer != nil || dep.MinVer != nil) && version == nil {
  139. return nil
  140. }
  141. if dep.Name != pname {
  142. return nil
  143. }
  144. if version == nil || version.Satisfies(dep) {
  145. // Todo
  146. addMapStringSet(conflicts, name, pkg.Name()+" ("+provide+")")
  147. return fmt.Errorf("")
  148. }
  149. return nil
  150. })
  151. return nil
  152. })
  153. return nil
  154. }
  155. // Checks the conflict of a to be installed package against the package name and
  156. // provides of every installed package.
  157. func checkConflict(name string, conflict string, conflicts map[string]stringSet) error {
  158. localDb, err := alpmHandle.LocalDb()
  159. if err != nil {
  160. return err
  161. }
  162. deps, err := gopkg.ParseDeps([]string{conflict})
  163. if err != nil {
  164. return nil
  165. }
  166. dep := deps[0]
  167. localDb.PkgCache().ForEach(func(pkg alpm.Package) error {
  168. if name == pkg.Name() {
  169. return nil
  170. }
  171. version, err := gopkg.NewCompleteVersion(pkg.Version())
  172. if err != nil {
  173. return nil
  174. }
  175. if dep.Name == pkg.Name() && version.Satisfies(dep) {
  176. addMapStringSet(conflicts, name, pkg.Name())
  177. return nil
  178. }
  179. pkg.Provides().ForEach(func(provide alpm.Depend) error {
  180. if dep.Name != provide.Name {
  181. return nil
  182. }
  183. // Provides arent version unless explicitly defined as
  184. // such. If a conflict is versioned but a provide is
  185. // not it can not conflict.
  186. if (dep.MaxVer != nil || dep.MinVer != nil) && provide.Mod == alpm.DepModAny {
  187. return nil
  188. }
  189. if provide.Mod == alpm.DepModAny {
  190. addMapStringSet(conflicts, name, pkg.Name()+" ("+provide.Name+")")
  191. return fmt.Errorf("")
  192. }
  193. version, err := gopkg.NewCompleteVersion(provide.Version)
  194. if err != nil {
  195. return nil
  196. }
  197. if version.Satisfies(dep) {
  198. addMapStringSet(conflicts, name, pkg.Name()+" ("+provide.Name+")")
  199. return fmt.Errorf("")
  200. }
  201. return nil
  202. })
  203. return nil
  204. })
  205. return nil
  206. }
  207. // Checks every to be installed package's conflicts against the names and
  208. // provides of every already installed package and checks every to be installed
  209. // package's name and provides against every already installed package.
  210. func checkForConflicts(dc *depCatagories) (map[string]stringSet, error) {
  211. conflicts := make(map[string]stringSet)
  212. for _, pkg := range dc.Aur {
  213. for _, cpkg := range pkg.Conflicts {
  214. checkConflict(pkg.Name, cpkg, conflicts)
  215. }
  216. }
  217. for _, pkg := range dc.Repo {
  218. pkg.Conflicts().ForEach(func(conflict alpm.Depend) error {
  219. checkConflict(pkg.Name(), conflict.String(), conflicts)
  220. return nil
  221. })
  222. }
  223. for _, pkg := range dc.Aur {
  224. checkReverseConflict(pkg.Name, pkg.Name, conflicts)
  225. for _, ppkg := range pkg.Provides {
  226. checkReverseConflict(pkg.Name, ppkg, conflicts)
  227. }
  228. }
  229. for _, pkg := range dc.Repo {
  230. checkReverseConflict(pkg.Name(), pkg.Name(), conflicts)
  231. pkg.Provides().ForEach(func(provide alpm.Depend) error {
  232. checkReverseConflict(pkg.Name(), provide.String(), conflicts)
  233. return nil
  234. })
  235. }
  236. return conflicts, nil
  237. }
  238. // Combiles checkForConflicts() and checkForInnerConflicts() in parallel and
  239. // does some printing.
  240. func checkForAllConflicts(dc *depCatagories) error {
  241. var err error
  242. var conflicts map[string]stringSet
  243. var innerConflicts map[string]stringSet
  244. var wg sync.WaitGroup
  245. wg.Add(2)
  246. fmt.Println(bold(cyan("::") + bold(" Checking for conflicts...")))
  247. go func() {
  248. conflicts, err = checkForConflicts(dc)
  249. wg.Done()
  250. }()
  251. fmt.Println(bold(cyan("::") + bold(" Checking for inner conflicts...")))
  252. go func() {
  253. innerConflicts = checkForInnerConflicts(dc)
  254. wg.Done()
  255. }()
  256. wg.Wait()
  257. if err != nil {
  258. return err
  259. }
  260. if len(innerConflicts) != 0 {
  261. fmt.Println()
  262. fmt.Println(bold(red(arrow)), bold("Inner conflicts found:"))
  263. for name, pkgs := range innerConflicts {
  264. str := red(bold(smallArrow)) + " " + name + ":"
  265. for pkg := range pkgs {
  266. str += " " + cyan(pkg)
  267. }
  268. fmt.Println(str)
  269. }
  270. return fmt.Errorf("Unresolvable package conflicts, aborting")
  271. }
  272. if len(conflicts) != 0 {
  273. fmt.Println()
  274. fmt.Println(bold(red(arrow)), bold("Package conflicts found:"))
  275. for name, pkgs := range conflicts {
  276. str := red(bold(smallArrow)) + " Installing " + cyan(name) + " will remove:"
  277. for pkg := range pkgs {
  278. str += " " + cyan(pkg)
  279. }
  280. fmt.Println(str)
  281. }
  282. fmt.Println()
  283. }
  284. return nil
  285. }