depSolver.go 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917
  1. package main
  2. import (
  3. "fmt"
  4. "sort"
  5. "strings"
  6. "sync"
  7. alpm "github.com/jguer/go-alpm"
  8. rpc "github.com/mikkeloscar/aur"
  9. )
  10. type depSolver struct {
  11. Aur []Base
  12. Repo []*alpm.Package
  13. Runtime stringSet
  14. Targets []target
  15. Explicit stringSet
  16. AurCache map[string]*rpc.Pkg
  17. Groups []string
  18. LocalDb *alpm.Db
  19. SyncDb alpm.DbList
  20. Seen stringSet
  21. Warnings *aurWarnings
  22. }
  23. func makeDepSolver() (*depSolver, error) {
  24. localDb, err := alpmHandle.LocalDb()
  25. if err != nil {
  26. return nil, err
  27. }
  28. syncDb, err := alpmHandle.SyncDbs()
  29. if err != nil {
  30. return nil, err
  31. }
  32. return &depSolver{
  33. make([]Base, 0),
  34. make([]*alpm.Package, 0),
  35. make(stringSet),
  36. make([]target, 0),
  37. make(stringSet),
  38. make(map[string]*rpc.Pkg),
  39. make([]string, 0),
  40. localDb,
  41. syncDb,
  42. make(stringSet),
  43. nil,
  44. }, nil
  45. }
  46. func getDepSolver(pkgs []string, warnings *aurWarnings) (*depSolver, error) {
  47. ds, err := makeDepSolver()
  48. if err != nil {
  49. return nil, err
  50. }
  51. ds.Warnings = warnings
  52. err = ds.resolveTargets(pkgs)
  53. if err != nil {
  54. return nil, err
  55. }
  56. ds.resolveRuntime()
  57. return ds, err
  58. }
  59. // Includes db/ prefixes and group installs
  60. func (ds *depSolver) resolveTargets(pkgs []string) error {
  61. // RPC requests are slow
  62. // Combine as many AUR package requests as possible into a single RPC
  63. // call
  64. aurTargets := make(stringSet)
  65. pkgs = removeInvalidTargets(pkgs)
  66. for _, pkg := range pkgs {
  67. var err error
  68. target := toTarget(pkg)
  69. // skip targets already satisfied
  70. // even if the user enters db/pkg and aur/pkg the latter will
  71. // still get skipped even if it's from a different database to
  72. // the one specified
  73. // this is how pacman behaves
  74. if ds.hasPackage(target.DepString()) {
  75. continue
  76. }
  77. var foundPkg *alpm.Package
  78. var singleDb *alpm.Db
  79. // aur/ prefix means we only check the aur
  80. if target.Db == "aur" || mode == ModeAUR {
  81. ds.Targets = append(ds.Targets, target)
  82. aurTargets.set(target.DepString())
  83. continue
  84. }
  85. // If there'ss a different priefix only look in that repo
  86. if target.Db != "" {
  87. singleDb, err = alpmHandle.SyncDbByName(target.Db)
  88. if err != nil {
  89. return err
  90. }
  91. foundPkg, err = singleDb.PkgCache().FindSatisfier(target.DepString())
  92. //otherwise find it in any repo
  93. } else {
  94. foundPkg, err = ds.SyncDb.FindSatisfier(target.DepString())
  95. }
  96. if err == nil {
  97. ds.Targets = append(ds.Targets, target)
  98. ds.Explicit.set(foundPkg.Name())
  99. ds.ResolveRepoDependency(foundPkg)
  100. continue
  101. } else {
  102. //check for groups
  103. //currently we don't resolve the packages in a group
  104. //only check if the group exists
  105. //would be better to check the groups from singleDb if
  106. //the user specified a db but there's no easy way to do
  107. //it without making alpm_lists so don't bother for now
  108. //db/group is probably a rare use case
  109. group, err := ds.SyncDb.PkgCachebyGroup(target.Name)
  110. if err == nil {
  111. ds.Groups = append(ds.Groups, target.String())
  112. group.ForEach(func(pkg alpm.Package) error {
  113. ds.Explicit.set(pkg.Name())
  114. return nil
  115. })
  116. continue
  117. }
  118. }
  119. //if there was no db prefix check the aur
  120. if target.Db == "" {
  121. aurTargets.set(target.DepString())
  122. }
  123. ds.Targets = append(ds.Targets, target)
  124. }
  125. if len(aurTargets) > 0 && (mode == ModeAny || mode == ModeAUR) {
  126. return ds.resolveAURPackages(aurTargets, true)
  127. }
  128. return nil
  129. }
  130. func (ds *depSolver) hasPackage(name string) bool {
  131. for _, pkg := range ds.Repo {
  132. if pkg.Name() == name {
  133. return true
  134. }
  135. }
  136. for _, base := range ds.Aur {
  137. for _, pkg := range base {
  138. if pkg.Name == name {
  139. return true
  140. }
  141. }
  142. }
  143. for _, pkg := range ds.Groups {
  144. if pkg == name {
  145. return true
  146. }
  147. }
  148. return false
  149. }
  150. func (ds *depSolver) findSatisfierAur(dep string) *rpc.Pkg {
  151. for _, base := range ds.Aur {
  152. for _, pkg := range base {
  153. if satisfiesAur(dep, pkg) {
  154. return pkg
  155. }
  156. }
  157. }
  158. return nil
  159. }
  160. func (ds *depSolver) findSatisfierRepo(dep string) *alpm.Package {
  161. for _, pkg := range ds.Repo {
  162. if satisfiesRepo(dep, pkg) {
  163. return pkg
  164. }
  165. }
  166. return nil
  167. }
  168. func (ds *depSolver) hasSatisfier(dep string) bool {
  169. return ds.findSatisfierRepo(dep) != nil || ds.findSatisfierAur(dep) != nil
  170. }
  171. func (ds *depSolver) ResolveRepoDependency(pkg *alpm.Package) {
  172. if ds.Seen.get(pkg.Name()) {
  173. return
  174. }
  175. ds.Repo = append(ds.Repo, pkg)
  176. ds.Seen.set(pkg.Name())
  177. pkg.Depends().ForEach(func(dep alpm.Depend) (err error) {
  178. //have satisfier in dep tree: skip
  179. if ds.hasSatisfier(dep.String()) {
  180. return
  181. }
  182. //has satisfier installed: skip
  183. _, isInstalled := ds.LocalDb.PkgCache().FindSatisfier(dep.String())
  184. if isInstalled == nil {
  185. return
  186. }
  187. //has satisfier in repo: fetch it
  188. repoPkg, inRepos := ds.SyncDb.FindSatisfier(dep.String())
  189. if inRepos != nil {
  190. return
  191. }
  192. ds.ResolveRepoDependency(repoPkg)
  193. return nil
  194. })
  195. }
  196. // This is mostly used to promote packages from the cache
  197. // to the Install list
  198. // Provide a pacman style provider menu if there's more than one candidate
  199. // This acts slightly differently from Pacman, It will give
  200. // a menu even if a package with a matching name exists. I believe this
  201. // method is better because most of the time you are choosing between
  202. // foo and foo-git.
  203. // Using Pacman's ways trying to install foo would never give you
  204. // a menu.
  205. // TODO: maybe intermix repo providers in the menu
  206. func (ds *depSolver) findSatisfierAurCache(dep string) *rpc.Pkg {
  207. depName, _, _ := splitDep(dep)
  208. seen := make(stringSet)
  209. providers := makeProviders(depName)
  210. if _, err := ds.LocalDb.PkgByName(depName); err == nil {
  211. if pkg, ok := ds.AurCache[dep]; ok && pkgSatisfies(pkg.Name, pkg.Version, dep) {
  212. return pkg
  213. }
  214. }
  215. if cmdArgs.op == "Y" || cmdArgs.op == "yay" {
  216. for _, pkg := range ds.AurCache {
  217. if pkgSatisfies(pkg.Name, pkg.Version, dep) {
  218. for _, target := range ds.Targets {
  219. if target.Name == pkg.Name {
  220. return pkg
  221. }
  222. }
  223. }
  224. }
  225. }
  226. for _, pkg := range ds.AurCache {
  227. if seen.get(pkg.Name) {
  228. continue
  229. }
  230. if pkgSatisfies(pkg.Name, pkg.Version, dep) {
  231. providers.Pkgs = append(providers.Pkgs, pkg)
  232. seen.set(pkg.Name)
  233. continue
  234. }
  235. for _, provide := range pkg.Provides {
  236. if provideSatisfies(provide, dep) {
  237. providers.Pkgs = append(providers.Pkgs, pkg)
  238. seen.set(pkg.Name)
  239. continue
  240. }
  241. }
  242. }
  243. if providers.Len() == 1 {
  244. return providers.Pkgs[0]
  245. }
  246. if providers.Len() > 1 {
  247. sort.Sort(providers)
  248. return providerMenu(dep, providers)
  249. }
  250. return nil
  251. }
  252. func (ds *depSolver) cacheAURPackages(_pkgs stringSet) error {
  253. pkgs := _pkgs.copy()
  254. query := make([]string, 0)
  255. for pkg := range pkgs {
  256. if _, ok := ds.AurCache[pkg]; ok {
  257. pkgs.remove(pkg)
  258. }
  259. }
  260. if len(pkgs) == 0 {
  261. return nil
  262. }
  263. if config.Provides {
  264. err := ds.findProvides(pkgs)
  265. if err != nil {
  266. return err
  267. }
  268. }
  269. for pkg := range pkgs {
  270. if _, ok := ds.AurCache[pkg]; !ok {
  271. name, _, _ := splitDep(pkg)
  272. query = append(query, name)
  273. }
  274. }
  275. info, err := aurInfo(query, ds.Warnings)
  276. if err != nil {
  277. return err
  278. }
  279. for _, pkg := range info {
  280. // Dump everything in cache just in case we need it later
  281. ds.AurCache[pkg.Name] = pkg
  282. }
  283. return nil
  284. }
  285. // Pseudo provides finder.
  286. // Try to find provides by performing a search of the package name
  287. // This effectively performs -Ss on each package
  288. // then runs -Si on each result to cache the information.
  289. //
  290. // For example if you were to -S yay then yay -Ss would give:
  291. // yay-git yay-bin yay realyog pacui pacui-git ruby-yard
  292. // These packages will all be added to the cache in case they are needed later
  293. // Ofcouse only the first three packages provide yay, the rest are just false
  294. // positives.
  295. //
  296. // This method increases dependency resolve time
  297. func (ds *depSolver) findProvides(pkgs stringSet) error {
  298. var mux sync.Mutex
  299. var wg sync.WaitGroup
  300. doSearch := func(pkg string) {
  301. defer wg.Done()
  302. var err error
  303. var results []rpc.Pkg
  304. // Hack for a bigger search result, if the user wants
  305. // java-envronment we can search for just java instead and get
  306. // more hits.
  307. words := strings.Split(pkg, "-")
  308. for i := range words {
  309. results, err = rpc.SearchByNameDesc(strings.Join(words[:i+1], "-"))
  310. if err == nil {
  311. break
  312. }
  313. }
  314. if err != nil {
  315. return
  316. }
  317. for _, result := range results {
  318. mux.Lock()
  319. if _, ok := ds.AurCache[result.Name]; !ok {
  320. pkgs.set(result.Name)
  321. }
  322. mux.Unlock()
  323. }
  324. }
  325. for pkg := range pkgs {
  326. if _, err := ds.LocalDb.PkgByName(pkg); err == nil {
  327. continue
  328. }
  329. wg.Add(1)
  330. go doSearch(pkg)
  331. }
  332. wg.Wait()
  333. return nil
  334. }
  335. func (ds *depSolver) resolveAURPackages(pkgs stringSet, explicit bool) error {
  336. newPackages := make(stringSet)
  337. newAURPackages := make(stringSet)
  338. toAdd := make([]*rpc.Pkg, 0)
  339. if len(pkgs) == 0 {
  340. return nil
  341. }
  342. err := ds.cacheAURPackages(pkgs)
  343. if err != nil {
  344. return err
  345. }
  346. for name := range pkgs {
  347. if ds.Seen.get(name) {
  348. continue
  349. }
  350. pkg := ds.findSatisfierAurCache(name)
  351. if pkg == nil {
  352. continue
  353. }
  354. if explicit {
  355. ds.Explicit.set(pkg.Name)
  356. }
  357. ds.Seen.set(pkg.Name)
  358. toAdd = append(toAdd, pkg)
  359. for _, deps := range [3][]string{pkg.Depends, pkg.MakeDepends, pkg.CheckDepends} {
  360. for _, dep := range deps {
  361. newPackages.set(dep)
  362. }
  363. }
  364. }
  365. for dep := range newPackages {
  366. if ds.hasSatisfier(dep) {
  367. continue
  368. }
  369. _, isInstalled := ds.LocalDb.PkgCache().FindSatisfier(dep) //has satisfier installed: skip
  370. hm := hideMenus
  371. hideMenus = isInstalled == nil
  372. repoPkg, inRepos := ds.SyncDb.FindSatisfier(dep) //has satisfier in repo: fetch it
  373. hideMenus = hm
  374. if isInstalled == nil && (config.ReBuild != "tree" || inRepos == nil) {
  375. continue
  376. }
  377. if inRepos == nil {
  378. ds.ResolveRepoDependency(repoPkg)
  379. continue
  380. }
  381. //assume it's in the aur
  382. //ditch the versioning because the RPC can't handle it
  383. newAURPackages.set(dep)
  384. }
  385. err = ds.resolveAURPackages(newAURPackages, false)
  386. for _, pkg := range toAdd {
  387. if !ds.hasPackage(pkg.Name) {
  388. ds.Aur = baseAppend(ds.Aur, pkg)
  389. }
  390. }
  391. return err
  392. }
  393. func (ds *depSolver) Print() {
  394. repo := ""
  395. repoMake := ""
  396. aur := ""
  397. aurMake := ""
  398. repoLen := 0
  399. repoMakeLen := 0
  400. aurLen := 0
  401. aurMakeLen := 0
  402. for _, pkg := range ds.Repo {
  403. if ds.Runtime.get(pkg.Name()) {
  404. repo += " " + pkg.Name() + "-" + pkg.Version()
  405. repoLen++
  406. } else {
  407. repoMake += " " + pkg.Name() + "-" + pkg.Version()
  408. repoMakeLen++
  409. }
  410. }
  411. for _, base := range ds.Aur {
  412. pkg := base.Pkgbase()
  413. pkgStr := " " + pkg + "-" + base[0].Version
  414. pkgStrMake := pkgStr
  415. push := false
  416. pushMake := false
  417. if len(base) > 1 || pkg != base[0].Name {
  418. pkgStr += " ("
  419. pkgStrMake += " ("
  420. for _, split := range base {
  421. if ds.Runtime.get(split.Name) {
  422. pkgStr += split.Name + " "
  423. aurLen++
  424. push = true
  425. } else {
  426. pkgStrMake += split.Name + " "
  427. aurMakeLen++
  428. pushMake = true
  429. }
  430. }
  431. pkgStr = pkgStr[:len(pkgStr)-1] + ")"
  432. pkgStrMake = pkgStrMake[:len(pkgStrMake)-1] + ")"
  433. } else if ds.Runtime.get(base[0].Name) {
  434. aurLen++
  435. push = true
  436. } else {
  437. aurMakeLen++
  438. pushMake = true
  439. }
  440. if push {
  441. aur += pkgStr
  442. }
  443. if pushMake {
  444. aurMake += pkgStrMake
  445. }
  446. }
  447. printDownloads("Repo", repoLen, repo)
  448. printDownloads("Repo Make", repoMakeLen, repoMake)
  449. printDownloads("Aur", aurLen, aur)
  450. printDownloads("Aur Make", aurMakeLen, aurMake)
  451. }
  452. func (ds *depSolver) resolveRuntime() {
  453. for _, pkg := range ds.Repo {
  454. if ds.Explicit.get(pkg.Name()) {
  455. ds.Runtime.set(pkg.Name())
  456. ds.resolveRuntimeRepo(pkg)
  457. }
  458. }
  459. for _, base := range ds.Aur {
  460. for _, pkg := range base {
  461. if ds.Explicit.get(pkg.Name) {
  462. ds.Runtime.set(pkg.Name)
  463. ds.resolveRuntimeAur(pkg)
  464. }
  465. }
  466. }
  467. }
  468. func (ds *depSolver) resolveRuntimeRepo(pkg *alpm.Package) {
  469. pkg.Depends().ForEach(func(dep alpm.Depend) (err error) {
  470. for _, pkg := range ds.Repo {
  471. if ds.Runtime.get(pkg.Name()) {
  472. continue
  473. }
  474. if satisfiesRepo(dep.String(), pkg) {
  475. ds.Runtime.set(pkg.Name())
  476. ds.resolveRuntimeRepo(pkg)
  477. }
  478. }
  479. return nil
  480. })
  481. }
  482. func (ds *depSolver) resolveRuntimeAur(pkg *rpc.Pkg) {
  483. for _, dep := range pkg.Depends {
  484. for _, pkg := range ds.Repo {
  485. if ds.Runtime.get(pkg.Name()) {
  486. continue
  487. }
  488. if satisfiesRepo(dep, pkg) {
  489. ds.Runtime.set(pkg.Name())
  490. ds.resolveRuntimeRepo(pkg)
  491. }
  492. }
  493. for _, base := range ds.Aur {
  494. for _, pkg := range base {
  495. if ds.Runtime.get(pkg.Name) {
  496. continue
  497. }
  498. if satisfiesAur(dep, pkg) {
  499. ds.Runtime.set(pkg.Name)
  500. ds.resolveRuntimeAur(pkg)
  501. }
  502. }
  503. }
  504. }
  505. }
  506. func (ds *depSolver) _checkMissing(dep string, stack []string, missing *missing) {
  507. if missing.Good.get(dep) {
  508. return
  509. }
  510. if trees, ok := missing.Missing[dep]; ok {
  511. for _, tree := range trees {
  512. if stringSliceEqual(tree, stack) {
  513. return
  514. }
  515. }
  516. missing.Missing[dep] = append(missing.Missing[dep], stack)
  517. return
  518. }
  519. aurPkg := ds.findSatisfierAur(dep)
  520. if aurPkg != nil {
  521. missing.Good.set(dep)
  522. for _, deps := range [3][]string{aurPkg.Depends, aurPkg.MakeDepends, aurPkg.CheckDepends} {
  523. for _, aurDep := range deps {
  524. if _, err := ds.LocalDb.PkgCache().FindSatisfier(aurDep); err == nil {
  525. missing.Good.set(aurDep)
  526. continue
  527. }
  528. ds._checkMissing(aurDep, append(stack, aurPkg.Name), missing)
  529. }
  530. }
  531. return
  532. }
  533. repoPkg := ds.findSatisfierRepo(dep)
  534. if repoPkg != nil {
  535. missing.Good.set(dep)
  536. repoPkg.Depends().ForEach(func(repoDep alpm.Depend) error {
  537. if _, err := ds.LocalDb.PkgCache().FindSatisfier(repoDep.String()); err == nil {
  538. missing.Good.set(repoDep.String())
  539. return nil
  540. }
  541. ds._checkMissing(repoDep.String(), append(stack, repoPkg.Name()), missing)
  542. return nil
  543. })
  544. return
  545. }
  546. missing.Missing[dep] = [][]string{stack}
  547. }
  548. func (ds *depSolver) CheckMissing() error {
  549. missing := &missing{
  550. make(stringSet),
  551. make(map[string][][]string),
  552. }
  553. for _, target := range ds.Targets {
  554. ds._checkMissing(target.DepString(), make([]string, 0), missing)
  555. }
  556. if len(missing.Missing) == 0 {
  557. return nil
  558. }
  559. fmt.Println(bold(red(arrow+" Error: ")) + "Could not find all required packages:")
  560. for dep, trees := range missing.Missing {
  561. for _, tree := range trees {
  562. fmt.Print(" ", cyan(dep))
  563. if len(tree) == 0 {
  564. fmt.Print(" (Target")
  565. } else {
  566. fmt.Print(" (Wanted by: ")
  567. for n := 0; n < len(tree)-1; n++ {
  568. fmt.Print(cyan(tree[n]), " -> ")
  569. }
  570. fmt.Print(cyan(tree[len(tree)-1]))
  571. }
  572. fmt.Println(")")
  573. }
  574. }
  575. return fmt.Errorf("")
  576. }
  577. func (ds *depSolver) HasMake() bool {
  578. lenAur := 0
  579. for _, base := range ds.Aur {
  580. lenAur += len(base)
  581. }
  582. return len(ds.Runtime) != lenAur+len(ds.Repo)
  583. }
  584. func (ds *depSolver) getMake() []string {
  585. makeOnly := make([]string, 0, len(ds.Aur)+len(ds.Repo)-len(ds.Runtime))
  586. for _, base := range ds.Aur {
  587. for _, pkg := range base {
  588. if !ds.Runtime.get(pkg.Name) {
  589. makeOnly = append(makeOnly, pkg.Name)
  590. }
  591. }
  592. }
  593. for _, pkg := range ds.Repo {
  594. if !ds.Runtime.get(pkg.Name()) {
  595. makeOnly = append(makeOnly, pkg.Name())
  596. }
  597. }
  598. return makeOnly
  599. }
  600. func (ds *depSolver) checkInnerConflict(name string, conflict string, conflicts mapStringSet) {
  601. for _, base := range ds.Aur {
  602. for _, pkg := range base {
  603. if pkg.Name == name {
  604. continue
  605. }
  606. if satisfiesAur(conflict, pkg) {
  607. conflicts.Add(name, pkg.Name)
  608. }
  609. }
  610. }
  611. for _, pkg := range ds.Repo {
  612. if pkg.Name() == name {
  613. continue
  614. }
  615. if satisfiesRepo(conflict, pkg) {
  616. conflicts.Add(name, pkg.Name())
  617. }
  618. }
  619. }
  620. func (ds *depSolver) checkForwardConflict(name string, conflict string, conflicts mapStringSet) {
  621. ds.LocalDb.PkgCache().ForEach(func(pkg alpm.Package) error {
  622. if pkg.Name() == name || ds.hasPackage(pkg.Name()) {
  623. return nil
  624. }
  625. if satisfiesRepo(conflict, &pkg) {
  626. n := pkg.Name()
  627. if n != conflict {
  628. n += " (" + conflict + ")"
  629. }
  630. conflicts.Add(name, n)
  631. }
  632. return nil
  633. })
  634. }
  635. func (ds *depSolver) checkReverseConflict(name string, conflict string, conflicts mapStringSet) {
  636. for _, base := range ds.Aur {
  637. for _, pkg := range base {
  638. if pkg.Name == name {
  639. continue
  640. }
  641. if satisfiesAur(conflict, pkg) {
  642. if name != conflict {
  643. name += " (" + conflict + ")"
  644. }
  645. conflicts.Add(pkg.Name, name)
  646. }
  647. }
  648. }
  649. for _, pkg := range ds.Repo {
  650. if pkg.Name() == name {
  651. continue
  652. }
  653. if satisfiesRepo(conflict, pkg) {
  654. if name != conflict {
  655. name += " (" + conflict + ")"
  656. }
  657. conflicts.Add(pkg.Name(), name)
  658. }
  659. }
  660. }
  661. func (ds *depSolver) checkInnerConflicts(conflicts mapStringSet) {
  662. for _, base := range ds.Aur {
  663. for _, pkg := range base {
  664. for _, conflict := range pkg.Conflicts {
  665. ds.checkInnerConflict(pkg.Name, conflict, conflicts)
  666. }
  667. }
  668. }
  669. for _, pkg := range ds.Repo {
  670. pkg.Conflicts().ForEach(func(conflict alpm.Depend) error {
  671. ds.checkInnerConflict(pkg.Name(), conflict.String(), conflicts)
  672. return nil
  673. })
  674. }
  675. }
  676. func (ds *depSolver) checkForwardConflicts(conflicts mapStringSet) {
  677. for _, base := range ds.Aur {
  678. for _, pkg := range base {
  679. for _, conflict := range pkg.Conflicts {
  680. ds.checkForwardConflict(pkg.Name, conflict, conflicts)
  681. }
  682. }
  683. }
  684. for _, pkg := range ds.Repo {
  685. pkg.Conflicts().ForEach(func(conflict alpm.Depend) error {
  686. ds.checkForwardConflict(pkg.Name(), conflict.String(), conflicts)
  687. return nil
  688. })
  689. }
  690. }
  691. func (ds *depSolver) checkReverseConflicts(conflicts mapStringSet) {
  692. ds.LocalDb.PkgCache().ForEach(func(pkg alpm.Package) error {
  693. if ds.hasPackage(pkg.Name()) {
  694. return nil
  695. }
  696. pkg.Conflicts().ForEach(func(conflict alpm.Depend) error {
  697. ds.checkReverseConflict(pkg.Name(), conflict.String(), conflicts)
  698. return nil
  699. })
  700. return nil
  701. })
  702. }
  703. func (ds *depSolver) CheckConflicts() (mapStringSet, error) {
  704. var wg sync.WaitGroup
  705. innerConflicts := make(mapStringSet)
  706. conflicts := make(mapStringSet)
  707. wg.Add(2)
  708. fmt.Println(bold(cyan("::") + bold(" Checking for conflicts...")))
  709. go func() {
  710. ds.checkForwardConflicts(conflicts)
  711. ds.checkReverseConflicts(conflicts)
  712. wg.Done()
  713. }()
  714. fmt.Println(bold(cyan("::") + bold(" Checking for inner conflicts...")))
  715. go func() {
  716. ds.checkInnerConflicts(innerConflicts)
  717. wg.Done()
  718. }()
  719. wg.Wait()
  720. if len(innerConflicts) != 0 {
  721. fmt.Println()
  722. fmt.Println(bold(red(arrow)), bold("Inner conflicts found:"))
  723. for name, pkgs := range innerConflicts {
  724. str := red(bold(smallArrow)) + " " + name + ":"
  725. for pkg := range pkgs {
  726. str += " " + cyan(pkg) + ","
  727. }
  728. str = strings.TrimSuffix(str, ",")
  729. fmt.Println(str)
  730. }
  731. }
  732. if len(conflicts) != 0 {
  733. fmt.Println()
  734. fmt.Println(bold(red(arrow)), bold("Package conflicts found:"))
  735. for name, pkgs := range conflicts {
  736. str := red(bold(smallArrow)) + " Installing " + cyan(name) + " will remove:"
  737. for pkg := range pkgs {
  738. str += " " + cyan(pkg) + ","
  739. }
  740. str = strings.TrimSuffix(str, ",")
  741. fmt.Println(str)
  742. }
  743. }
  744. // Add the inner conflicts to the conflicts
  745. // These are used to decide what to pass --ask to (if set) or don't pass --noconfirm to
  746. // As we have no idea what the order is yet we add every inner conflict to the slice
  747. for name, pkgs := range innerConflicts {
  748. conflicts[name] = make(stringSet)
  749. for pkg := range pkgs {
  750. conflicts[pkg] = make(stringSet)
  751. }
  752. }
  753. if len(conflicts) > 0 {
  754. if !config.UseAsk {
  755. if config.NoConfirm {
  756. return nil, fmt.Errorf("Package conflicts can not be resolved with noconfirm, aborting")
  757. }
  758. fmt.Println()
  759. fmt.Println(bold(red(arrow)), bold("Conflicting packages will have to be confirmed manually"))
  760. fmt.Println()
  761. }
  762. }
  763. return conflicts, nil
  764. }