dependencies.go 6.8 KB

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