install.go 9.8 KB

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