install.go 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466
  1. package main
  2. import (
  3. "fmt"
  4. "io/ioutil"
  5. "os"
  6. "os/exec"
  7. "strings"
  8. alpm "github.com/jguer/go-alpm"
  9. rpc "github.com/mikkeloscar/aur"
  10. gopkg "github.com/mikkeloscar/gopkgbuild"
  11. )
  12. // Install handles package installs
  13. func install(parser *arguments) error {
  14. aurs, repos, missing, err := packageSlices(parser.targets.toSlice())
  15. srcinfos := make(map[string]*gopkg.PKGBUILD)
  16. if err != nil {
  17. return err
  18. }
  19. if len(missing) > 0 {
  20. fmt.Println(missing)
  21. fmt.Println("Could not find all Targets")
  22. }
  23. arguments := parser.copy()
  24. arguments.delArg("u", "sysupgrade")
  25. arguments.delArg("y", "refresh")
  26. arguments.op = "S"
  27. arguments.targets = make(stringSet)
  28. arguments.addTarget(repos...)
  29. if len(repos) != 0 {
  30. err := passToPacman(arguments)
  31. if err != nil {
  32. fmt.Println("Error installing repo packages.")
  33. }
  34. }
  35. if len(aurs) != 0 {
  36. //todo mamakeke pretty
  37. fmt.Println(greenFg(arrow), greenFg("Resolving Dependencies"))
  38. dt, err := getDepTree(aurs)
  39. if err != nil {
  40. return err
  41. }
  42. if len(dt.Missing) > 0 {
  43. fmt.Println(dt.Missing)
  44. return fmt.Errorf("Could not find all Deps")
  45. }
  46. dc, err := getDepCatagories(aurs, dt)
  47. if err != nil {
  48. return err
  49. }
  50. for _, pkg := range dc.Aur {
  51. if pkg.Maintainer == "" {
  52. fmt.Println(boldRedFgBlackBg(arrow+" Warning:"),
  53. blackBg(pkg.Name+"-"+pkg.Version+" is orphaned"))
  54. }
  55. }
  56. //printDownloadsFromRepo("Repo", dc.Repo)
  57. //printDownloadsFromRepo("Repo Make", dc.RepoMake)
  58. //printDownloadsFromAur("AUR", dc.Aur)
  59. //printDownloadsFromAur("AUR Make", dc.AurMake)
  60. //fmt.Println(dc.MakeOnly)
  61. //fmt.Println(dc.AurSet)
  62. printDepCatagories(dc)
  63. askCleanBuilds(dc.Aur, dc.Bases)
  64. fmt.Println()
  65. if !continueTask("Proceed with install?", "nN") {
  66. return fmt.Errorf("Aborting due to user")
  67. }
  68. // if !continueTask("Proceed with download?", "nN") {
  69. // return fmt.Errorf("Aborting due to user")
  70. // }
  71. if _, ok := arguments.options["gendb"]; !ok {
  72. //err = checkForConflicts(dc.Aur, dc.AurMake, dc.Repo, dc.RepoMake)
  73. if err != nil {
  74. return err
  75. }
  76. }
  77. err = dowloadPkgBuilds(dc.Aur, dc.Bases)
  78. if err != nil {
  79. return err
  80. }
  81. err = askEditPkgBuilds(dc.Aur, dc.Bases)
  82. if err != nil {
  83. return err
  84. }
  85. if len(dc.Repo) > 0 {
  86. arguments := parser.copy()
  87. arguments.delArg("u", "sysupgrade")
  88. arguments.delArg("y", "refresh")
  89. arguments.op = "S"
  90. arguments.targets = make(stringSet)
  91. arguments.addArg("needed", "asdeps")
  92. for _, pkg := range dc.Repo {
  93. arguments.addTarget(pkg.Name())
  94. }
  95. oldConfirm := config.NoConfirm
  96. config.NoConfirm = true
  97. passToPacman(arguments)
  98. config.NoConfirm = oldConfirm
  99. if err != nil {
  100. return err
  101. }
  102. }
  103. if _, ok := arguments.options["gendb"]; ok {
  104. fmt.Println("GenDB finished. No packages were installed")
  105. return nil
  106. }
  107. // if !continueTask("Proceed with install?", "nN") {
  108. // return fmt.Errorf("Aborting due to user")
  109. // }
  110. err = downloadPkgBuildsSources(dc.Aur)
  111. if err != nil {
  112. return err
  113. }
  114. err = parsesrcinfos(dc.Aur, srcinfos)
  115. if err != nil {
  116. return err
  117. }
  118. err = buildInstallPkgBuilds(dc.Aur, srcinfos, parser.targets, parser, dc.Bases)
  119. if err != nil {
  120. return err
  121. }
  122. if len(dc.MakeOnly) > 0 {
  123. if continueTask("Remove make dependencies?", "yY") {
  124. return nil
  125. }
  126. removeArguments := makeArguments()
  127. removeArguments.addArg("R", "u")
  128. for pkg := range dc.MakeOnly {
  129. removeArguments.addTarget(pkg)
  130. }
  131. oldValue := config.NoConfirm
  132. config.NoConfirm = true
  133. passToPacman(removeArguments)
  134. config.NoConfirm = oldValue
  135. }
  136. if config.CleanAfter {
  137. clean(dc.Aur)
  138. }
  139. return nil
  140. }
  141. return nil
  142. }
  143. func askCleanBuilds(pkgs []*rpc.Pkg, bases map[string][]*rpc.Pkg) {
  144. for _, pkg := range pkgs {
  145. dir := config.BuildDir + pkg.PackageBase + "/"
  146. if _, err := os.Stat(dir); !os.IsNotExist(err) {
  147. str := pkg.Name
  148. if len(bases[pkg.PackageBase]) > 1 || pkg.PackageBase != pkg.Name {
  149. str += " ("
  150. for _, split := range bases[pkg.PackageBase] {
  151. str += split.Name + " "
  152. }
  153. str = str[:len(str)-1] + ")"
  154. }
  155. if !continueTask(str+" Directory exists. Clean Build?", "yY") {
  156. _ = os.RemoveAll(config.BuildDir + pkg.PackageBase)
  157. }
  158. }
  159. }
  160. }
  161. func checkForConflicts(aur []*rpc.Pkg, aurMake []*rpc.Pkg, repo []*alpm.Package,
  162. repoMake []*alpm.Package) error {
  163. localDb, err := alpmHandle.LocalDb()
  164. if err != nil {
  165. return err
  166. }
  167. var toRemove []string
  168. for _, pkg := range aur {
  169. for _, cpkg := range pkg.Conflicts {
  170. if _, err := localDb.PkgByName(cpkg); err == nil {
  171. toRemove = append(toRemove, cpkg)
  172. }
  173. }
  174. }
  175. for _, pkg := range aurMake {
  176. for _, cpkg := range pkg.Conflicts {
  177. if _, err := localDb.PkgByName(cpkg); err == nil {
  178. toRemove = append(toRemove, cpkg)
  179. }
  180. }
  181. }
  182. for _, pkg := range repo {
  183. pkg.Conflicts().ForEach(func(conf alpm.Depend) error {
  184. if _, err := localDb.PkgByName(conf.Name); err == nil {
  185. toRemove = append(toRemove, conf.Name)
  186. }
  187. return nil
  188. })
  189. }
  190. for _, pkg := range repoMake {
  191. pkg.Conflicts().ForEach(func(conf alpm.Depend) error {
  192. if _, err := localDb.PkgByName(conf.Name); err == nil {
  193. toRemove = append(toRemove, conf.Name)
  194. }
  195. return nil
  196. })
  197. }
  198. if len(toRemove) != 0 {
  199. fmt.Println(
  200. redFg("The following packages conflict with packages to install:"))
  201. for _, pkg := range toRemove {
  202. fmt.Println(yellowFg(pkg))
  203. }
  204. if !continueTask("Remove conflicting package(s)?", "nN") {
  205. return fmt.Errorf("Aborting due to user")
  206. }
  207. removeArguments := makeArguments()
  208. removeArguments.addArg("R", "d", "d")
  209. for _, pkg := range toRemove {
  210. removeArguments.addTarget(pkg)
  211. }
  212. oldValue := config.NoConfirm
  213. config.NoConfirm = true
  214. passToPacman(removeArguments)
  215. config.NoConfirm = oldValue
  216. }
  217. return nil
  218. }
  219. func askEditPkgBuilds(pkgs []*rpc.Pkg, bases map[string][]*rpc.Pkg) error {
  220. for _, pkg := range pkgs {
  221. dir := config.BuildDir + pkg.PackageBase + "/"
  222. str := "Edit PKGBUILD? " + pkg.PackageBase
  223. if len(bases[pkg.PackageBase]) > 1 || pkg.PackageBase != pkg.Name {
  224. str += " ("
  225. for _, split := range bases[pkg.PackageBase] {
  226. str += split.Name + " "
  227. }
  228. str = str[:len(str)-1] + ")"
  229. }
  230. if !continueTask(str, "yY") {
  231. editcmd := exec.Command(editor(), dir+"PKGBUILD")
  232. editcmd.Stdin, editcmd.Stdout, editcmd.Stderr = os.Stdin, os.Stdout, os.Stderr
  233. editcmd.Run()
  234. }
  235. }
  236. return nil
  237. }
  238. func parsesrcinfos(pkgs []*rpc.Pkg, srcinfos map[string]*gopkg.PKGBUILD) error {
  239. for _, pkg := range pkgs {
  240. dir := config.BuildDir + pkg.PackageBase + "/"
  241. cmd := exec.Command(config.MakepkgBin, "--printsrcinfo")
  242. cmd.Stderr = os.Stderr
  243. cmd.Dir = dir
  244. srcinfo, err := cmd.Output()
  245. if err != nil {
  246. return err
  247. }
  248. pkgbuild, err := gopkg.ParseSRCINFOContent(srcinfo)
  249. if err == nil {
  250. srcinfos[pkg.PackageBase] = pkgbuild
  251. for _, pkgsource := range pkgbuild.Source {
  252. owner, repo := parseSource(pkgsource)
  253. if owner != "" && repo != "" {
  254. err = branchInfo(pkg.Name, owner, repo)
  255. if err != nil {
  256. return err
  257. }
  258. }
  259. }
  260. }
  261. }
  262. return nil
  263. }
  264. func dowloadPkgBuilds(pkgs []*rpc.Pkg, bases map[string][]*rpc.Pkg) (err error) {
  265. for _, pkg := range pkgs {
  266. //todo make pretty
  267. str := "Downloading: " + pkg.PackageBase + "-" + pkg.Version
  268. if len(bases[pkg.PackageBase]) > 1 || pkg.PackageBase != pkg.Name {
  269. str += " ("
  270. for _, split := range bases[pkg.PackageBase] {
  271. str += split.Name + " "
  272. }
  273. str = str[:len(str)-1] + ")"
  274. }
  275. fmt.Println(str)
  276. err = downloadAndUnpack(baseURL+pkg.URLPath, config.BuildDir, false)
  277. if err != nil {
  278. return
  279. }
  280. }
  281. return
  282. }
  283. func downloadPkgBuildsSources(pkgs []*rpc.Pkg) (err error) {
  284. for _, pkg := range pkgs {
  285. dir := config.BuildDir + pkg.PackageBase + "/"
  286. err = passToMakepkg(dir, "--nobuild", "--nocheck", "--noprepare", "--nodeps")
  287. if err != nil {
  288. return
  289. }
  290. }
  291. return
  292. }
  293. func buildInstallPkgBuilds(pkgs []*rpc.Pkg, srcinfos map[string]*gopkg.PKGBUILD, targets stringSet, parser *arguments, bases map[string][]*rpc.Pkg) error {
  294. //for n := len(pkgs) -1 ; n > 0; n-- {
  295. for n := 0; n < len(pkgs); n++ {
  296. pkg := pkgs[n]
  297. dir := config.BuildDir + pkg.PackageBase + "/"
  298. built := true
  299. srcinfo := srcinfos[pkg.PackageBase]
  300. version := srcinfo.CompleteVersion()
  301. for _, split := range bases[pkg.PackageBase] {
  302. file, err := completeFileName(dir, split.Name+"-"+version.String())
  303. if err != nil {
  304. return err
  305. }
  306. if file == "" {
  307. built = false
  308. }
  309. }
  310. if built {
  311. fmt.Println(boldRedFgBlackBg(arrow+" Warning:"),
  312. blackBg(pkg.Name+"-"+pkg.Version+" Already made -- skipping build"))
  313. } else {
  314. err := passToMakepkg(dir, "-Cscf", "--noconfirm")
  315. if err != nil {
  316. return err
  317. }
  318. }
  319. arguments := parser.copy()
  320. arguments.targets = make(stringSet)
  321. arguments.op = "U"
  322. arguments.delArg("confirm")
  323. arguments.delArg("c", "clean")
  324. arguments.delArg("q", "quiet")
  325. arguments.delArg("q", "quiet")
  326. arguments.delArg("y", "refresh")
  327. arguments.delArg("u", "sysupgrade")
  328. arguments.delArg("w", "downloadonly")
  329. depArguments := makeArguments()
  330. depArguments.addArg("D", "asdeps")
  331. for _, split := range bases[pkg.PackageBase] {
  332. file, err := completeFileName(dir, split.Name+"-"+version.String())
  333. if err != nil {
  334. return err
  335. }
  336. if file == "" {
  337. return fmt.Errorf("Could not find built package " + split.Name + "-" + version.String())
  338. }
  339. arguments.addTarget(file)
  340. if !targets.get(split.Name) {
  341. depArguments.addTarget(split.Name)
  342. }
  343. }
  344. oldConfirm := config.NoConfirm
  345. config.NoConfirm = true
  346. err := passToPacman(arguments)
  347. if err != nil {
  348. return err
  349. }
  350. if len(depArguments.targets) > 0 {
  351. err = passToPacman(depArguments)
  352. if err != nil {
  353. return err
  354. }
  355. }
  356. config.NoConfirm = oldConfirm
  357. }
  358. return nil
  359. }
  360. func clean(pkgs []*rpc.Pkg) {
  361. for _, pkg := range pkgs {
  362. dir := config.BuildDir + pkg.PackageBase + "/"
  363. fmt.Println(boldGreenFg(arrow +
  364. " CleanAfter enabled. Deleting " + pkg.Name + " source folder."))
  365. os.RemoveAll(dir)
  366. }
  367. }
  368. func completeFileName(dir, name string) (string, error) {
  369. files, err := ioutil.ReadDir(dir)
  370. if err != nil {
  371. return "", err
  372. }
  373. for _, file := range files {
  374. if file.IsDir() {
  375. continue
  376. }
  377. if strings.HasPrefix(file.Name(), name) {
  378. return dir + file.Name(), nil
  379. }
  380. }
  381. return "", nil
  382. }