install.go 24 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079
  1. package main
  2. import (
  3. "fmt"
  4. "os"
  5. "os/exec"
  6. "path/filepath"
  7. "strconv"
  8. "strings"
  9. "sync"
  10. gosrc "github.com/Morganamilo/go-srcinfo"
  11. alpm "github.com/jguer/go-alpm"
  12. )
  13. // Install handles package installs
  14. func install(parser *arguments) error {
  15. var err error
  16. var incompatible stringSet
  17. var do *depOrder
  18. var aurUp upSlice
  19. var repoUp upSlice
  20. var srcinfos map[string]*gosrc.Srcinfo
  21. warnings := &aurWarnings{}
  22. removeMake := false
  23. if mode == modeAny || mode == modeRepo {
  24. if config.CombinedUpgrade {
  25. if parser.existsArg("y", "refresh") {
  26. err = earlyRefresh(parser)
  27. if err != nil {
  28. return fmt.Errorf("Error refreshing databases")
  29. }
  30. }
  31. } else if parser.existsArg("y", "refresh") || parser.existsArg("u", "sysupgrade") || len(parser.targets) > 0 {
  32. err = earlyPacmanCall(parser)
  33. if err != nil {
  34. return err
  35. }
  36. }
  37. }
  38. //we may have done -Sy, our handle now has an old
  39. //database.
  40. err = initAlpmHandle()
  41. if err != nil {
  42. return err
  43. }
  44. _, _, localNames, remoteNames, err := filterPackages()
  45. if err != nil {
  46. return err
  47. }
  48. remoteNamesCache := sliceToStringSet(remoteNames)
  49. localNamesCache := sliceToStringSet(localNames)
  50. requestTargets := parser.copy().targets
  51. //create the arguments to pass for the repo install
  52. arguments := parser.copy()
  53. arguments.delArg("asdeps", "asdep")
  54. arguments.delArg("asexplicit", "asexp")
  55. arguments.op = "S"
  56. arguments.clearTargets()
  57. if mode == modeAUR {
  58. arguments.delArg("u", "sysupgrade")
  59. }
  60. //if we are doing -u also request all packages needing update
  61. if parser.existsArg("u", "sysupgrade") {
  62. aurUp, repoUp, err = upList(warnings)
  63. if err != nil {
  64. return err
  65. }
  66. warnings.print()
  67. ignore, aurUp, err := upgradePkgs(aurUp, repoUp)
  68. if err != nil {
  69. return err
  70. }
  71. for _, up := range repoUp {
  72. if !ignore.get(up.Name) {
  73. requestTargets = append(requestTargets, up.Name)
  74. parser.addTarget(up.Name)
  75. }
  76. }
  77. for up := range aurUp {
  78. requestTargets = append(requestTargets, "aur/"+up)
  79. parser.addTarget("aur/" + up)
  80. }
  81. value, _, exists := cmdArgs.getArg("ignore")
  82. if len(ignore) > 0 {
  83. ignoreStr := strings.Join(ignore.toSlice(), ",")
  84. if exists {
  85. ignoreStr += "," + value
  86. }
  87. arguments.options["ignore"] = ignoreStr
  88. }
  89. }
  90. targets := sliceToStringSet(parser.targets)
  91. dp, err := getDepPool(requestTargets, warnings)
  92. if err != nil {
  93. return err
  94. }
  95. err = dp.CheckMissing()
  96. if err != nil {
  97. return err
  98. }
  99. if len(dp.Aur) == 0 {
  100. if !config.CombinedUpgrade {
  101. if parser.existsArg("u", "sysupgrade") {
  102. fmt.Println(" there is nothing to do")
  103. }
  104. return nil
  105. }
  106. parser.op = "S"
  107. parser.delArg("y", "refresh")
  108. parser.options["ignore"] = arguments.options["ignore"]
  109. return show(passToPacman(parser))
  110. }
  111. if len(dp.Aur) > 0 && 0 == os.Geteuid() {
  112. return fmt.Errorf(bold(red(arrow)) + " Refusing to install AUR Packages as root, Aborting.")
  113. }
  114. conflicts, err := dp.CheckConflicts()
  115. if err != nil {
  116. return err
  117. }
  118. do = getDepOrder(dp)
  119. if err != nil {
  120. return err
  121. }
  122. for _, pkg := range do.Repo {
  123. arguments.addTarget(pkg.DB().Name() + "/" + pkg.Name())
  124. }
  125. for _, pkg := range dp.Groups {
  126. arguments.addTarget(pkg)
  127. }
  128. if len(do.Aur) == 0 && len(arguments.targets) == 0 && (!parser.existsArg("u", "sysupgrade") || mode == modeAUR) {
  129. fmt.Println(" there is nothing to do")
  130. return nil
  131. }
  132. do.Print()
  133. fmt.Println()
  134. if do.HasMake() {
  135. if config.RemoveMake == "yes" {
  136. removeMake = true
  137. } else if config.RemoveMake == "no" {
  138. removeMake = false
  139. } else if continueTask("Remove make dependencies after install?", false) {
  140. removeMake = true
  141. }
  142. }
  143. if config.CleanMenu {
  144. if anyExistInCache(do.Aur) {
  145. askClean := pkgbuildNumberMenu(do.Aur, remoteNamesCache)
  146. toClean, err := cleanNumberMenu(do.Aur, remoteNamesCache, askClean)
  147. if err != nil {
  148. return err
  149. }
  150. cleanBuilds(toClean)
  151. }
  152. }
  153. toSkip := pkgbuildsToSkip(do.Aur, targets)
  154. cloned, err := downloadPkgbuilds(do.Aur, toSkip, config.BuildDir)
  155. if err != nil {
  156. return err
  157. }
  158. var toDiff []Base
  159. var toEdit []Base
  160. if config.DiffMenu {
  161. pkgbuildNumberMenu(do.Aur, remoteNamesCache)
  162. toDiff, err = diffNumberMenu(do.Aur, remoteNamesCache)
  163. if err != nil {
  164. return err
  165. }
  166. if len(toDiff) > 0 {
  167. err = showPkgbuildDiffs(toDiff, cloned)
  168. if err != nil {
  169. return err
  170. }
  171. }
  172. }
  173. if len(toDiff) > 0 {
  174. oldValue := config.NoConfirm
  175. config.NoConfirm = false
  176. fmt.Println()
  177. if !continueTask(bold(green("Proceed with install?")), true) {
  178. return fmt.Errorf("Aborting due to user")
  179. }
  180. config.NoConfirm = oldValue
  181. }
  182. err = mergePkgbuilds(do.Aur)
  183. if err != nil {
  184. return err
  185. }
  186. srcinfos, err = parseSrcinfoFiles(do.Aur, true)
  187. if err != nil {
  188. return err
  189. }
  190. if config.EditMenu {
  191. pkgbuildNumberMenu(do.Aur, remoteNamesCache)
  192. toEdit, err = editNumberMenu(do.Aur, remoteNamesCache)
  193. if err != nil {
  194. return err
  195. }
  196. if len(toEdit) > 0 {
  197. err = editPkgbuilds(toEdit, srcinfos)
  198. if err != nil {
  199. return err
  200. }
  201. }
  202. }
  203. if len(toEdit) > 0 {
  204. oldValue := config.NoConfirm
  205. config.NoConfirm = false
  206. fmt.Println()
  207. if !continueTask(bold(green("Proceed with install?")), true) {
  208. return fmt.Errorf("Aborting due to user")
  209. }
  210. config.NoConfirm = oldValue
  211. }
  212. incompatible, err = getIncompatible(do.Aur, srcinfos)
  213. if err != nil {
  214. return err
  215. }
  216. if config.PGPFetch {
  217. err = checkPgpKeys(do.Aur, srcinfos)
  218. if err != nil {
  219. return err
  220. }
  221. }
  222. if !config.CombinedUpgrade {
  223. arguments.delArg("u", "sysupgrade")
  224. }
  225. if len(arguments.targets) > 0 || arguments.existsArg("u") {
  226. err := show(passToPacman(arguments))
  227. if err != nil {
  228. return fmt.Errorf("Error installing repo packages")
  229. }
  230. depArguments := makeArguments()
  231. depArguments.addArg("D", "asdeps")
  232. expArguments := makeArguments()
  233. expArguments.addArg("D", "asexplicit")
  234. for _, pkg := range do.Repo {
  235. if !dp.Explicit.get(pkg.Name()) && !localNamesCache.get(pkg.Name()) && !remoteNamesCache.get(pkg.Name()) {
  236. depArguments.addTarget(pkg.Name())
  237. continue
  238. }
  239. if parser.existsArg("asdeps", "asdep") && dp.Explicit.get(pkg.Name()) {
  240. depArguments.addTarget(pkg.Name())
  241. } else if parser.existsArg("asexp", "asexplicit") && dp.Explicit.get(pkg.Name()) {
  242. expArguments.addTarget(pkg.Name())
  243. }
  244. }
  245. if len(depArguments.targets) > 0 {
  246. _, stderr, err := capture(passToPacman(depArguments))
  247. if err != nil {
  248. return fmt.Errorf("%s%s", stderr, err)
  249. }
  250. }
  251. if len(expArguments.targets) > 0 {
  252. _, stderr, err := capture(passToPacman(expArguments))
  253. if err != nil {
  254. return fmt.Errorf("%s%s", stderr, err)
  255. }
  256. }
  257. }
  258. go updateCompletion(false)
  259. err = downloadPkgbuildsSources(do.Aur, incompatible)
  260. if err != nil {
  261. return err
  262. }
  263. err = buildInstallPkgbuilds(dp, do, srcinfos, parser, incompatible, conflicts)
  264. if err != nil {
  265. return err
  266. }
  267. if removeMake {
  268. removeArguments := makeArguments()
  269. removeArguments.addArg("R", "u")
  270. for _, pkg := range do.getMake() {
  271. removeArguments.addTarget(pkg)
  272. }
  273. oldValue := config.NoConfirm
  274. config.NoConfirm = true
  275. err = show(passToPacman(removeArguments))
  276. config.NoConfirm = oldValue
  277. if err != nil {
  278. return err
  279. }
  280. }
  281. if config.CleanAfter {
  282. cleanAfter(do.Aur)
  283. }
  284. return nil
  285. }
  286. func inRepos(syncDB alpm.DBList, pkg string) bool {
  287. target := toTarget(pkg)
  288. if target.DB == "aur" {
  289. return false
  290. } else if target.DB != "" {
  291. return true
  292. }
  293. previousHideMenus := hideMenus
  294. hideMenus = false
  295. _, err := syncDB.FindSatisfier(target.DepString())
  296. hideMenus = previousHideMenus
  297. if err == nil {
  298. return true
  299. }
  300. _, err = syncDB.FindGroupPkgs(target.Name)
  301. if err == nil {
  302. return true
  303. }
  304. return false
  305. }
  306. func earlyPacmanCall(parser *arguments) error {
  307. arguments := parser.copy()
  308. arguments.op = "S"
  309. targets := parser.targets
  310. parser.clearTargets()
  311. arguments.clearTargets()
  312. syncDB, err := alpmHandle.SyncDBs()
  313. if err != nil {
  314. return err
  315. }
  316. if mode == modeRepo {
  317. arguments.targets = targets
  318. } else {
  319. //separate aur and repo targets
  320. for _, target := range targets {
  321. if inRepos(syncDB, target) {
  322. arguments.addTarget(target)
  323. } else {
  324. parser.addTarget(target)
  325. }
  326. }
  327. }
  328. if parser.existsArg("y", "refresh") || parser.existsArg("u", "sysupgrade") || len(arguments.targets) > 0 {
  329. err = show(passToPacman(arguments))
  330. if err != nil {
  331. return fmt.Errorf("Error installing repo packages")
  332. }
  333. }
  334. return nil
  335. }
  336. func earlyRefresh(parser *arguments) error {
  337. arguments := parser.copy()
  338. parser.delArg("y", "refresh")
  339. arguments.delArg("u", "sysupgrade")
  340. arguments.delArg("s", "search")
  341. arguments.delArg("i", "info")
  342. arguments.delArg("l", "list")
  343. arguments.clearTargets()
  344. return show(passToPacman(arguments))
  345. }
  346. func getIncompatible(bases []Base, srcinfos map[string]*gosrc.Srcinfo) (stringSet, error) {
  347. incompatible := make(stringSet)
  348. basesMap := make(map[string]Base)
  349. alpmArch, err := alpmHandle.Arch()
  350. if err != nil {
  351. return nil, err
  352. }
  353. nextpkg:
  354. for _, base := range bases {
  355. for _, arch := range srcinfos[base.Pkgbase()].Arch {
  356. if arch == "any" || arch == alpmArch {
  357. continue nextpkg
  358. }
  359. }
  360. incompatible.set(base.Pkgbase())
  361. basesMap[base.Pkgbase()] = base
  362. }
  363. if len(incompatible) > 0 {
  364. fmt.Println()
  365. fmt.Print(bold(yellow(arrow)) + " The following packages are not compatible with your architecture:")
  366. for pkg := range incompatible {
  367. fmt.Print(" " + cyan(basesMap[pkg].String()))
  368. }
  369. fmt.Println()
  370. if !continueTask("Try to build them anyway?", true) {
  371. return nil, fmt.Errorf("Aborting due to user")
  372. }
  373. }
  374. return incompatible, nil
  375. }
  376. func parsePackageList(dir string) (map[string]string, string, error) {
  377. stdout, stderr, err := capture(passToMakepkg(dir, "--packagelist"))
  378. if err != nil {
  379. return nil, "", fmt.Errorf("%s%s", stderr, err)
  380. }
  381. var version string
  382. lines := strings.Split(stdout, "\n")
  383. pkgdests := make(map[string]string)
  384. for _, line := range lines {
  385. if line == "" {
  386. continue
  387. }
  388. fileName := filepath.Base(line)
  389. split := strings.Split(fileName, "-")
  390. if len(split) < 4 {
  391. return nil, "", fmt.Errorf("Can not find package name : %s", split)
  392. }
  393. // pkgname-pkgver-pkgrel-arch.pkgext
  394. // This assumes 3 dashes after the pkgname, Will cause an error
  395. // if the PKGEXT contains a dash. Please no one do that.
  396. pkgname := strings.Join(split[:len(split)-3], "-")
  397. version = strings.Join(split[len(split)-3:len(split)-1], "-")
  398. pkgdests[pkgname] = line
  399. }
  400. return pkgdests, version, nil
  401. }
  402. func anyExistInCache(bases []Base) bool {
  403. for _, base := range bases {
  404. pkg := base.Pkgbase()
  405. dir := filepath.Join(config.BuildDir, pkg)
  406. if _, err := os.Stat(dir); !os.IsNotExist(err) {
  407. return true
  408. }
  409. }
  410. return false
  411. }
  412. func pkgbuildNumberMenu(bases []Base, installed stringSet) bool {
  413. toPrint := ""
  414. askClean := false
  415. for n, base := range bases {
  416. pkg := base.Pkgbase()
  417. dir := filepath.Join(config.BuildDir, pkg)
  418. toPrint += fmt.Sprintf(magenta("%3d")+" %-40s", len(bases)-n,
  419. bold(base.String()))
  420. anyInstalled := false
  421. for _, b := range base {
  422. anyInstalled = anyInstalled || installed.get(b.Name)
  423. }
  424. if anyInstalled {
  425. toPrint += bold(green(" (Installed)"))
  426. }
  427. if _, err := os.Stat(dir); !os.IsNotExist(err) {
  428. toPrint += bold(green(" (Build Files Exist)"))
  429. askClean = true
  430. }
  431. toPrint += "\n"
  432. }
  433. fmt.Print(toPrint)
  434. return askClean
  435. }
  436. func cleanNumberMenu(bases []Base, installed stringSet, hasClean bool) ([]Base, error) {
  437. toClean := make([]Base, 0)
  438. if !hasClean {
  439. return toClean, nil
  440. }
  441. fmt.Println(bold(green(arrow + " Packages to cleanBuild?")))
  442. fmt.Println(bold(green(arrow) + cyan(" [N]one ") + "[A]ll [Ab]ort [I]nstalled [No]tInstalled or (1 2 3, 1-3, ^4)"))
  443. fmt.Print(bold(green(arrow + " ")))
  444. cleanInput, err := getInput(config.AnswerClean)
  445. if err != nil {
  446. return nil, err
  447. }
  448. cInclude, cExclude, cOtherInclude, cOtherExclude := parseNumberMenu(cleanInput)
  449. cIsInclude := len(cExclude) == 0 && len(cOtherExclude) == 0
  450. if cOtherInclude.get("abort") || cOtherInclude.get("ab") {
  451. return nil, fmt.Errorf("Aborting due to user")
  452. }
  453. if !cOtherInclude.get("n") && !cOtherInclude.get("none") {
  454. for i, base := range bases {
  455. pkg := base.Pkgbase()
  456. anyInstalled := false
  457. for _, b := range base {
  458. anyInstalled = anyInstalled || installed.get(b.Name)
  459. }
  460. dir := filepath.Join(config.BuildDir, pkg)
  461. if _, err := os.Stat(dir); os.IsNotExist(err) {
  462. continue
  463. }
  464. if !cIsInclude && cExclude.get(len(bases)-i) {
  465. continue
  466. }
  467. if anyInstalled && (cOtherInclude.get("i") || cOtherInclude.get("installed")) {
  468. toClean = append(toClean, base)
  469. continue
  470. }
  471. if !anyInstalled && (cOtherInclude.get("no") || cOtherInclude.get("notinstalled")) {
  472. toClean = append(toClean, base)
  473. continue
  474. }
  475. if cOtherInclude.get("a") || cOtherInclude.get("all") {
  476. toClean = append(toClean, base)
  477. continue
  478. }
  479. if cIsInclude && (cInclude.get(len(bases)-i) || cOtherInclude.get(pkg)) {
  480. toClean = append(toClean, base)
  481. continue
  482. }
  483. if !cIsInclude && (!cExclude.get(len(bases)-i) && !cOtherExclude.get(pkg)) {
  484. toClean = append(toClean, base)
  485. continue
  486. }
  487. }
  488. }
  489. return toClean, nil
  490. }
  491. func editNumberMenu(bases []Base, installed stringSet) ([]Base, error) {
  492. return editDiffNumberMenu(bases, installed, false)
  493. }
  494. func diffNumberMenu(bases []Base, installed stringSet) ([]Base, error) {
  495. return editDiffNumberMenu(bases, installed, true)
  496. }
  497. func editDiffNumberMenu(bases []Base, installed stringSet, diff bool) ([]Base, error) {
  498. toEdit := make([]Base, 0)
  499. var editInput string
  500. var err error
  501. fmt.Println(bold(green(arrow) + cyan(" [N]one ") + "[A]ll [Ab]ort [I]nstalled [No]tInstalled or (1 2 3, 1-3, ^4)"))
  502. if diff {
  503. fmt.Println(bold(green(arrow + " Diffs to show?")))
  504. fmt.Print(bold(green(arrow + " ")))
  505. editInput, err = getInput(config.AnswerDiff)
  506. if err != nil {
  507. return nil, err
  508. }
  509. } else {
  510. fmt.Println(bold(green(arrow + " PKGBUILDs to edit?")))
  511. fmt.Print(bold(green(arrow + " ")))
  512. editInput, err = getInput(config.AnswerEdit)
  513. if err != nil {
  514. return nil, err
  515. }
  516. }
  517. eInclude, eExclude, eOtherInclude, eOtherExclude := parseNumberMenu(editInput)
  518. eIsInclude := len(eExclude) == 0 && len(eOtherExclude) == 0
  519. if eOtherInclude.get("abort") || eOtherInclude.get("ab") {
  520. return nil, fmt.Errorf("Aborting due to user")
  521. }
  522. if !eOtherInclude.get("n") && !eOtherInclude.get("none") {
  523. for i, base := range bases {
  524. pkg := base.Pkgbase()
  525. anyInstalled := false
  526. for _, b := range base {
  527. anyInstalled = anyInstalled || installed.get(b.Name)
  528. }
  529. if !eIsInclude && eExclude.get(len(bases)-i) {
  530. continue
  531. }
  532. if anyInstalled && (eOtherInclude.get("i") || eOtherInclude.get("installed")) {
  533. toEdit = append(toEdit, base)
  534. continue
  535. }
  536. if !anyInstalled && (eOtherInclude.get("no") || eOtherInclude.get("notinstalled")) {
  537. toEdit = append(toEdit, base)
  538. continue
  539. }
  540. if eOtherInclude.get("a") || eOtherInclude.get("all") {
  541. toEdit = append(toEdit, base)
  542. continue
  543. }
  544. if eIsInclude && (eInclude.get(len(bases)-i) || eOtherInclude.get(pkg)) {
  545. toEdit = append(toEdit, base)
  546. }
  547. if !eIsInclude && (!eExclude.get(len(bases)-i) && !eOtherExclude.get(pkg)) {
  548. toEdit = append(toEdit, base)
  549. }
  550. }
  551. }
  552. return toEdit, nil
  553. }
  554. func showPkgbuildDiffs(bases []Base, cloned stringSet) error {
  555. for _, base := range bases {
  556. pkg := base.Pkgbase()
  557. dir := filepath.Join(config.BuildDir, pkg)
  558. if shouldUseGit(dir) {
  559. start := "HEAD"
  560. if cloned.get(pkg) {
  561. start = gitEmptyTree
  562. } else {
  563. hasDiff, err := gitHasDiff(config.BuildDir, pkg)
  564. if err != nil {
  565. return err
  566. }
  567. if !hasDiff {
  568. fmt.Printf("%s %s: %s\n", bold(yellow(arrow)), cyan(base.String()), bold("No changes -- skipping"))
  569. continue
  570. }
  571. }
  572. args := []string{"diff", start + "..HEAD@{upstream}", "--src-prefix", dir + "/", "--dst-prefix", dir + "/", "--", ".", ":(exclude).SRCINFO"}
  573. if useColor {
  574. args = append(args, "--color=always")
  575. } else {
  576. args = append(args, "--color=never")
  577. }
  578. err := show(passToGit(dir, args...))
  579. if err != nil {
  580. return err
  581. }
  582. } else {
  583. args := []string{"diff"}
  584. if useColor {
  585. args = append(args, "--color=always")
  586. } else {
  587. args = append(args, "--color=never")
  588. }
  589. args = append(args, "--no-index", "/var/empty", dir)
  590. // git always returns 1. why? I have no idea
  591. show(passToGit(dir, args...))
  592. }
  593. }
  594. return nil
  595. }
  596. func editPkgbuilds(bases []Base, srcinfos map[string]*gosrc.Srcinfo) error {
  597. pkgbuilds := make([]string, 0, len(bases))
  598. for _, base := range bases {
  599. pkg := base.Pkgbase()
  600. dir := filepath.Join(config.BuildDir, pkg)
  601. pkgbuilds = append(pkgbuilds, filepath.Join(dir, "PKGBUILD"))
  602. for _, splitPkg := range srcinfos[pkg].SplitPackages() {
  603. if splitPkg.Install != "" {
  604. pkgbuilds = append(pkgbuilds, filepath.Join(dir, splitPkg.Install))
  605. }
  606. }
  607. }
  608. if len(pkgbuilds) > 0 {
  609. editor, editorArgs := editor()
  610. editorArgs = append(editorArgs, pkgbuilds...)
  611. editcmd := exec.Command(editor, editorArgs...)
  612. editcmd.Stdin, editcmd.Stdout, editcmd.Stderr = os.Stdin, os.Stdout, os.Stderr
  613. err := editcmd.Run()
  614. if err != nil {
  615. return fmt.Errorf("Editor did not exit successfully, Aborting: %s", err)
  616. }
  617. }
  618. return nil
  619. }
  620. func parseSrcinfoFiles(bases []Base, errIsFatal bool) (map[string]*gosrc.Srcinfo, error) {
  621. srcinfos := make(map[string]*gosrc.Srcinfo)
  622. for k, base := range bases {
  623. pkg := base.Pkgbase()
  624. dir := filepath.Join(config.BuildDir, pkg)
  625. str := bold(cyan("::") + " Parsing SRCINFO (%d/%d): %s\n")
  626. fmt.Printf(str, k+1, len(bases), cyan(base.String()))
  627. pkgbuild, err := gosrc.ParseFile(filepath.Join(dir, ".SRCINFO"))
  628. if err != nil {
  629. if !errIsFatal {
  630. fmt.Fprintf(os.Stderr, "failed to parse %s -- skipping: %s\n", base.String(), err)
  631. continue
  632. }
  633. return nil, fmt.Errorf("failed to parse %s: %s", base.String(), err)
  634. }
  635. srcinfos[pkg] = pkgbuild
  636. }
  637. return srcinfos, nil
  638. }
  639. func pkgbuildsToSkip(bases []Base, targets stringSet) stringSet {
  640. toSkip := make(stringSet)
  641. for _, base := range bases {
  642. isTarget := false
  643. for _, pkg := range base {
  644. isTarget = isTarget || targets.get(pkg.Name)
  645. }
  646. if (config.ReDownload == "yes" && isTarget) || config.ReDownload == "all" {
  647. continue
  648. }
  649. dir := filepath.Join(config.BuildDir, base.Pkgbase(), ".SRCINFO")
  650. pkgbuild, err := gosrc.ParseFile(dir)
  651. if err == nil {
  652. if alpm.VerCmp(pkgbuild.Version(), base.Version()) >= 0 {
  653. toSkip.set(base.Pkgbase())
  654. }
  655. }
  656. }
  657. return toSkip
  658. }
  659. func mergePkgbuilds(bases []Base) error {
  660. for _, base := range bases {
  661. if shouldUseGit(filepath.Join(config.BuildDir, base.Pkgbase())) {
  662. err := gitMerge(config.BuildDir, base.Pkgbase())
  663. if err != nil {
  664. return err
  665. }
  666. }
  667. }
  668. return nil
  669. }
  670. func downloadPkgbuilds(bases []Base, toSkip stringSet, buildDir string) (stringSet, error) {
  671. cloned := make(stringSet)
  672. downloaded := 0
  673. var wg sync.WaitGroup
  674. var mux sync.Mutex
  675. var errs MultiError
  676. download := func(k int, base Base) {
  677. defer wg.Done()
  678. pkg := base.Pkgbase()
  679. if toSkip.get(pkg) {
  680. mux.Lock()
  681. downloaded++
  682. str := bold(cyan("::") + " PKGBUILD up to date, Skipping (%d/%d): %s\n")
  683. fmt.Printf(str, downloaded, len(bases), cyan(base.String()))
  684. mux.Unlock()
  685. return
  686. }
  687. if shouldUseGit(filepath.Join(config.BuildDir, pkg)) {
  688. clone, err := gitDownload(config.AURURL+"/"+pkg+".git", buildDir, pkg)
  689. if err != nil {
  690. errs.Add(err)
  691. return
  692. }
  693. if clone {
  694. mux.Lock()
  695. cloned.set(pkg)
  696. mux.Unlock()
  697. }
  698. } else {
  699. err := downloadAndUnpack(config.AURURL+base.URLPath(), buildDir)
  700. if err != nil {
  701. errs.Add(err)
  702. return
  703. }
  704. }
  705. mux.Lock()
  706. downloaded++
  707. str := bold(cyan("::") + " Downloaded PKGBUILD (%d/%d): %s\n")
  708. fmt.Printf(str, downloaded, len(bases), cyan(base.String()))
  709. mux.Unlock()
  710. }
  711. count := 0
  712. for k, base := range bases {
  713. wg.Add(1)
  714. go download(k, base)
  715. count++
  716. if count%25 == 0 {
  717. wg.Wait()
  718. }
  719. }
  720. wg.Wait()
  721. return cloned, errs.Return()
  722. }
  723. func downloadPkgbuildsSources(bases []Base, incompatible stringSet) (err error) {
  724. for _, base := range bases {
  725. pkg := base.Pkgbase()
  726. dir := filepath.Join(config.BuildDir, pkg)
  727. args := []string{"--verifysource", "-Ccf"}
  728. if incompatible.get(pkg) {
  729. args = append(args, "--ignorearch")
  730. }
  731. err = show(passToMakepkg(dir, args...))
  732. if err != nil {
  733. return fmt.Errorf("Error downloading sources: %s", cyan(base.String()))
  734. }
  735. }
  736. return
  737. }
  738. func buildInstallPkgbuilds(dp *depPool, do *depOrder, srcinfos map[string]*gosrc.Srcinfo, parser *arguments, incompatible stringSet, conflicts mapStringSet) error {
  739. for _, base := range do.Aur {
  740. pkg := base.Pkgbase()
  741. dir := filepath.Join(config.BuildDir, pkg)
  742. built := true
  743. srcinfo := srcinfos[pkg]
  744. args := []string{"--nobuild", "-fC"}
  745. if incompatible.get(pkg) {
  746. args = append(args, "--ignorearch")
  747. }
  748. //pkgver bump
  749. err := show(passToMakepkg(dir, args...))
  750. if err != nil {
  751. return fmt.Errorf("Error making: %s", base.String())
  752. }
  753. pkgdests, version, err := parsePackageList(dir)
  754. if err != nil {
  755. return err
  756. }
  757. isExplicit := false
  758. for _, b := range base {
  759. isExplicit = isExplicit || dp.Explicit.get(b.Name)
  760. }
  761. if config.ReBuild == "no" || (config.ReBuild == "yes" && !isExplicit) {
  762. for _, split := range base {
  763. pkgdest, ok := pkgdests[split.Name]
  764. if !ok {
  765. return fmt.Errorf("Could not find PKGDEST for: %s", split.Name)
  766. }
  767. _, err := os.Stat(pkgdest)
  768. if os.IsNotExist(err) {
  769. built = false
  770. } else if err != nil {
  771. return err
  772. }
  773. }
  774. } else {
  775. built = false
  776. }
  777. if cmdArgs.existsArg("needed") {
  778. installed := true
  779. for _, split := range base {
  780. if alpmpkg, err := dp.LocalDB.Pkg(split.Name); err != nil || alpmpkg.Version() != version {
  781. installed = false
  782. }
  783. }
  784. if installed {
  785. show(passToMakepkg(dir, "-c", "--nobuild", "--noextract", "--ignorearch"))
  786. fmt.Println(cyan(pkg+"-"+version) + bold(" is up to date -- skipping"))
  787. continue
  788. }
  789. }
  790. if built {
  791. show(passToMakepkg(dir, "-c", "--nobuild", "--noextract", "--ignorearch"))
  792. fmt.Println(bold(yellow(arrow)),
  793. cyan(pkg+"-"+version)+bold(" already made -- skipping build"))
  794. } else {
  795. args := []string{"-cf", "--noconfirm", "--noextract", "--noprepare", "--holdver"}
  796. if incompatible.get(pkg) {
  797. args = append(args, "--ignorearch")
  798. }
  799. err := show(passToMakepkg(dir, args...))
  800. if err != nil {
  801. return fmt.Errorf("Error making: %s", base.String())
  802. }
  803. }
  804. arguments := parser.copy()
  805. arguments.clearTargets()
  806. arguments.op = "U"
  807. arguments.delArg("confirm")
  808. arguments.delArg("noconfirm")
  809. arguments.delArg("c", "clean")
  810. arguments.delArg("q", "quiet")
  811. arguments.delArg("q", "quiet")
  812. arguments.delArg("y", "refresh")
  813. arguments.delArg("u", "sysupgrade")
  814. arguments.delArg("w", "downloadonly")
  815. oldConfirm := config.NoConfirm
  816. //conflicts have been checked so answer y for them
  817. if config.UseAsk {
  818. ask, _ := strconv.Atoi(cmdArgs.globals["ask"])
  819. uask := alpm.QuestionType(ask) | alpm.QuestionTypeConflictPkg
  820. cmdArgs.globals["ask"] = fmt.Sprint(uask)
  821. } else {
  822. conflict := false
  823. for _, split := range base {
  824. if _, ok := conflicts[split.Name]; ok {
  825. conflict = true
  826. }
  827. }
  828. if !conflict {
  829. config.NoConfirm = true
  830. }
  831. }
  832. depArguments := makeArguments()
  833. depArguments.addArg("D", "asdeps")
  834. expArguments := makeArguments()
  835. expArguments.addArg("D", "asexplicit")
  836. //remotenames: names of all non repo packages on the system
  837. _, _, localNames, remoteNames, err := filterPackages()
  838. if err != nil {
  839. return err
  840. }
  841. //cache as a stringset. maybe make it return a string set in the first
  842. //place
  843. remoteNamesCache := sliceToStringSet(remoteNames)
  844. localNamesCache := sliceToStringSet(localNames)
  845. for _, split := range base {
  846. pkgdest, ok := pkgdests[split.Name]
  847. if !ok {
  848. return fmt.Errorf("Could not find PKGDEST for: %s", split.Name)
  849. }
  850. arguments.addTarget(pkgdest)
  851. if !dp.Explicit.get(split.Name) && !localNamesCache.get(split.Name) && !remoteNamesCache.get(split.Name) {
  852. depArguments.addTarget(split.Name)
  853. }
  854. if dp.Explicit.get(split.Name) {
  855. if parser.existsArg("asdeps", "asdep") {
  856. depArguments.addTarget(split.Name)
  857. } else if parser.existsArg("asexplicit", "asexp") {
  858. expArguments.addTarget(split.Name)
  859. }
  860. }
  861. }
  862. err = show(passToPacman(arguments))
  863. if err != nil {
  864. return err
  865. }
  866. var mux sync.Mutex
  867. var wg sync.WaitGroup
  868. for _, pkg := range base {
  869. wg.Add(1)
  870. go updateVCSData(pkg.Name, srcinfo.Source, &mux, &wg)
  871. }
  872. wg.Wait()
  873. err = saveVCSInfo()
  874. if err != nil {
  875. fmt.Fprintln(os.Stderr, err)
  876. }
  877. if len(depArguments.targets) > 0 {
  878. _, stderr, err := capture(passToPacman(depArguments))
  879. if err != nil {
  880. return fmt.Errorf("%s%s", stderr, err)
  881. }
  882. }
  883. config.NoConfirm = oldConfirm
  884. }
  885. return nil
  886. }