Browse Source

Merge handles.Aur and depOrder.Bases

depOrder.Aur contains the order in which AUR packages are to be
installed. While depOrder.bases contains the actual package data
organized by pkgbase.

deoOrder.AUR is kind of counterintuitive, as it only contains one
package from each package base.

For example if you were to install libc++{,abi,experimental},
depOrder.Aur would only contain one of those packages, which one
actually being quite random. depOrder.Bases[pkg.Pkgbase] will then be
looked up and everything under that slice would be installed.

This means that the only real use depOrder.Aur has, is to give the
pkgbase. So to cut out the middleman, lets merge .Aur and .Bases into
a single field.

Doing this has also heped to spot som subtle bugs:

Fix subtle split package errors.

The number menus now correctly list and respect (installed) for bases
that have atleast one of their packages installed.

Entering package names in number menus now always expects the pkgbase
name instead of the random package which happened to make it into .Aur.

--rebuild and --redownload correctly handles split packages.

formatPkgbase is also used more.
morganamilo 6 years ago
parent
commit
43feb12c85
6 changed files with 219 additions and 171 deletions
  1. 8 8
      dep.go
  2. 28 15
      depOrder.go
  3. 157 122
      install.go
  4. 15 18
      keys.go
  5. 6 5
      print.go
  6. 5 3
      vcs.go

+ 8 - 8
dep.go

@@ -149,15 +149,15 @@ func splitDbFromName(pkg string) (string, string) {
 	return "", split[0]
 }
 
