install.go 9.8 KB

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