dependencies.go 7.0 KB

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