dependencies.go 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290
  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. RepoMake []*alpm.Package
  16. Aur []*rpc.Pkg
  17. AurMake []*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([]*alpm.Package, 0),
  32. make([]*rpc.Pkg, 0),
  33. make([]*rpc.Pkg, 0),
  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. for _, pkg := range pkgs {
  45. dep := getNameFromDep(pkg)
  46. alpmpkg, exists := dt.Repo[dep]
  47. if exists {
  48. repoDepCatagoriesRecursive(alpmpkg, dc, dt, false)
  49. dc.Repo = append(dc.Repo, alpmpkg)
  50. delete(dt.Repo, dep)
  51. }
  52. aurpkg, exists := dt.Aur[dep]
  53. if exists {
  54. depCatagoriesRecursive(aurpkg, dc, dt, false)
  55. dc.Aur = append(dc.Aur, aurpkg)
  56. delete(dt.Aur, dep)
  57. }
  58. }
  59. return dc, nil
  60. }
  61. func repoDepCatagoriesRecursive(pkg *alpm.Package, dc *depCatagories, dt *depTree, isMake bool) {
  62. pkg.Depends().ForEach(func(_dep alpm.Depend) error {
  63. dep := _dep.Name
  64. alpmpkg, exists := dt.Repo[dep]
  65. if exists {
  66. delete(dt.Repo, dep)
  67. repoDepCatagoriesRecursive(alpmpkg, dc, dt, isMake)
  68. if isMake {
  69. dc.RepoMake = append(dc.RepoMake, alpmpkg)
  70. } else {
  71. dc.Repo = append(dc.Repo, alpmpkg)
  72. }
  73. }
  74. return nil
  75. })
  76. }
  77. func depCatagoriesRecursive(pkg *rpc.Pkg, dc *depCatagories, dt *depTree, isMake bool) {
  78. for _, deps := range [2][]string{pkg.Depends, pkg.MakeDepends} {
  79. for _, _dep := range deps {
  80. dep := getNameFromDep(_dep)
  81. aurpkg, exists := dt.Aur[dep]
  82. if exists {
  83. delete(dt.Aur, dep)
  84. depCatagoriesRecursive(aurpkg, dc, dt, isMake)
  85. if isMake {
  86. dc.AurMake = append(dc.AurMake, aurpkg)
  87. } else {
  88. dc.Aur = append(dc.Aur, aurpkg)
  89. }
  90. }
  91. alpmpkg, exists := dt.Repo[dep]
  92. if exists {
  93. delete(dt.Repo, dep)
  94. repoDepCatagoriesRecursive(alpmpkg, dc, dt, isMake)
  95. if isMake {
  96. dc.RepoMake = append(dc.RepoMake, alpmpkg)
  97. } else {
  98. dc.Repo = append(dc.Repo, alpmpkg)
  99. }
  100. }
  101. }
  102. isMake = true
  103. }
  104. }
  105. func getDepTree(pkgs []string) (*depTree, error) {
  106. dt := makeDepTree()
  107. localDb, err := alpmHandle.LocalDb()
  108. if err != nil {
  109. return dt, err
  110. }
  111. syncDb, err := alpmHandle.SyncDbs()
  112. if err != nil {
  113. return dt, err
  114. }
  115. for _, pkg := range pkgs {
  116. //if they explicitly asked for it still look for installed pkgs
  117. /*installedPkg, isInstalled := localDb.PkgCache().FindSatisfier(pkg)
  118. if isInstalled == nil {
  119. dt.Repo[installedPkg.Name()] = installedPkg
  120. continue
  121. }//*/
  122. //check the repos for a matching dep
  123. repoPkg, inRepos := syncDb.FindSatisfier(pkg)
  124. if inRepos == nil {
  125. repoTreeRecursive(repoPkg, dt, localDb, syncDb)
  126. continue
  127. }
  128. dt.ToProcess = append(dt.ToProcess, pkg)
  129. }
  130. if len(dt.ToProcess) > 0 {
  131. err = depTreeRecursive(dt, localDb, syncDb, false)
  132. }
  133. return dt, err
  134. }
  135. //takes a repo package
  136. //gives all of the non installed deps
  137. //does again on each sub dep
  138. func repoTreeRecursive(pkg *alpm.Package, dt *depTree, localDb *alpm.Db, syncDb alpm.DbList) (err error) {
  139. _, exists := dt.Repo[pkg.Name()]
  140. if exists {
  141. return
  142. }
  143. dt.Repo[pkg.Name()] = pkg
  144. (*pkg).Provides().ForEach(func(dep alpm.Depend) (err error) {
  145. dt.Repo[dep.Name] = pkg
  146. return nil
  147. })
  148. (*pkg).Depends().ForEach(func(dep alpm.Depend) (err error) {
  149. _, exists := dt.Repo[dep.Name]
  150. if exists {
  151. return
  152. }
  153. _, isInstalled := localDb.PkgCache().FindSatisfier(dep.String())
  154. if isInstalled == nil {
  155. return
  156. }
  157. repoPkg, inRepos := syncDb.FindSatisfier(dep.String())
  158. if inRepos == nil {
  159. repoTreeRecursive(repoPkg, dt, localDb, syncDb)
  160. return
  161. }
  162. dt.Missing.set(dep.String())
  163. return
  164. })
  165. return
  166. }
  167. func depTreeRecursive(dt *depTree, localDb *alpm.Db, syncDb alpm.DbList, isMake bool) (err error) {
  168. nextProcess := make([]string, 0)
  169. currentProcess := make([]string, 0, len(dt.ToProcess))
  170. //strip version conditions
  171. for _, dep := range dt.ToProcess {
  172. currentProcess = append(currentProcess, getNameFromDep(dep))
  173. }
  174. //assume toprocess only contains aur stuff we have not seen
  175. info, err := rpc.Info(currentProcess)
  176. if err != nil {
  177. return
  178. }
  179. //cache the results
  180. for _, pkg := range info {
  181. //copying to p fixes a bug
  182. //would rather not copy but cant find another way to fix
  183. p := pkg
  184. dt.Aur[pkg.Name] = &p
  185. }
  186. //loop through to process and check if we now have
  187. //each packaged cached
  188. //if its not cached we assume its missing
  189. for k, pkgName := range currentProcess {
  190. pkg, exists := dt.Aur[pkgName]
  191. //did not get it in the request
  192. if !exists {
  193. dt.Missing.set(dt.ToProcess[k])
  194. continue
  195. }
  196. //for reach dep and makedep
  197. for _, deps := range [2][]string{pkg.Depends, pkg.MakeDepends} {
  198. for _, versionedDep := range deps {
  199. dep := getNameFromDep(versionedDep)
  200. _, exists = dt.Aur[dep]
  201. //we have it cached so skip
  202. if exists {
  203. continue
  204. }
  205. _, exists = dt.Repo[dep]
  206. //we have it cached so skip
  207. if exists {
  208. continue
  209. }
  210. _, exists = dt.Missing[dep]
  211. //we know it does not resolve so skip
  212. if exists {
  213. continue
  214. }
  215. //check if already installed
  216. _, isInstalled := localDb.PkgCache().FindSatisfier(versionedDep)
  217. if isInstalled == nil {
  218. continue
  219. }
  220. //check the repos for a matching dep
  221. repoPkg, inRepos := syncDb.FindSatisfier(versionedDep)
  222. if inRepos == nil {
  223. repoTreeRecursive(repoPkg, dt, localDb, syncDb)
  224. continue
  225. }
  226. //if all else fails add it to next search
  227. nextProcess = append(nextProcess, versionedDep)
  228. }
  229. }
  230. }
  231. dt.ToProcess = nextProcess
  232. depTreeRecursive(dt, localDb, syncDb, true)
  233. return
  234. }