-func getBases(pkgs map[string]*rpc.Pkg) map[string][]*rpc.Pkg {
-	bases := make(map[string][]*rpc.Pkg)
-
+func getBases(pkgs map[string]*rpc.Pkg) []Base {
+	basesMap := make(map[string]Base)
 	for _, pkg := range pkgs {
-		_, ok := bases[pkg.PackageBase]
-		if !ok {
-			bases[pkg.PackageBase] = make([]*rpc.Pkg, 0)
-		}
-		bases[pkg.PackageBase] = append(bases[pkg.PackageBase], pkg)
+		basesMap[pkg.PackageBase] = append(basesMap[pkg.PackageBase], pkg)
+	}
+
+	bases := make([]Base, 0, len(basesMap))
+	for _, base := range basesMap {
+		bases = append(bases, base)
 	}
 
 	return bases

+ 28 - 15
depOrder.go

@@ -5,35 +5,48 @@ import (
 	rpc "github.com/mikkeloscar/aur"
 )
 
+type Base []*rpc.Pkg
+
+func (b Base) Pkgbase() string {
+	return b[0].PackageBase
+}
+
+func (b Base) Version() string {
+	return b[0].Version
+}
+
+func (b Base) URLPath() string {
+	return b[0].URLPath
+}
+
 type depOrder struct {
-	Aur     []*rpc.Pkg
+	Aur     []Base
 	Repo    []*alpm.Package
 	Runtime stringSet
-	Bases   map[string][]*rpc.Pkg
 }
 
 func makeDepOrder() *depOrder {
 	return &depOrder{
-		make([]*rpc.Pkg, 0),
+		make([]Base, 0),
 		make([]*alpm.Package, 0),
 		make(stringSet),
-		make(map[string][]*rpc.Pkg),
 	}
 }
 
 func getDepOrder(dp *depPool) *depOrder {
 	do := makeDepOrder()
+	basesMap := make(map[string]Base)
 
 	for _, target := range dp.Targets {
 		dep := target.DepString()
 		aurPkg := dp.Aur[dep]
 		if aurPkg != nil && pkgSatisfies(aurPkg.Name, aurPkg.Version, dep) {
-			do.orderPkgAur(aurPkg, dp, true)
+			do.orderPkgAur(aurPkg, dp, basesMap, true)
 		}
 
 		aurPkg = dp.findSatisfierAur(dep)
 		if aurPkg != nil {
-			do.orderPkgAur(aurPkg, dp, true)
+			do.orderPkgAur(aurPkg, dp, basesMap, true)
 		}
 
 		repoPkg := dp.findSatisfierRepo(dep)
@@ -42,10 +55,14 @@ func getDepOrder(dp *depPool) *depOrder {
 		}
 	}
 
+	for _, base := range basesMap {
+		do.Aur = append(do.Aur, base)
+	}
+
 	return do
 }
 
-func (do *depOrder) orderPkgAur(pkg *rpc.Pkg, dp *depPool, runtime bool) {
+func (do *depOrder) orderPkgAur(pkg *rpc.Pkg, dp *depPool, basesMap map[string]Base, runtime bool) {
 	if runtime {
 		do.Runtime.set(pkg.Name)
 	}
@@ -55,7 +72,7 @@ func (do *depOrder) orderPkgAur(pkg *rpc.Pkg, dp *depPool, runtime bool) {
 		for _, dep := range deps {
 			aurPkg := dp.findSatisfierAur(dep)
 			if aurPkg != nil {
-				do.orderPkgAur(aurPkg, dp, runtime && i == 0)
+				do.orderPkgAur(aurPkg, dp, basesMap, runtime && i == 0)
 			}
 
 			repoPkg := dp.findSatisfierRepo(dep)
@@ -65,11 +82,7 @@ func (do *depOrder) orderPkgAur(pkg *rpc.Pkg, dp *depPool, runtime bool) {
 		}
 	}
 
-	if _, ok := do.Bases[pkg.PackageBase]; !ok {
-		do.Aur = append(do.Aur, pkg)
-		do.Bases[pkg.PackageBase] = make([]*rpc.Pkg, 0)
-	}
-	do.Bases[pkg.PackageBase] = append(do.Bases[pkg.PackageBase], pkg)
+	basesMap[pkg.PackageBase] = append(basesMap[pkg.PackageBase], pkg)
 }
 
 func (do *depOrder) orderPkgRepo(pkg *alpm.Package, dp *depPool, runtime bool) {
@@ -92,7 +105,7 @@ func (do *depOrder) orderPkgRepo(pkg *alpm.Package, dp *depPool, runtime bool) {
 
 func (do *depOrder) HasMake() bool {
 	lenAur := 0
-	for _, base := range do.Bases {
+	for _, base := range do.Aur {
 		lenAur += len(base)
 	}
 
@@ -102,7 +115,7 @@ func (do *depOrder) HasMake() bool {
 func (do *depOrder) getMake() []string {
 	makeOnly := make([]string, 0, len(do.Aur)+len(do.Repo)-len(do.Runtime))
 
-	for _, base := range do.Bases {
+	for _, base := range do.Aur {
 		for _, pkg := range base {
 			if !do.Runtime.get(pkg.Name) {
 				makeOnly = append(makeOnly, pkg.Name)

+ 157 - 122
install.go

@@ -11,7 +11,6 @@ import (
 
 	gosrc "github.com/Morganamilo/go-srcinfo"
 	alpm "github.com/jguer/go-alpm"
-	rpc "github.com/mikkeloscar/aur"
 )
 
 // Install handles package installs
@@ -176,7 +175,7 @@ func install(parser *arguments) error {
 	}
 
 	if config.CleanMenu {
-		askClean := pkgbuildNumberMenu(do.Aur, do.Bases, remoteNamesCache)
+		askClean := pkgbuildNumberMenu(do.Aur, remoteNamesCache)
 		toClean, err := cleanNumberMenu(do.Aur, remoteNamesCache, askClean)
 		if err != nil {
 			return err
@@ -186,23 +185,23 @@ func install(parser *arguments) error {
 	}
 
 	toSkip := pkgBuildsToSkip(do.Aur, targets)
-	cloned, err := downloadPkgBuilds(do.Aur, do.Bases, toSkip)
+	cloned, err := downloadPkgBuilds(do.Aur, toSkip)
 	if err != nil {
 		return err
 	}
 
-	var toDiff []*rpc.Pkg
-	var toEdit []*rpc.Pkg
+	var toDiff []Base
+	var toEdit []Base
 
 	if config.DiffMenu {
-		pkgbuildNumberMenu(do.Aur, do.Bases, remoteNamesCache)
+		pkgbuildNumberMenu(do.Aur, remoteNamesCache)
 		toDiff, err = diffNumberMenu(do.Aur, remoteNamesCache)
 		if err != nil {
 			return err
 		}
 
 		if len(toDiff) > 0 {
-			err = showPkgBuildDiffs(toDiff, do.Bases, cloned)
+			err = showPkgBuildDiffs(toDiff, cloned)
 			if err != nil {
 				return err
 			}
@@ -225,13 +224,13 @@ func install(parser *arguments) error {
 	}
 
 	//initial srcinfo parse before pkgver() bump
-	err = parseSRCINFOFiles(do.Aur, srcinfosStale, do.Bases)
+	err = parseSRCINFOFiles(do.Aur, srcinfosStale)
 	if err != nil {
 		return err
 	}
 
 	if config.EditMenu {
-		pkgbuildNumberMenu(do.Aur, do.Bases, remoteNamesCache)
+		pkgbuildNumberMenu(do.Aur, remoteNamesCache)
 		toEdit, err = editNumberMenu(do.Aur, remoteNamesCache)
 		if err != nil {
 			return err
@@ -255,13 +254,14 @@ func install(parser *arguments) error {
 		config.NoConfirm = oldValue
 	}
 
+	//TODO: fix for split packages maybe?
 	incompatible, err = getIncompatible(do.Aur, srcinfosStale)
 	if err != nil {
 		return err
 	}
 
 	if config.PGPFetch {
-		err = checkPgpKeys(do.Aur, do.Bases, srcinfosStale)
+		err = checkPgpKeys(do.Aur, srcinfosStale)
 		if err != nil {
 			return err
 		}
@@ -312,7 +312,7 @@ func install(parser *arguments) error {
 
 	go updateCompletion(false)
 
-	err = downloadPkgBuildsSources(do.Aur, do.Bases, incompatible)
+	err = downloadPkgBuildsSources(do.Aur, incompatible)
 	if err != nil {
 		return err
 	}
@@ -416,7 +416,7 @@ func earlyRefresh(parser *arguments) error {
 	return show(passToPacman(arguments))
 }
 
-func getIncompatible(pkgs []*rpc.Pkg, srcinfos map[string]*gosrc.Srcinfo) (stringSet, error) {
+func getIncompatible(bases []Base, srcinfos map[string]*gosrc.Srcinfo) (stringSet, error) {
 	incompatible := make(stringSet)
 	alpmArch, err := alpmHandle.Arch()
 	if err != nil {
@@ -424,14 +424,14 @@ func getIncompatible(pkgs []*rpc.Pkg, srcinfos map[string]*gosrc.Srcinfo) (strin
 	}
 
 nextpkg:
-	for _, pkg := range pkgs {
-		for _, arch := range srcinfos[pkg.PackageBase].Arch {
+	for _, base := range bases {
+		for _, arch := range srcinfos[base.Pkgbase()].Arch {
 			if arch == "any" || arch == alpmArch {
 				continue nextpkg
 			}
 		}
 
-		incompatible.set(pkg.PackageBase)
+		incompatible.set(base.Pkgbase())
 	}
 
 	if len(incompatible) > 0 {
@@ -485,16 +485,23 @@ func parsePackageList(dir string) (map[string]string, string, error) {
 	return pkgdests, version, nil
 }
 
-func pkgbuildNumberMenu(pkgs []*rpc.Pkg, bases map[string][]*rpc.Pkg, installed stringSet) bool {
+func pkgbuildNumberMenu(bases []Base, installed stringSet) bool {
 	toPrint := ""
 	askClean := false
 
-	for n, pkg := range pkgs {
-		dir := filepath.Join(config.BuildDir, pkg.PackageBase)
+	for n, base := range bases {
+		pkg := base.Pkgbase()
+		dir := filepath.Join(config.BuildDir, pkg)
 
-		toPrint += fmt.Sprintf(magenta("%3d")+" %-40s", len(pkgs)-n,
-			bold(formatPkgbase(bases[pkg.PackageBase])))
-		if installed.get(pkg.Name) {
+		toPrint += fmt.Sprintf(magenta("%3d")+" %-40s", len(bases)-n,
+			bold(formatPkgbase(base)))
+
+		anyInstalled := false
+		for _, b := range base {
+			anyInstalled = anyInstalled || installed.get(b.Name)
+		}
+
+		if anyInstalled {
 			toPrint += bold(green(" (Installed)"))
 		}
 
@@ -511,8 +518,8 @@ func pkgbuildNumberMenu(pkgs []*rpc.Pkg, bases map[string][]*rpc.Pkg, installed
 	return askClean
 }
 
-func cleanNumberMenu(pkgs []*rpc.Pkg, installed stringSet, hasClean bool) ([]*rpc.Pkg, error) {
-	toClean := make([]*rpc.Pkg, 0)
+func cleanNumberMenu(bases []Base, installed stringSet, hasClean bool) ([]Base, error) {
+	toClean := make([]Base, 0)
 
 	if !hasClean {
 		return toClean, nil
@@ -534,38 +541,44 @@ func cleanNumberMenu(pkgs []*rpc.Pkg, installed stringSet, hasClean bool) ([]*rp
 	}
 
 	if !cOtherInclude.get("n") && !cOtherInclude.get("none") {
-		for i, pkg := range pkgs {
-			dir := filepath.Join(config.BuildDir, pkg.PackageBase)
+		for i, base := range bases {
+			pkg := base.Pkgbase()
+			anyInstalled := false
+			for _, b := range base {
+				anyInstalled = anyInstalled || installed.get(b.Name)
+			}
+
+			dir := filepath.Join(config.BuildDir, pkg)
 			if _, err := os.Stat(dir); os.IsNotExist(err) {
 				continue
 			}
 
-			if !cIsInclude && cExclude.get(len(pkgs)-i) {
+			if !cIsInclude && cExclude.get(len(bases)-i) {
 				continue
 			}
 
-			if installed.get(pkg.Name) && (cOtherInclude.get("i") || cOtherInclude.get("installed")) {
-				toClean = append(toClean, pkg)
+			if anyInstalled && (cOtherInclude.get("i") || cOtherInclude.get("installed")) {
+				toClean = append(toClean, base)
 				continue
 			}
 
-			if !installed.get(pkg.Name) && (cOtherInclude.get("no") || cOtherInclude.get("notinstalled")) {
-				toClean = append(toClean, pkg)
+			if !anyInstalled && (cOtherInclude.get("no") || cOtherInclude.get("notinstalled")) {
+				toClean = append(toClean, base)
 				continue
 			}
 
 			if cOtherInclude.get("a") || cOtherInclude.get("all") {
-				toClean = append(toClean, pkg)
+				toClean = append(toClean, base)
 				continue
 			}
 
-			if cIsInclude && (cInclude.get(len(pkgs)-i) || cOtherInclude.get(pkg.PackageBase)) {
-				toClean = append(toClean, pkg)
+			if cIsInclude && (cInclude.get(len(bases)-i) || cOtherInclude.get(pkg)) {
+				toClean = append(toClean, base)
 				continue
 			}
 
-			if !cIsInclude && (!cExclude.get(len(pkgs)-i) && !cOtherExclude.get(pkg.PackageBase)) {
-				toClean = append(toClean, pkg)
+			if !cIsInclude && (!cExclude.get(len(bases)-i) && !cOtherExclude.get(pkg)) {
+				toClean = append(toClean, base)
 				continue
 			}
 		}
@@ -574,16 +587,16 @@ func cleanNumberMenu(pkgs []*rpc.Pkg, installed stringSet, hasClean bool) ([]*rp
 	return toClean, nil
 }
 
-func editNumberMenu(pkgs []*rpc.Pkg, installed stringSet) ([]*rpc.Pkg, error) {
-	return editDiffNumberMenu(pkgs, installed, false)
+func editNumberMenu(bases []Base, installed stringSet) ([]Base, error) {
+	return editDiffNumberMenu(bases, installed, false)
 }
 
-func diffNumberMenu(pkgs []*rpc.Pkg, installed stringSet) ([]*rpc.Pkg, error) {
-	return editDiffNumberMenu(pkgs, installed, true)
+func diffNumberMenu(bases []Base, installed stringSet) ([]Base, error) {
+	return editDiffNumberMenu(bases, installed, true)
 }
 
-func editDiffNumberMenu(pkgs []*rpc.Pkg, installed stringSet, diff bool) ([]*rpc.Pkg, error) {
-	toEdit := make([]*rpc.Pkg, 0)
+func editDiffNumberMenu(bases []Base, installed stringSet, diff bool) ([]Base, error) {
+	toEdit := make([]Base, 0)
 	var editInput string
 	var err error
 
@@ -613,32 +626,38 @@ func editDiffNumberMenu(pkgs []*rpc.Pkg, installed stringSet, diff bool) ([]*rpc
 	}
 
 	if !eOtherInclude.get("n") && !eOtherInclude.get("none") {
-		for i, pkg := range pkgs {
-			if !eIsInclude && eExclude.get(len(pkgs)-i) {
+		for i, base := range bases {
+			pkg := base.Pkgbase()
+			anyInstalled := false
+			for _, b := range base {
+				anyInstalled = anyInstalled || installed.get(b.Name)
+			}
+
+			if !eIsInclude && eExclude.get(len(bases)-i) {
 				continue
 			}
 
-			if installed.get(pkg.Name) && (eOtherInclude.get("i") || eOtherInclude.get("installed")) {
-				toEdit = append(toEdit, pkg)
+			if anyInstalled && (eOtherInclude.get("i") || eOtherInclude.get("installed")) {
+				toEdit = append(toEdit, base)
 				continue
 			}
 
-			if !installed.get(pkg.Name) && (eOtherInclude.get("no") || eOtherInclude.get("notinstalled")) {
-				toEdit = append(toEdit, pkg)
+			if !anyInstalled && (eOtherInclude.get("no") || eOtherInclude.get("notinstalled")) {
+				toEdit = append(toEdit, base)
 				continue
 			}
 
 			if eOtherInclude.get("a") || eOtherInclude.get("all") {
-				toEdit = append(toEdit, pkg)
+				toEdit = append(toEdit, base)
 				continue
 			}
 
-			if eIsInclude && (eInclude.get(len(pkgs)-i) || eOtherInclude.get(pkg.PackageBase)) {
-				toEdit = append(toEdit, pkg)
+			if eIsInclude && (eInclude.get(len(bases)-i) || eOtherInclude.get(pkg)) {
+				toEdit = append(toEdit, base)
 			}
 
-			if !eIsInclude && (!eExclude.get(len(pkgs)-i) && !eOtherExclude.get(pkg.PackageBase)) {
-				toEdit = append(toEdit, pkg)
+			if !eIsInclude && (!eExclude.get(len(bases)-i) && !eOtherExclude.get(pkg)) {
+				toEdit = append(toEdit, base)
 			}
 		}
 	}
@@ -646,30 +665,31 @@ func editDiffNumberMenu(pkgs []*rpc.Pkg, installed stringSet, diff bool) ([]*rpc
 	return toEdit, nil
 }
 
-func cleanBuilds(pkgs []*rpc.Pkg) {
-	for i, pkg := range pkgs {
-		dir := filepath.Join(config.BuildDir, pkg.PackageBase)
-		fmt.Printf(bold(cyan("::")+" Deleting (%d/%d): %s\n"), i+1, len(pkgs), cyan(dir))
+func cleanBuilds(bases []Base) {
+	for i, base := range bases {
+		dir := filepath.Join(config.BuildDir, base.Pkgbase())
+		fmt.Printf(bold(cyan("::")+" Deleting (%d/%d): %s\n"), i+1, len(bases), cyan(dir))
 		os.RemoveAll(dir)
 	}
 }
 
-func showPkgBuildDiffs(pkgs []*rpc.Pkg, bases map[string][]*rpc.Pkg, cloned stringSet) error {
-	for _, pkg := range pkgs {
-		dir := filepath.Join(config.BuildDir, pkg.PackageBase)
+func showPkgBuildDiffs(bases []Base, cloned stringSet) error {
+	for _, base := range bases {
+		pkg := base.Pkgbase()
+		dir := filepath.Join(config.BuildDir, pkg)
 		if shouldUseGit(dir) {
 			start := "HEAD"
 
-			if cloned.get(pkg.PackageBase) {
+			if cloned.get(pkg) {
 				start = gitEmptyTree
 			} else {
-				hasDiff, err := gitHasDiff(config.BuildDir, pkg.PackageBase)
+				hasDiff, err := gitHasDiff(config.BuildDir, pkg)
 				if err != nil {
 					return err
 				}
 
 				if !hasDiff {
-					fmt.Printf("%s %s: %s\n", bold(yellow(arrow)), cyan(formatPkgbase(bases[pkg.PackageBase])), bold("No changes -- skipping"))
+					fmt.Printf("%s %s: %s\n", bold(yellow(arrow)), cyan(formatPkgbase(base)), bold("No changes -- skipping"))
 					continue
 				}
 			}
@@ -700,13 +720,14 @@ func showPkgBuildDiffs(pkgs []*rpc.Pkg, bases map[string][]*rpc.Pkg, cloned stri
 	return nil
 }
 
-func editPkgBuilds(pkgs []*rpc.Pkg, srcinfos map[string]*gosrc.Srcinfo) error {
-	pkgbuilds := make([]string, 0, len(pkgs))
-	for _, pkg := range pkgs {
-		dir := filepath.Join(config.BuildDir, pkg.PackageBase)
+func editPkgBuilds(bases []Base, srcinfos map[string]*gosrc.Srcinfo) error {
+	pkgbuilds := make([]string, 0, len(bases))
+	for _, base := range bases {
+		pkg := base.Pkgbase()
+		dir := filepath.Join(config.BuildDir, pkg)
 		pkgbuilds = append(pkgbuilds, filepath.Join(dir, "PKGBUILD"))
 
-		for _, splitPkg := range srcinfos[pkg.PackageBase].SplitPackages() {
+		for _, splitPkg := range srcinfos[pkg].SplitPackages() {
 			if splitPkg.Install != "" {
 				pkgbuilds = append(pkgbuilds, filepath.Join(dir, splitPkg.Install))
 			}
@@ -727,52 +748,59 @@ func editPkgBuilds(pkgs []*rpc.Pkg, srcinfos map[string]*gosrc.Srcinfo) error {
 	return nil
 }
 
-func parseSRCINFOFiles(pkgs []*rpc.Pkg, srcinfos map[string]*gosrc.Srcinfo, bases map[string][]*rpc.Pkg) error {
-	for k, pkg := range pkgs {
-		dir := filepath.Join(config.BuildDir, pkg.PackageBase)
+func parseSRCINFOFiles(bases []Base, srcinfos map[string]*gosrc.Srcinfo) error {
+	for k, base := range bases {
+		pkg := base.Pkgbase()
+		dir := filepath.Join(config.BuildDir, pkg)
 
 		str := bold(cyan("::") + " Parsing SRCINFO (%d/%d): %s\n")
-		fmt.Printf(str, k+1, len(pkgs), cyan(formatPkgbase(bases[pkg.PackageBase])))
+		fmt.Printf(str, k+1, len(bases), cyan(formatPkgbase(base)))
 
 		pkgbuild, err := gosrc.ParseFile(filepath.Join(dir, ".SRCINFO"))
 		if err != nil {
-			return fmt.Errorf("%s: %s", pkg.Name, err)
+			return fmt.Errorf("%s: %s", formatPkgbase(base), err)
 		}
 
-		srcinfos[pkg.PackageBase] = pkgbuild
+		srcinfos[pkg] = pkgbuild
 	}
 
 	return nil
 }
 
-func tryParsesrcinfosFile(pkgs []*rpc.Pkg, srcinfos map[string]*gosrc.Srcinfo, bases map[string][]*rpc.Pkg) {
-	for k, pkg := range pkgs {
-		dir := filepath.Join(config.BuildDir, pkg.PackageBase)
+func tryParsesrcinfosFile(bases []Base, srcinfos map[string]*gosrc.Srcinfo) {
+	for k, base := range bases {
+		pkg := base.Pkgbase()
+		dir := filepath.Join(config.BuildDir, pkg)
 
 		str := bold(cyan("::") + " Parsing SRCINFO (%d/%d): %s\n")
-		fmt.Printf(str, k+1, len(pkgs), cyan(formatPkgbase(bases[pkg.PackageBase])))
+		fmt.Printf(str, k+1, len(bases), cyan(formatPkgbase(base)))
 
 		pkgbuild, err := gosrc.ParseFile(filepath.Join(dir, ".SRCINFO"))
 		if err != nil {
-			fmt.Printf("cannot parse %s skipping: %s\n", pkg.Name, err)
+			fmt.Printf("cannot parse %s skipping: %s\n", formatPkgbase(base), err)
 			continue
 		}
 
-		srcinfos[pkg.PackageBase] = pkgbuild
+		srcinfos[pkg] = pkgbuild
 	}
 }
 
-func pkgBuildsToSkip(pkgs []*rpc.Pkg, targets stringSet) stringSet {
+func pkgBuildsToSkip(bases []Base, targets stringSet) stringSet {
 	toSkip := make(stringSet)
 
-	for _, pkg := range pkgs {
-		if config.ReDownload == "no" || (config.ReDownload == "yes" && !targets.get(pkg.Name)) {
-			dir := filepath.Join(config.BuildDir, pkg.PackageBase, ".SRCINFO")
+	for _, base := range bases {
+		isTarget := false
+		for _, pkg := range base {
+			isTarget = isTarget || targets.get(pkg.Name)
+		}
+
+		if config.ReDownload == "no" || (config.ReDownload == "yes" && isTarget) {
+			dir := filepath.Join(config.BuildDir, base.Pkgbase(), ".SRCINFO")
 			pkgbuild, err := gosrc.ParseFile(dir)
 
 			if err == nil {
-				if alpm.VerCmp(pkgbuild.Version(), pkg.Version) >= 0 {
-					toSkip.set(pkg.PackageBase)
+				if alpm.VerCmp(pkgbuild.Version(), base.Version()) >= 0 {
+					toSkip.set(base.Pkgbase())
 				}
 			}
 		}
@@ -781,10 +809,10 @@ func pkgBuildsToSkip(pkgs []*rpc.Pkg, targets stringSet) stringSet {
 	return toSkip
 }
 
-func mergePkgBuilds(pkgs []*rpc.Pkg) error {
-	for _, pkg := range pkgs {
-		if shouldUseGit(filepath.Join(config.BuildDir, pkg.PackageBase)) {
-			err := gitMerge(config.BuildDir, pkg.PackageBase)
+func mergePkgBuilds(bases []Base) error {
+	for _, base := range bases {
+		if shouldUseGit(filepath.Join(config.BuildDir, base.Pkgbase())) {
+			err := gitMerge(config.BuildDir, base.Pkgbase())
 			if err != nil {
 				return err
 			}
@@ -794,38 +822,39 @@ func mergePkgBuilds(pkgs []*rpc.Pkg) error {
 	return nil
 }
 
-func downloadPkgBuilds(pkgs []*rpc.Pkg, bases map[string][]*rpc.Pkg, toSkip stringSet) (stringSet, error) {
+func downloadPkgBuilds(bases []Base, toSkip stringSet) (stringSet, error) {
 	cloned := make(stringSet)
 	downloaded := 0
 	var wg sync.WaitGroup
 	var mux sync.Mutex
 	var errs MultiError
 
-	download := func(k int, pkg *rpc.Pkg) {
+	download := func(k int, base Base) {
 		defer wg.Done()
+		pkg := base.Pkgbase()
 
-		if toSkip.get(pkg.PackageBase) {
+		if toSkip.get(pkg) {
 			mux.Lock()
 			downloaded++
 			str := bold(cyan("::") + " PKGBUILD up to date, Skipping (%d/%d): %s\n")
-			fmt.Printf(str, downloaded, len(pkgs), cyan(formatPkgbase(bases[pkg.PackageBase])))
+			fmt.Printf(str, downloaded, len(bases), cyan(formatPkgbase(base)))
 			mux.Unlock()
 			return
 		}
 
-		if shouldUseGit(filepath.Join(config.BuildDir, pkg.PackageBase)) {
-			clone, err := gitDownload(baseURL+"/"+pkg.PackageBase+".git", config.BuildDir, pkg.PackageBase)
+		if shouldUseGit(filepath.Join(config.BuildDir, pkg)) {
+			clone, err := gitDownload(baseURL+"/"+pkg+".git", config.BuildDir, pkg)
 			if err != nil {
 				errs.Add(err)
 				return
 			}
 			if clone {
 				mux.Lock()
-				cloned.set(pkg.PackageBase)
+				cloned.set(pkg)
 				mux.Unlock()
 			}
 		} else {
-			err := downloadAndUnpack(baseURL+pkg.URLPath, config.BuildDir)
+			err := downloadAndUnpack(baseURL+base.URLPath(), config.BuildDir)
 			if err != nil {
 				errs.Add(err)
 				return
@@ -835,13 +864,13 @@ func downloadPkgBuilds(pkgs []*rpc.Pkg, bases map[string][]*rpc.Pkg, toSkip stri
 		mux.Lock()
 		downloaded++
 		str := bold(cyan("::") + " Downloaded PKGBUILD (%d/%d): %s\n")
-		fmt.Printf(str, downloaded, len(pkgs), cyan(formatPkgbase(bases[pkg.PackageBase])))
+		fmt.Printf(str, downloaded, len(bases), cyan(formatPkgbase(base)))
 		mux.Unlock()
 	}
 
-	for k, pkg := range pkgs {
+	for k, base := range bases {
 		wg.Add(1)
-		go download(k, pkg)
+		go download(k, base)
 	}
 
 	wg.Wait()
@@ -849,18 +878,19 @@ func downloadPkgBuilds(pkgs []*rpc.Pkg, bases map[string][]*rpc.Pkg, toSkip stri
 	return cloned, errs.Return()
 }
 
-func downloadPkgBuildsSources(pkgs []*rpc.Pkg, bases map[string][]*rpc.Pkg, incompatible stringSet) (err error) {
-	for _, pkg := range pkgs {
-		dir := filepath.Join(config.BuildDir, pkg.PackageBase)
+func downloadPkgBuildsSources(bases []Base, incompatible stringSet) (err error) {
+	for _, base := range bases {
+		pkg := base.Pkgbase()
+		dir := filepath.Join(config.BuildDir, pkg)
 		args := []string{"--verifysource", "-Ccf"}
 
-		if incompatible.get(pkg.PackageBase) {
+		if incompatible.get(pkg) {
 			args = append(args, "--ignorearch")
 		}
 
 		err = show(passToMakepkg(dir, args...))
 		if err != nil {
-			return fmt.Errorf("Error downloading sources: %s", cyan(formatPkgbase(bases[pkg.PackageBase])))
+			return fmt.Errorf("Error downloading sources: %s", cyan(formatPkgbase(base)))
 		}
 	}
 
@@ -868,22 +898,23 @@ func downloadPkgBuildsSources(pkgs []*rpc.Pkg, bases map[string][]*rpc.Pkg, inco
 }
 
 func buildInstallPkgBuilds(dp *depPool, do *depOrder, srcinfos map[string]*gosrc.Srcinfo, parser *arguments, incompatible stringSet, conflicts mapStringSet) error {
-	for _, pkg := range do.Aur {
-		dir := filepath.Join(config.BuildDir, pkg.PackageBase)
+	for _, base := range do.Aur {
+		pkg := base.Pkgbase()
+		dir := filepath.Join(config.BuildDir, pkg)
 		built := true
 
-		srcinfo := srcinfos[pkg.PackageBase]
+		srcinfo := srcinfos[pkg]
 
 		args := []string{"--nobuild", "-fC"}
 
-		if incompatible.get(pkg.PackageBase) {
+		if incompatible.get(pkg) {
 			args = append(args, "--ignorearch")
 		}
 
 		//pkgver bump
 		err := show(passToMakepkg(dir, args...))
 		if err != nil {
-			return fmt.Errorf("Error making: %s", pkg.Name)
+			return fmt.Errorf("Error making: %s", formatPkgbase(base))
 		}
 
 		pkgdests, version, err := parsePackageList(dir)
@@ -891,8 +922,12 @@ func buildInstallPkgBuilds(dp *depPool, do *depOrder, srcinfos map[string]*gosrc
 			return err
 		}
 
-		if config.ReBuild == "no" || (config.ReBuild == "yes" && !dp.Explicit.get(pkg.Name)) {
-			for _, split := range do.Bases[pkg.PackageBase] {
+		isExplicit := false
+		for _, b := range base {
+			isExplicit = isExplicit || dp.Explicit.get(b.Name)
+		}
+		if config.ReBuild == "no" || (config.ReBuild == "yes" && isExplicit) {
+			for _, split := range base {
 				pkgdest, ok := pkgdests[split.Name]
 				if !ok {
 					return fmt.Errorf("Could not find PKGDEST for: %s", split.Name)
@@ -911,17 +946,17 @@ func buildInstallPkgBuilds(dp *depPool, do *depOrder, srcinfos map[string]*gosrc
 
 		if built {
 			fmt.Println(bold(yellow(arrow)),
-				cyan(pkg.Name+"-"+version)+bold(" Already made -- skipping build"))
+				cyan(pkg+"-"+version)+bold(" Already made -- skipping build"))
 		} else {
 			args := []string{"-cf", "--noconfirm", "--noextract", "--noprepare", "--holdver"}
 
-			if incompatible.get(pkg.PackageBase) {
+			if incompatible.get(pkg) {
 				args = append(args, "--ignorearch")
 			}
 
 			err := show(passToMakepkg(dir, args...))
 			if err != nil {
-				return fmt.Errorf("Error making: %s", pkg.Name)
+				return fmt.Errorf("Error making: %s", formatPkgbase(base))
 			}
 		}
 
@@ -946,7 +981,7 @@ func buildInstallPkgBuilds(dp *depPool, do *depOrder, srcinfos map[string]*gosrc
 			cmdArgs.globals["ask"] = fmt.Sprint(uask)
 		} else {
 			conflict := false
-			for _, split := range do.Bases[pkg.PackageBase] {
+			for _, split := range base {
 				if _, ok := conflicts[split.Name]; ok {
 					conflict = true
 				}
@@ -973,7 +1008,7 @@ func buildInstallPkgBuilds(dp *depPool, do *depOrder, srcinfos map[string]*gosrc
 		remoteNamesCache := sliceToStringSet(remoteNames)
 		localNamesCache := sliceToStringSet(localNames)
 
-		for _, split := range do.Bases[pkg.PackageBase] {
+		for _, split := range base {
 			pkgdest, ok := pkgdests[split.Name]
 			if !ok {
 				return fmt.Errorf("Could not find PKGDEST for: %s", split.Name)
@@ -1000,7 +1035,7 @@ func buildInstallPkgBuilds(dp *depPool, do *depOrder, srcinfos map[string]*gosrc
 
 		var mux sync.Mutex
 		var wg sync.WaitGroup
-		for _, pkg := range do.Bases[pkg.PackageBase] {
+		for _, pkg := range base {
 			wg.Add(1)
 			go updateVCSData(pkg.Name, srcinfo.Source, &mux, &wg)
 		}
@@ -1024,12 +1059,12 @@ func buildInstallPkgBuilds(dp *depPool, do *depOrder, srcinfos map[string]*gosrc
 	return nil
 }
 
-func clean(pkgs []*rpc.Pkg) {
-	for _, pkg := range pkgs {
-		dir := filepath.Join(config.BuildDir, pkg.PackageBase)
+func clean(bases []Base) {
+	for _, base := range bases {
+		dir := filepath.Join(config.BuildDir, base.Pkgbase())
 
 		fmt.Println(bold(green(arrow +
-			" CleanAfter enabled. Deleting " + pkg.Name + " source folder.")))
+			" CleanAfter enabled. Deleting " + base.Pkgbase() + " source folder.")))
 		os.RemoveAll(dir)
 	}
 }

+ 15 - 18
keys.go

@@ -8,12 +8,11 @@ import (
 	"strings"
 
 	gosrc "github.com/Morganamilo/go-srcinfo"
-	rpc "github.com/mikkeloscar/aur"
 )
 
 // pgpKeySet maps a PGP key with a list of PKGBUILDs that require it.
 // This is similar to stringSet, used throughout the code.
-type pgpKeySet map[string][]*rpc.Pkg
+type pgpKeySet map[string][]Base
 
 func (set pgpKeySet) toSlice() []string {
 	slice := make([]string, 0, len(set))
@@ -23,14 +22,11 @@ func (set pgpKeySet) toSlice() []string {
 	return slice
 }
 
-func (set pgpKeySet) set(key string, p *rpc.Pkg) {
+func (set pgpKeySet) set(key string, p Base) {
 	// Using ToUpper to make sure keys with a different case will be
 	// considered the same.
 	upperKey := strings.ToUpper(key)
-	if _, exists := set[upperKey]; !exists {
-		set[upperKey] = []*rpc.Pkg{}
-	}
-	set[key] = append(set[key], p)
+	set[key] = append(set[upperKey], p)
 }
 
 func (set pgpKeySet) get(key string) bool {
@@ -41,28 +37,29 @@ func (set pgpKeySet) get(key string) bool {
 
 // checkPgpKeys iterates through the keys listed in the PKGBUILDs and if needed,
 // asks the user whether yay should try to import them.
-func checkPgpKeys(pkgs []*rpc.Pkg, bases map[string][]*rpc.Pkg, srcinfos map[string]*gosrc.Srcinfo) error {
+func checkPgpKeys(bases []Base, srcinfos map[string]*gosrc.Srcinfo) error {
 	// Let's check the keys individually, and then we can offer to import
 	// the problematic ones.
 	problematic := make(pgpKeySet)
 	args := append(strings.Fields(config.GpgFlags), "--list-keys")
 
 	// Mapping all the keys.
-	for _, pkg := range pkgs {
-		srcinfo := srcinfos[pkg.PackageBase]
+	for _, base := range bases {
+		pkg := base.Pkgbase()
+		srcinfo := srcinfos[pkg]
 
 		for _, key := range srcinfo.ValidPGPKeys {
 			// If key already marked as problematic, indicate the current
 			// PKGBUILD requires it.
 			if problematic.get(key) {
-				problematic.set(key, pkg)
+				problematic.set(key, base)
 				continue
 			}
 
 			cmd := exec.Command(config.GpgBin, append(args, key)...)
 			err := cmd.Run()
 			if err != nil {
-				problematic.set(key, pkg)
+				problematic.set(key, base)
 			}
 		}
 	}
@@ -72,7 +69,7 @@ func checkPgpKeys(pkgs []*rpc.Pkg, bases map[string][]*rpc.Pkg, srcinfos map[str
 		return nil
 	}
 
-	str, err := formatKeysToImport(problematic, bases)
+	str, err := formatKeysToImport(problematic)
 	if err != nil {
 		return err
 	}
@@ -104,7 +101,7 @@ func importKeys(keys []string) error {
 
 // formatKeysToImport receives a set of keys and returns a string containing the
 // question asking the user wants to import the problematic keys.
-func formatKeysToImport(keys pgpKeySet, bases map[string][]*rpc.Pkg) (string, error) {
+func formatKeysToImport(keys pgpKeySet) (string, error) {
 	if len(keys) == 0 {
 		return "", fmt.Errorf("%s No keys to import", bold(red(arrow+" Error:")))
 	}
@@ -112,12 +109,12 @@ func formatKeysToImport(keys pgpKeySet, bases map[string][]*rpc.Pkg) (string, er
 	var buffer bytes.Buffer
 	buffer.WriteString(bold(green(arrow)))
 	buffer.WriteString(bold(green(" PGP keys need importing:")))
-	for key, pkgs := range keys {
+	for key, bases := range keys {
 		pkglist := ""
-		for _, pkg := range pkgs {
-			pkglist += formatPkgbase(bases[pkg.PackageBase]) + " "
+		for _, base := range bases {
+			pkglist += formatPkgbase(base) + "  "
 		}
-		pkglist = strings.TrimRight(pkglist, " ")
+		pkglist = strings.TrimRight(pkglist, "  ")
 		buffer.WriteString(fmt.Sprintf("\n%s %s, required by: %s", yellow(bold(smallArrow)), cyan(key), cyan(pkglist)))
 	}
 	return buffer.String(), nil

+ 6 - 5
print.go

@@ -211,18 +211,19 @@ func (do *depOrder) Print() {
 		}
 	}
 
-	for _, pkg := range do.Aur {
-		pkgStr := "  " + pkg.PackageBase + "-" + pkg.Version
+	for _, base := range do.Aur {
+		pkg := base.Pkgbase()
+		pkgStr := "  " + pkg + "-" + base[0].Version
 		pkgStrMake := pkgStr
 
 		push := false
 		pushMake := false
 
-		if len(do.Bases[pkg.PackageBase]) > 1 || pkg.PackageBase != pkg.Name {
+		if len(base) > 1 || pkg != base[0].Name {
 			pkgStr += " ("
 			pkgStrMake += " ("
 
-			for _, split := range do.Bases[pkg.PackageBase] {
+			for _, split := range base {
 				if do.Runtime.get(split.Name) {
 					pkgStr += split.Name + " "
 					aurLen++
@@ -236,7 +237,7 @@ func (do *depOrder) Print() {
 
 			pkgStr = pkgStr[:len(pkgStr)-1] + ")"
 			pkgStrMake = pkgStrMake[:len(pkgStrMake)-1] + ")"
-		} else if do.Runtime.get(pkg.Name) {
+		} else if do.Runtime.get(base[0].Name) {
 			aurLen++
 			push = true
 		} else {

+ 5 - 3
vcs.go

@@ -26,6 +26,7 @@ type shaInfo struct {
 func createDevelDB() error {
 	var mux sync.Mutex
 	var wg sync.WaitGroup
+	baseNames := make([]string, 0)
 	infoMap := make(map[string]*rpc.Pkg)
 	srcinfosStale := make(map[string]*gosrc.Srcinfo)
 
@@ -40,14 +41,15 @@ func createDevelDB() error {
 	}
 
 	for _, pkg := range info {
+		baseNames = append(baseNames, pkg.PackageBase)
 		infoMap[pkg.Name] = pkg
 	}
 
 	bases := getBases(infoMap)
 
-	toSkip := pkgBuildsToSkip(info, sliceToStringSet(remoteNames))
-	downloadPkgBuilds(info, bases, toSkip)
-	tryParsesrcinfosFile(info, srcinfosStale, bases)
+	toSkip := pkgBuildsToSkip(bases, sliceToStringSet(remoteNames))
+	downloadPkgBuilds(bases, toSkip)
+	tryParsesrcinfosFile(bases, srcinfosStale)
 
 	for _, pkgbuild := range srcinfosStale {
 		for _, pkg := range pkgbuild.Packages {