dependencies.go 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323
  1. package main
  2. import (
  3. "strings"
  4. alpm "github.com/jguer/go-alpm"
  5. rpc "github.com/mikkeloscar/aur"
  6. )
  7. type depTree struct {
  8. ToProcess []string
  9. Repo map[string]*alpm.Package
  10. Aur map[string]*rpc.Pkg
  11. Missing stringSet
  12. }
  13. type depCatagories struct {
  14. Repo []*alpm.Package
  15. Aur []*rpc.Pkg
  16. MakeOnly stringSet
  17. Bases map[string][]*rpc.Pkg
  18. }
  19. func makeDepTree() *depTree {
  20. dt := depTree{
  21. make([]string, 0),
  22. make(map[string]*alpm.Package),
  23. make(map[string]*rpc.Pkg),
  24. make(stringSet),
  25. }
  26. return &dt
  27. }
  28. func makeDependCatagories() *depCatagories {
  29. dc := depCatagories{
  30. make([]*alpm.Package, 0),
  31. make([]*rpc.Pkg, 0),
  32. make(stringSet),
  33. make(map[string][]*rpc.Pkg),
  34. }
  35. return &dc
  36. }
  37. func getNameFromDep(dep string) string {
  38. return strings.FieldsFunc(dep, func(c rune) bool {
  39. return c == '>' || c == '<' || c == '=' || c == ' '
  40. })[0]
  41. }
  42. func getDepCatagories(pkgs []string, dt *depTree) (*depCatagories, error) {
  43. dc := makeDependCatagories()
  44. seen := make(stringSet)
  45. for _, pkg := range pkgs {
  46. dep := getNameFromDep(pkg)
  47. alpmpkg, exists := dt.Repo[dep]
  48. if exists {
  49. repoDepCatagoriesRecursive(alpmpkg, dc, dt, false)
  50. dc.Repo = append(dc.Repo, alpmpkg)
  51. delete(dt.Repo, dep)
  52. }
  53. aurpkg, exists := dt.Aur[dep]
  54. if exists {
  55. depCatagoriesRecursive(aurpkg, dc, dt, false, seen)
  56. if !seen.get(aurpkg.PackageBase) {
  57. dc.Aur = append(dc.Aur, aurpkg)
  58. seen.set(aurpkg.PackageBase)
  59. }
  60. _, ok := dc.Bases[aurpkg.PackageBase]
  61. if !ok {
  62. dc.Bases[aurpkg.PackageBase] = make([]*rpc.Pkg, 0)
  63. }
  64. dc.Bases[aurpkg.PackageBase] = append(dc.Bases[aurpkg.PackageBase], aurpkg)
  65. delete(dt.Aur, dep)
  66. }
  67. }
  68. for _, base := range dc.Bases {
  69. for _, pkg := range base {
  70. for _, dep := range pkg.Depends {
  71. dc.MakeOnly.remove(dep)
  72. }
  73. }
  74. }
  75. for _, pkg := range dc.Repo {
  76. pkg.Depends().ForEach(func(_dep alpm.Depend) error {
  77. dep := _dep.Name
  78. dc.MakeOnly.remove(dep)
  79. return nil
  80. })
  81. }
  82. return dc, nil
  83. }
  84. func repoDepCatagoriesRecursive(pkg *alpm.Package, dc *depCatagories, dt *depTree, isMake bool) {
  85. pkg.Depends().ForEach(func(_dep alpm.Depend) error {
  86. dep := _dep.Name
  87. alpmpkg, exists := dt.Repo[dep]
  88. if exists {
  89. delete(dt.Repo, dep)
  90. repoDepCatagoriesRecursive(alpmpkg, dc, dt, isMake)
  91. if isMake {
  92. dc.MakeOnly.set(alpmpkg.Name())
  93. }
  94. dc.Repo = append(dc.Repo, alpmpkg)
  95. }
  96. return nil
  97. })
  98. }
  99. func depCatagoriesRecursive(pkg *rpc.Pkg, dc *depCatagories, dt *depTree, isMake bool, seen stringSet) {
  100. for _, deps := range [2][]string{pkg.Depends, pkg.MakeDepends} {
  101. for _, _dep := range deps {
  102. dep := getNameFromDep(_dep)
  103. aurpkg, exists := dt.Aur[dep]
  104. if exists {
  105. _, ok := dc.Bases[aurpkg.PackageBase]
  106. if !ok {
  107. dc.Bases[aurpkg.PackageBase] = make([]*rpc.Pkg, 0)
  108. }
  109. dc.Bases[aurpkg.PackageBase] = append(dc.Bases[aurpkg.PackageBase], aurpkg)
  110. delete(dt.Aur, dep)
  111. depCatagoriesRecursive(aurpkg, dc, dt, isMake, seen)
  112. if !seen.get(aurpkg.PackageBase) {
  113. dc.Aur = append(dc.Aur, aurpkg)
  114. seen.set(aurpkg.PackageBase)
  115. }
  116. if isMake {
  117. dc.MakeOnly.set(aurpkg.Name)
  118. }
  119. }
  120. alpmpkg, exists := dt.Repo[dep]
  121. if exists {
  122. delete(dt.Repo, dep)
  123. repoDepCatagoriesRecursive(alpmpkg, dc, dt, isMake)
  124. if isMake {
  125. dc.MakeOnly.set(alpmpkg.Name())
  126. }
  127. dc.Repo = append(dc.Repo, alpmpkg)
  128. }
  129. }
  130. isMake = true
  131. }
  132. }
  133. func getDepTree(pkgs []string) (*depTree, error) {
  134. dt := makeDepTree()
  135. localDb, err := alpmHandle.LocalDb()
  136. if err != nil {
  137. return dt, err
  138. }
  139. syncDb, err := alpmHandle.SyncDbs()
  140. if err != nil {
  141. return dt, err
  142. }
  143. for _, pkg := range pkgs {
  144. //if they explicitly asked for it still look for installed pkgs
  145. /*installedPkg, isInstalled := localDb.PkgCache().FindSatisfier(pkg)
  146. if isInstalled == nil {
  147. dt.Repo[installedPkg.Name()] = installedPkg
  148. continue
  149. }//*/
  150. //check the repos for a matching dep
  151. repoPkg, inRepos := syncDb.FindSatisfier(pkg)
  152. if inRepos == nil {
  153. repoTreeRecursive(repoPkg, dt, localDb, syncDb)
  154. continue
  155. }
  156. dt.ToProcess = append(dt.ToProcess, pkg)
  157. }
  158. if len(dt.ToProcess) > 0 {
  159. err = depTreeRecursive(dt, localDb, syncDb, false)
  160. }
  161. return dt, err
  162. }
  163. //takes a repo package
  164. //gives all of the non installed deps
  165. //does again on each sub dep
  166. func repoTreeRecursive(pkg *alpm.Package, dt *depTree, localDb *alpm.Db, syncDb alpm.DbList) (err error) {
  167. _, exists := dt.Repo[pkg.Name()]
  168. if exists {
  169. return
  170. }
  171. dt.Repo[pkg.Name()] = pkg
  172. (*pkg).Provides().ForEach(func(dep alpm.Depend) (err error) {
  173. dt.Repo[dep.Name] = pkg
  174. return nil
  175. })
  176. (*pkg).Depends().ForEach(func(dep alpm.Depend) (err error) {
  177. _, exists := dt.Repo[dep.Name]
  178. if exists {
  179. return
  180. }
  181. _, isInstalled := localDb.PkgCache().FindSatisfier(dep.String())
  182. if isInstalled == nil {
  183. return
  184. }
  185. repoPkg, inRepos := syncDb.FindSatisfier(dep.String())
  186. if inRepos == nil {
  187. repoTreeRecursive(repoPkg, dt, localDb, syncDb)
  188. return
  189. }
  190. dt.Missing.set(dep.String())
  191. return
  192. })
  193. return
  194. }
  195. func depTreeRecursive(dt *depTree, localDb *alpm.Db, syncDb alpm.DbList, isMake bool) (err error) {
  196. nextProcess := make([]string, 0)
  197. currentProcess := make([]string, 0, len(dt.ToProcess))
  198. //strip version conditions
  199. for _, dep := range dt.ToProcess {
  200. currentProcess = append(currentProcess, getNameFromDep(dep))
  201. }
  202. //assume toprocess only contains aur stuff we have not seen
  203. info, err := rpc.Info(currentProcess)
  204. if err != nil {
  205. return
  206. }
  207. //cache the results
  208. for _, pkg := range info {
  209. //copying to p fixes a bug
  210. //would rather not copy but cant find another way to fix
  211. p := pkg
  212. dt.Aur[pkg.Name] = &p
  213. }
  214. //loop through to process and check if we now have
  215. //each packaged cached
  216. //if its not cached we assume its missing
  217. for k, pkgName := range currentProcess {
  218. pkg, exists := dt.Aur[pkgName]
  219. //did not get it in the request
  220. if !exists {
  221. dt.Missing.set(dt.ToProcess[k])
  222. continue
  223. }
  224. //for reach dep and makedep
  225. for _, deps := range [2][]string{pkg.Depends, pkg.MakeDepends} {
  226. for _, versionedDep := range deps {
  227. dep := getNameFromDep(versionedDep)
  228. _, exists = dt.Aur[dep]
  229. //we have it cached so skip
  230. if exists {
  231. continue
  232. }
  233. _, exists = dt.Repo[dep]
  234. //we have it cached so skip
  235. if exists {
  236. continue
  237. }
  238. _, exists = dt.Missing[dep]
  239. //we know it does not resolve so skip
  240. if exists {
  241. continue
  242. }
  243. //check if already installed
  244. _, isInstalled := localDb.PkgCache().FindSatisfier(versionedDep)
  245. if isInstalled == nil {
  246. continue
  247. }
  248. //check the repos for a matching dep
  249. repoPkg, inRepos := syncDb.FindSatisfier(versionedDep)
  250. if inRepos == nil {
  251. repoTreeRecursive(repoPkg, dt, localDb, syncDb)
  252. continue
  253. }
  254. //if all else fails add it to next search
  255. nextProcess = append(nextProcess, versionedDep)
  256. }
  257. }
  258. }
  259. dt.ToProcess = nextProcess
  260. depTreeRecursive(dt, localDb, syncDb, true)
  261. return
  262. }