dependencies.go 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286
  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).Depends().ForEach(func(dep alpm.Depend) (err error) {
  145. _, exists := dt.Repo[dep.Name]
  146. if exists {
  147. return
  148. }
  149. _, isInstalled := localDb.PkgCache().FindSatisfier(dep.String())
  150. if isInstalled == nil {
  151. return
  152. }
  153. repoPkg, inRepos := syncDb.FindSatisfier(dep.String())
  154. if inRepos == nil {
  155. repoTreeRecursive(repoPkg, dt, localDb, syncDb)
  156. return
  157. } else {
  158. dt.Missing.set(dep.String())
  159. }
  160. return
  161. })
  162. return
  163. }
  164. func depTreeRecursive(dt *depTree, localDb *alpm.Db, syncDb alpm.DbList, isMake bool) (err error) {
  165. nextProcess := make([]string, 0)
  166. currentProcess := make([]string, 0, len(dt.ToProcess))
  167. //strip version conditions
  168. for _, dep := range dt.ToProcess {
  169. currentProcess = append(currentProcess, getNameFromDep(dep))
  170. }
  171. //assume toprocess only contains aur stuff we have not seen
  172. info, err := rpc.Info(currentProcess)
  173. if err != nil {
  174. return
  175. }
  176. //cache the results
  177. for _, pkg := range info {
  178. //copying to p fixes a bug
  179. //would rather not copy but cant find another way to fix
  180. p := pkg
  181. dt.Aur[pkg.Name] = &p
  182. }
  183. //loop through to process and check if we now have
  184. //each packaged cached
  185. //if its not cached we assume its missing
  186. for k, pkgName := range currentProcess {
  187. pkg, exists := dt.Aur[pkgName]
  188. //didnt get it in the request
  189. if !exists {
  190. dt.Missing.set(dt.ToProcess[k])
  191. continue
  192. }
  193. //for reach dep and makedep
  194. for _, deps := range [2][]string{pkg.Depends, pkg.MakeDepends} {
  195. for _, versionedDep := range deps {
  196. dep := getNameFromDep(versionedDep)
  197. _, exists = dt.Aur[dep]
  198. //we have it cached so skip
  199. if exists {
  200. continue
  201. }
  202. _, exists = dt.Repo[dep]
  203. //we have it cached so skip
  204. if exists {
  205. continue
  206. }
  207. _, exists = dt.Missing[dep]
  208. //we know it doesnt resolve so skip
  209. if exists {
  210. continue
  211. }
  212. //check if already installed
  213. _, isInstalled := localDb.PkgCache().FindSatisfier(versionedDep)
  214. if isInstalled == nil {
  215. continue
  216. }
  217. //check the repos for a matching dep
  218. repoPkg, inRepos := syncDb.FindSatisfier(versionedDep)
  219. if inRepos == nil {
  220. repoTreeRecursive(repoPkg, dt, localDb, syncDb)
  221. continue
  222. }
  223. //if all else failes add it to next search
  224. nextProcess = append(nextProcess, versionedDep)
  225. }
  226. }
  227. }
  228. dt.ToProcess = nextProcess
  229. depTreeRecursive(dt, localDb, syncDb, true)
  230. return
  231. }