Browse Source

Merge branch 'master' into master

Reeto Chatterjee 7 years ago
parent
commit
992c27e82e
15 changed files with 581 additions and 225 deletions
  1. 12 0
      README.md
  2. 47 11
      cmd.go
  3. 1 1
      completions/bash
  4. 6 1
      completions/fish
  5. 5 1
      completions/zsh
  6. 29 0
      config.go
  7. 138 39
      dependencies.go
  8. 45 4
      doc/yay.8
  9. 98 87
      install.go
  10. 4 1
      main.go
  11. 31 24
      parser.go
  12. 24 8
      print.go
  13. 55 13
      query.go
  14. 50 30
      upgrade.go
  15. 36 5
      vcs.go

+ 12 - 0
README.md

@@ -48,6 +48,18 @@ Yay was created with a few objectives in mind and based on the design of [yaourt
 
 ### Changelog
 
+#### v5.608
+
+* Updated Shell completions
+* Added `-Qu` to extended pacman options
+* Provides now supported in `-Si`
+* Improved build method
+* Improved conflict checking
+* PKGBUILDs with unsupported arch can force build now
+* PGP Key automatic importing
+* GPG option passing
+* `db/name` support readded
+
 #### 4.505
 
 * `yay` used to auto save permanent configuration options, now `--save` must be passed to save permanent configuration options

+ 47 - 11
cmd.go

@@ -48,6 +48,13 @@ Permanent configuration options:
     --config   <file>    pacman.conf file to use
 
     --requestsplitn <n>  Max amount of packages to query per AUR request
+    --sortby <field>     Sort AUR results by a specific field during search
+    --answerclean   <a>  Set a predetermined answer for the clean build menu
+    --answeredit    <a>  Set a predetermined answer for the edit pkgbuild menu
+    --answerupgrade <a>  Set a predetermined answer for the upgrade menu
+    --noanswerclean      Unset the answer for the clean build menu
+    --noansweredit       Unset the answer for the edit pkgbuild menu
+    --noanswerupgrade    Unset the answer for the upgrade menu
 
     --topdown            Shows repository's packages first and then AUR's
     --bottomup           Shows AUR's packages first and then repository's
@@ -126,6 +133,11 @@ func handleCmd() (err error) {
 		config.saveConfig()
 	}
 
+	if cmdArgs.existsArg("h", "help") {
+		err = handleHelp()
+		return
+	}
+
 	if config.SudoLoop && cmdArgs.needRoot() {
 		sudoLoopBackground()
 	}
@@ -174,6 +186,15 @@ func handleQuery() error {
 	return err
 }
 
+func handleHelp() error {
+	if cmdArgs.op == "Y" || cmdArgs.op == "yay" {
+		usage()
+		return nil
+	} else {
+		return passToPacman(cmdArgs)
+	}
+}
+
 //this function should only set config options
 //but currently still uses the switch left over from old code
 //eventually this should be refactored out futher
@@ -200,6 +221,8 @@ func handleConfig(option, value string) bool {
 		config.SortMode = TopDown
 	case "bottomup":
 		config.SortMode = BottomUp
+	case "sortby":
+		config.SortBy = value
 	case "noconfirm":
 		config.NoConfirm = true
 	case "redownload":
@@ -216,6 +239,18 @@ func handleConfig(option, value string) bool {
 		config.ReBuild = "tree"
 	case "norebuild":
 		config.ReBuild = "no"
+	case "answerclean":
+		config.AnswerClean = value
+	case "noanswerclean":
+		config.AnswerClean = ""
+	case "answeredit":
+		config.AnswerEdit = value
+	case "noansweredit":
+		config.AnswerEdit = ""
+	case "answerupgrade":
+		config.AnswerUpgrade = value
+	case "noanswerupgrade":
+		config.AnswerUpgrade = ""
 	case "gpgflags":
 		config.GpgFlags = value
 	case "mflags":
@@ -284,13 +319,8 @@ func handlePrint() (err error) {
 
 func handleYay() (err error) {
 	//_, options, targets := cmdArgs.formatArgs()
-	if cmdArgs.existsArg("h", "help") {
-		usage()
-	} else if cmdArgs.existsArg("gendb") {
+	if cmdArgs.existsArg("gendb") {
 		err = createDevelDB()
-		if err != nil {
-			return
-		}
 	} else if cmdArgs.existsDouble("c") {
 		err = cleanDependencies(true)
 	} else if cmdArgs.existsArg("c", "clean") {
@@ -365,10 +395,7 @@ func handleRemove() (err error) {
 
 // NumberMenu presents a CLI for selecting packages to install.
 func numberMenu(pkgS []string, flags []string) (err error) {
-	aurQ, err := narrowSearch(pkgS, true)
-	if err != nil {
-		fmt.Println("Error during AUR search:", err)
-	}
+	aurQ, aurErr := narrowSearch(pkgS, true)
 	numaq := len(aurQ)
 	repoQ, numpq, err := queryRepo(pkgS)
 	if err != nil {
@@ -387,6 +414,11 @@ func numberMenu(pkgS []string, flags []string) (err error) {
 		aurQ.printSearch(numpq + 1)
 	}
 
+	if aurErr != nil {
+		fmt.Printf("Error during AUR search: %s\n", aurErr)
+		fmt.Println("Showing repo packages only")
+	}
+
 	fmt.Println(bold(green(arrow + " Packages to install (eg: 1 2 3, 1-3 or ^4)")))
 	fmt.Print(bold(green(arrow + " ")))
 
@@ -467,7 +499,11 @@ func passToPacman(args *arguments) error {
 
 	cmd.Stdin, cmd.Stdout, cmd.Stderr = os.Stdin, os.Stdout, os.Stderr
 	err := cmd.Run()
-	return err
+
+	if err != nil {
+		return fmt.Errorf("")
+	}
+	return nil
 }
 
 //passToPacman but return the output instead of showing the user

+ 1 - 1
completions/bash

@@ -70,7 +70,7 @@ _yay() {
   common=('arch cachedir color config confirm dbpath debug gpgdir help hookdir logfile
            noconfirm noprogressbar noscriptlet quiet save mflags buildir editor
            makepkg pacman tar git gpg gpgflags config requestsplitn sudoloop nosudoloop
-           redownload noredownload redownloadall root verbose' 'b d h q r v')
+           redownload noredownload redownloadall rebuild rebuildall rebuildtree norebuild root verbose' 'b d h q r v')
   core=('database files help query remove sync upgrade version' 'D F Q R S U V h')
 
   for o in 'D database' 'F files' 'Q query' 'R remove' 'S sync' 'U upgrade' 'Y yays' 'P print'; do

+ 6 - 1
completions/fish

@@ -70,19 +70,24 @@ complete -c $progname -n "not $noopt" -l notimeupdate -d 'Check only package ver
 
 complete -c $progname -n "not $noopt" -l save -d 'Save current arguments to yay permanent configuration' -f
 complete -c $progname -n "not $noopt" -l mflags -d 'Pass the following options to makepkg' -f
+complete -c $progname -n "not $noopt" -l gpgflags -d 'Pass the following options to gpg' -f
 complete -c $progname -n "not $noopt" -l buildir -d 'Specify the build directory' -f
 complete -c $progname -n "not $noopt" -l editor -d 'Editor to use' -f
 complete -c $progname -n "not $noopt" -l makepkg -d 'Makepkg command to use' -f
 complete -c $progname -n "not $noopt" -l pacman -d 'Pacman command to use' -f
 complete -c $progname -n "not $noopt" -l tar -d 'Tar command to use' -f
 complete -c $progname -n "not $noopt" -l git -d 'Git command to use' -f
-complete -c $progname -n "not $noopt" -l config -d 'config command to use' -f
+complete -c $progname -n "not $noopt" -l gpg -d 'Gpg command to use' -f
 complete -c $progname -n "not $noopt" -l requestsplitn -d 'Max amount of packages to query per AUR request' -f
 complete -c $progname -n "not $noopt" -l sudoloop -d 'Loop sudo calls in the backgroud to avoid timeout' -f
 complete -c $progname -n "not $noopt" -l nosudoloop -d 'Do not loop sudo calls in the background' -f
 complete -c $progname -n "not $noopt" -l redownload -d 'Redownload PKGBUILD of package even if up-to-date' -f
 complete -c $progname -n "not $noopt" -l noredownload -d 'Do not redownload up-to-date PKGBUILDs' -f
 complete -c $progname -n "not $noopt" -l redownloadall -d 'Redownload PKGBUILD of package and deps even if up-to-date' -f
+complete -c $progname -n "not $noopt" -l rebuild -d 'Always build target packages' -f
+complete -c $progname -n "not $noopt" -l rebuildall -d 'Always build all AUR packages' -f
+complete -c $progname -n "not $noopt" -l rebuildtree -d 'Always build all AUR packages even if installed' -f
+complete -c $progname -n "not $noopt" -l norebuild -d 'Skip package build if in cache and up to date' -f
 
 # Yay options
 complete -c $progname -n $yayspecific -s c -l clean -d 'Remove unneeded dependencies' -f

+ 5 - 1
completions/zsh

@@ -60,6 +60,10 @@ _pacman_opts_common=(
   '--redownload[Always download pkgbuilds of targets]'
   '--redownloadall[Always download pkgbuilds of all AUR packages]'
   '--noredownload[Skip pkgbuild download if in cache and up to date]'
+  '--rebuild[Always build target packages]'
+  '--rebuildall[Always build all AUR packages]'
+  '--rebuildtree[Always build all AUR packages even if installed]'
+  '--norebuild[Skip package build if in cache and up to date]'
   '--mflags[Pass arguments to makepkg]:mflags'
   '--gpgflags[Pass arguments to gpg]:gpgflags'
   '--sudoloop[Loop sudo calls in the backgroud to avoid timeout]'
@@ -376,8 +380,8 @@ _pacman_completions_installed_groups() {
 # provides completions for installed packages
 _pacman_completions_installed_packages() {
   local -a cmd packages packages_long
-  packages=( ${${packages_long#/var/lib/pacman/local/}%-*-*} )
   packages_long=(/var/lib/pacman/local/*(/))
+  packages=( ${${packages_long#/var/lib/pacman/local/}%-*-*} )
   compadd "$@" -a packages
 }
 

+ 29 - 0
config.go

@@ -1,6 +1,7 @@
 package main
 
 import (
+	"bufio"
 	"bytes"
 	"encoding/json"
 	"fmt"
@@ -33,10 +34,14 @@ type Configuration struct {
 	TarBin        string `json:"tarbin"`
 	ReDownload    string `json:"redownload"`
 	ReBuild       string `json:"rebuild"`
+	AnswerClean   string `json:"answerclean"`
+	AnswerEdit    string `json:"answeredit"`
+	AnswerUpgrade string `json:"answerupgrade"`
 	GitBin        string `json:"gitbin"`
 	GpgBin        string `json:"gpgbin"`
 	GpgFlags      string `json:"gpgflags"`
 	MFlags        string `json:"mflags"`
+	SortBy        string `json:"sortby"`
 	RequestSplitN int    `json:"requestsplitn"`
 	SearchMode    int    `json:"-"`
 	SortMode      int    `json:"sortmode"`
@@ -134,6 +139,7 @@ func defaultSettings(config *Configuration) {
 	config.GpgFlags = ""
 	config.MFlags = ""
 	config.SortMode = BottomUp
+	config.SortBy = "votes"
 	config.SudoLoop = false
 	config.TarBin = "bsdtar"
 	config.GitBin = "git"
@@ -142,6 +148,9 @@ func defaultSettings(config *Configuration) {
 	config.RequestSplitN = 150
 	config.ReDownload = "no"
 	config.ReBuild = "no"
+	config.AnswerClean = ""
+	config.AnswerEdit = ""
+	config.AnswerUpgrade = ""
 }
 
 // Editor returns the preferred system editor.
@@ -223,6 +232,26 @@ func continueTask(s string, def string) (cont bool) {
 	return true
 }
 
+func getInput(defaultValue string) (string, error) {
+	if defaultValue != "" || config.NoConfirm {
+		fmt.Println(defaultValue)
+		return defaultValue, nil
+	}
+
+	reader := bufio.NewReader(os.Stdin)
+
+	buf, overflow, err := reader.ReadLine()
+	if err != nil {
+		return "", err
+	}
+
+	if overflow {
+		return "", fmt.Errorf("Input too long")
+	}
+
+	return string(buf), nil
+}
+
 func (config Configuration) String() string {
 	var buf bytes.Buffer
 	enc := json.NewEncoder(&buf)

+ 138 - 39
dependencies.go

@@ -15,6 +15,7 @@ type depTree struct {
 	Aur       map[string]*rpc.Pkg
 	Missing   stringSet
 	Groups    stringSet
+	Provides  map[string]string
 }
 
 type depCatagories struct {
@@ -31,6 +32,7 @@ func makeDepTree() *depTree {
 		make(map[string]*rpc.Pkg),
 		make(stringSet),
 		make(stringSet),
+		make(map[string]string),
 	}
 
 	return &dt
@@ -70,6 +72,77 @@ func splitDbFromName(pkg string) (string, string) {
 	return "", split[0]
 }
 
+func isDevelName(name string) bool {
+	for _, suffix := range []string{"git", "svn", "hg", "bzr", "nightly"} {
+		if strings.HasSuffix(name, suffix) {
+			return true
+		}
+	}
+
+	return strings.Contains(name, "-always-")
+}
+
+func getBases(pkgs map[string]*rpc.Pkg) map[string][]*rpc.Pkg {
+	bases := make(map[string][]*rpc.Pkg)
+
+nextpkg:
+	for _, pkg := range pkgs {
+		for _, base := range bases[pkg.PackageBase] {
+			if base == pkg {
+				continue nextpkg
+			}
+		}
+
+		_, ok := bases[pkg.PackageBase]
+		if !ok {
+			bases[pkg.PackageBase] = make([]*rpc.Pkg, 0)
+		}
+		bases[pkg.PackageBase] = append(bases[pkg.PackageBase], pkg)
+	}
+
+	return bases
+}
+
+func aurFindProvider(name string, dt *depTree) (string, *rpc.Pkg) {
+	dep, _ := splitNameFromDep(name)
+	aurpkg, exists := dt.Aur[dep]
+
+	if exists {
+		return dep, aurpkg
+	}
+
+	dep, exists = dt.Provides[dep]
+	if exists {
+		aurpkg, exists = dt.Aur[dep]
+		if exists {
+			return dep, aurpkg
+		}
+	}
+
+	return "", nil
+
+}
+
+func repoFindProvider(name string, dt *depTree) (string, *alpm.Package) {
+	dep, _ := splitNameFromDep(name)
+	alpmpkg, exists := dt.Repo[dep]
+
+	if exists {
+		return dep, alpmpkg
+	}
+
+	dep, exists = dt.Provides[dep]
+	if exists {
+		alpmpkg, exists = dt.Repo[dep]
+		if exists {
+			return dep, alpmpkg
+		}
+	}
+
+	return "", nil
+
+}
+
 // Step two of dependency resolving. We already have all the information on the
 // packages we need, now it's just about ordering them correctly.
 // pkgs is a list of targets, the packages we want to install. Dependencies are
@@ -105,26 +178,18 @@ func getDepCatagories(pkgs []string, dt *depTree) (*depCatagories, error) {
 	dc := makeDependCatagories()
 	seen := make(stringSet)
 
-	for _, pkg := range dt.Aur {
-		_, ok := dc.Bases[pkg.PackageBase]
-		if !ok {
-			dc.Bases[pkg.PackageBase] = make([]*rpc.Pkg, 0)
-		}
-		dc.Bases[pkg.PackageBase] = append(dc.Bases[pkg.PackageBase], pkg)
-	}
+	dc.Bases = getBases(dt.Aur)
 
 	for _, pkg := range pkgs {
-		_, name := splitDbFromName(pkg)
-		dep, _ := splitNameFromDep(name)
-		alpmpkg, exists := dt.Repo[dep]
-		if exists {
+		dep, alpmpkg := repoFindProvider(pkg, dt)
+		if alpmpkg != nil {
 			repoDepCatagoriesRecursive(alpmpkg, dc, dt, false)
 			dc.Repo = append(dc.Repo, alpmpkg)
 			delete(dt.Repo, dep)
 		}
 
-		aurpkg, exists := dt.Aur[dep]
-		if exists {
+		dep, aurpkg := aurFindProvider(pkg, dt)
+		if aurpkg != nil {
 			depCatagoriesRecursive(aurpkg, dc, dt, false, seen)
 			if !seen.get(aurpkg.PackageBase) {
 				dc.Aur = append(dc.Aur, aurpkg)
@@ -175,9 +240,8 @@ func getDepCatagories(pkgs []string, dt *depTree) (*depCatagories, error) {
 
 func repoDepCatagoriesRecursive(pkg *alpm.Package, dc *depCatagories, dt *depTree, isMake bool) {
 	pkg.Depends().ForEach(func(_dep alpm.Depend) error {
-		dep := _dep.Name
-		alpmpkg, exists := dt.Repo[dep]
-		if exists {
+		dep, alpmpkg := repoFindProvider(_dep.Name, dt)
+		if alpmpkg != nil {
 			delete(dt.Repo, dep)
 			repoDepCatagoriesRecursive(alpmpkg, dc, dt, isMake)
 
@@ -195,11 +259,9 @@ func repoDepCatagoriesRecursive(pkg *alpm.Package, dc *depCatagories, dt *depTre
 func depCatagoriesRecursive(_pkg *rpc.Pkg, dc *depCatagories, dt *depTree, isMake bool, seen stringSet) {
 	for _, pkg := range dc.Bases[_pkg.PackageBase] {
 		for _, deps := range [3][]string{pkg.Depends, pkg.MakeDepends, pkg.CheckDepends} {
-			for _, _dep := range deps {
-				dep, _ := splitNameFromDep(_dep)
-
-				aurpkg, exists := dt.Aur[dep]
-				if exists {
+			for _, pkg := range deps {
+				dep, aurpkg := aurFindProvider(pkg, dt)
+				if aurpkg != nil {
 					delete(dt.Aur, dep)
 					depCatagoriesRecursive(aurpkg, dc, dt, isMake, seen)
 
@@ -213,8 +275,8 @@ func depCatagoriesRecursive(_pkg *rpc.Pkg, dc *depCatagories, dt *depTree, isMak
 					}
 				}
 
-				alpmpkg, exists := dt.Repo[dep]
-				if exists {
+				dep, alpmpkg := repoFindProvider(pkg, dt)
+				if alpmpkg != nil {
 					delete(dt.Repo, dep)
 					repoDepCatagoriesRecursive(alpmpkg, dc, dt, isMake)
 
@@ -344,9 +406,14 @@ func repoTreeRecursive(pkg *alpm.Package, dt *depTree, localDb *alpm.Db, syncDb
 		return
 	}
 
+	_, exists = dt.Provides[pkg.Name()]
+	if exists {
+		return
+	}
+
 	dt.Repo[pkg.Name()] = pkg
 	(*pkg).Provides().ForEach(func(dep alpm.Depend) (err error) {
-		dt.Repo[dep.Name] = pkg
+		dt.Provides[dep.Name] = pkg.Name()
 		return nil
 	})
 
@@ -397,11 +464,12 @@ func depTreeRecursive(dt *depTree, localDb *alpm.Db, syncDb alpm.DbList, isMake
 
 	// Cache the results
 	for _, pkg := range info {
-		// Copying to p fixes a bug.
-		// Would rather not copy but cant find another way to fix.
-		p := pkg
-		dt.Aur[pkg.Name] = &p
+		dt.Aur[pkg.Name] = pkg
 
+		for _, provide := range pkg.Provides {
+			name, _ := splitNameFromDep(provide)
+			dt.Provides[name] = pkg.Name
+		}
 	}
 
 	// Loop through to process and check if we now have
@@ -427,6 +495,12 @@ func depTreeRecursive(dt *depTree, localDb *alpm.Db, syncDb alpm.DbList, isMake
 					continue
 				}
 
+				_, exists = dt.Provides[dep]
+				// We have it cached so skip.
+				if exists {
+					continue
+				}
+
 				_, exists = dt.Repo[dep]
 				// We have it cached so skip.
 				if exists {
@@ -469,27 +543,37 @@ func depTreeRecursive(dt *depTree, localDb *alpm.Db, syncDb alpm.DbList, isMake
 }
 
 func checkVersions(dt *depTree) error {
-	depStrings := make([]string, 0)
 	has := make(map[string][]string)
+	allDeps := make([]*gopkg.Dependency, 0)
+
+	localDb, err := alpmHandle.LocalDb()
+	if err != nil {
+		return err
+	}
 
 	for _, pkg := range dt.Aur {
 		for _, deps := range [3][]string{pkg.Depends, pkg.MakeDepends, pkg.CheckDepends} {
 			for _, dep := range deps {
 				_, _dep := splitNameFromDep(dep)
 				if _dep != "" {
-					depStrings = append(depStrings, dep)
+					deps, _ := gopkg.ParseDeps([]string{dep})
+					if deps[0] != nil {
+						allDeps = append(allDeps, deps[0])
+					}
 				}
 			}
 		}
 
 		addMapStringSlice(has, pkg.Name, pkg.Version)
 
-		for _, name := range pkg.Provides {
-			_name, _ver := splitNameFromDep(name)
-			if _ver != "" {
-				addMapStringSlice(has, _name, _ver)
-			} else {
-				delete(has, _name)
+		if !isDevelName(pkg.Name) {
+			for _, name := range pkg.Provides {
+				_name, _ver := splitNameFromDep(name)
+				if _ver != "" {
+					addMapStringSlice(has, _name, _ver)
+				} else {
+					delete(has, _name)
+				}
 			}
 		}
 	}
@@ -497,7 +581,10 @@ func checkVersions(dt *depTree) error {
 	for _, pkg := range dt.Repo {
 		pkg.Depends().ForEach(func(dep alpm.Depend) error {
 			if dep.Mod != alpm.DepModAny {
-				depStrings = append(depStrings, dep.String())
+				deps, _ := gopkg.ParseDeps([]string{dep.String()})
+				if deps[0] != nil {
+					allDeps = append(allDeps, deps[0])
+				}
 			}
 			return nil
 		})
@@ -516,9 +603,21 @@ func checkVersions(dt *depTree) error {
 
 	}
 
-	deps, _ := gopkg.ParseDeps(depStrings)
+	localDb.PkgCache().ForEach(func(pkg alpm.Package) error {
+		pkg.Provides().ForEach(func(dep alpm.Depend) error {
+			if dep.Mod != alpm.DepModAny {
+				addMapStringSlice(has, dep.Name, dep.Version)
+			} else {
+				delete(has, dep.Name)
+			}
+
+			return nil
+		})
+
+		return nil
+	})
 
-	for _, dep := range deps {
+	for _, dep := range allDeps {
 		satisfied := false
 		verStrs, ok := has[dep.Name]
 		if !ok {

+ 45 - 4
doc/yay.8

@@ -1,4 +1,4 @@
-/n'\" t
+'\" t
 .TH "YAY" "8" "2018-02-29" "Yay v3\&.460+" "Yay Manual"
 .nh
 .ad l
@@ -37,7 +37,7 @@ Downloads PKGBUILD from ABS or AUR\&.
 If no operation is selected -Y will be assumed\&.
 .SH "EXTENDED PACMAN OPERATIONS"
 .PP
-\fB\-S, -Si, -Ss, -Su\fR
+\fB\-S, -Si, -Ss, -Su, -Qu\fR
 .RS 4
 These operations are extended to support both AUR and repo packages\&.
 .RE
@@ -56,7 +56,7 @@ which packages to install (yogurt mode)\&.
 .PP
 \fB   \-\-gendb\fR
 .RS 4
-Generate development package databse\&. Tracks the latest commit for each
+Generate development package database\&. Tracks the latest commit for each
 development package, when there is a new commit Yay will know to update\&. This
 is done per package whenever a package is synced. This option should only be
 used when migrating to Yay from another AUR helper.
@@ -171,6 +171,47 @@ AUR query will cause an error\%. This should only make a noticeable difference
 with very large requests (>500) packages\&.
 .RE
 .PP
+\fB\-\-sortby <votes|popularity|id|baseid|name|base|submitted|modified>\fR
+.RS 4
+Sort AUR results by a specific field during search\&.
+.RE
+.PP
+\fB\-\-answerclean <All|None|Installed|NotInstalled|...>\fR
+.RS 4
+Set a predetermined answer for the clean build menu question\&. This answer
+will be used instead of reading from standard input but will be treaded exactly
+the same when parsed\&.
+.RE
+.PP
+\fB\-\-answeredit <All|None|Installed|NotInstalled|...>\fR
+.RS 4
+Set a predetermined answer for the edit pkgbuild  menu question\&. This answer
+will be used instead of reading from standard input but will be treaded exactly
+the same when parsed\&.
+.RE
+.PP
+\fB\-\-answerupgrade\fR <Repo|^Repo|None|...>
+.RS 4
+Set a predetermined answer for the upgrade  menu question\&. This answer
+will be used instead of reading from standard input but will be treaded exactly
+the same\&.
+.RE
+.PP
+\fB\-\-noanswerclean\fR
+.RS 4
+Unset the answer for the clean build menu\&.
+.RE
+.PP
+\fB\-\-noansweredit\fR
+.RS 4
+Unset the answer for the edit pkgbuild menu\&.
+.RE
+.PP
+\fB\-\-noanswerupgrade\fR
+.RS 4
+Unset the answer for the upgrade menu\&.
+.RE
+.PP
 \fB\-\-topdown\fR
 .RS 4
 Display repository packages first and then AUR packages\&.
@@ -318,7 +359,7 @@ yay --devel --save
 Sets devel to true in the config\&.
 .RE
 .PP
-yay --stats
+yay -P --stats
 .RS 4
 Shows statistics for installed packages and system health\&.
 .RE

+ 98 - 87
install.go

@@ -1,7 +1,6 @@
 package main
 
 import (
-	"bufio"
 	"fmt"
 	"os"
 	"os/exec"
@@ -17,14 +16,18 @@ import (
 func install(parser *arguments) error {
 	requestTargets := parser.targets.toSlice()
 	var err error
-	var incompatable stringSet
+	var incompatible stringSet
 	var dc *depCatagories
 	var toClean []*rpc.Pkg
 	var toEdit []*rpc.Pkg
 
+	var aurUp upSlice
+	var repoUp upSlice
+
 	removeMake := false
 	srcinfosStale := make(map[string]*gopkg.PKGBUILD)
 	srcinfos := make(map[string]*gopkg.PKGBUILD)
+
 	//remotenames: names of all non repo packages on the system
 	_, _, _, remoteNames, err := filterPackages()
 	if err != nil {
@@ -35,9 +38,21 @@ func install(parser *arguments) error {
 	//place
 	remoteNamesCache := sliceToStringSet(remoteNames)
 
-	//if we are doing -u also request every non repo package on the system
+	//if we are doing -u also request all packages needing update
 	if parser.existsArg("u", "sysupgrade") {
-		requestTargets = append(requestTargets, remoteNames...)
+		aurUp, repoUp, err = upList()
+		if err != nil {
+			return err
+		}
+
+		for _, up := range aurUp {
+			requestTargets = append(requestTargets, up.Name)
+		}
+
+		for _, up := range repoUp {
+			requestTargets = append(requestTargets, up.Name)
+		}
+
 	}
 
 	//if len(aurTargets) > 0 || parser.existsArg("u", "sysupgrade") && len(remoteNames) > 0 {
@@ -56,18 +71,19 @@ func install(parser *arguments) error {
 		parser.targets.set(name)
 	}
 
-	//only error if direct targets or deps are missing
-	for missing := range dt.Missing {
-		_, missingName := splitDbFromName(missing)
-		if !remoteNamesCache.get(missingName) || parser.targets.get(missingName) {
-			str := bold(red(arrow+" Error: ")) + "Could not find all required packages:"
+	for i, pkg := range requestTargets {
+		_, name := splitDbFromName(pkg)
+		requestTargets[i] = name
+	}
 
-			for name := range dt.Missing {
-				str += "\n\t" + name
-			}
+	if len(dt.Missing) > 0 {
+		str := bold(red(arrow+" Error: ")) + "Could not find all required packages:"
 
-			return fmt.Errorf("%s", str)
+		for name := range dt.Missing {
+			str += "\n\t" + name
 		}
+
+		return fmt.Errorf("%s", str)
 	}
 
 	//create the arguments to pass for the repo install
@@ -77,27 +93,29 @@ func install(parser *arguments) error {
 	arguments.targets = make(stringSet)
 
 	if parser.existsArg("u", "sysupgrade") {
-		ignore, aurUp, err := upgradePkgs(dt)
+		ignore, aurUp, err := upgradePkgs(aurUp, repoUp)
 		if err != nil {
 			return err
 		}
 
+		requestTargets = parser.targets.toSlice()
+
+		for _, up := range repoUp {
+			if !ignore.get(up.Name) {
+				requestTargets = append(requestTargets, up.Name)
+			}
+		}
+
+		for up := range aurUp {
+			requestTargets = append(requestTargets, up)
+		}
+
 		arguments.addParam("ignore", strings.Join(ignore.toSlice(), ","))
 		fmt.Println()
 
 		for pkg := range aurUp {
 			parser.addTarget(pkg)
 		}
-
-		//discard stuff thats
-		//not a target and
-		//not an upgrade and
-		//is installed
-		for pkg := range dt.Aur {
-			if !parser.targets.get(pkg) && remoteNamesCache.get(pkg) {
-				delete(dt.Aur, pkg)
-			}
-		}
 	}
 
 	hasAur := false
@@ -112,7 +130,7 @@ func install(parser *arguments) error {
 		return fmt.Errorf(red(arrow + " Refusing to install AUR Packages as root, Aborting."))
 	}
 
-	dc, err = getDepCatagories(parser.formatTargets(), dt)
+	dc, err = getDepCatagories(requestTargets, dt)
 	if err != nil {
 		return err
 	}
@@ -135,11 +153,9 @@ func install(parser *arguments) error {
 		hasAur = len(dc.Aur) != 0
 		fmt.Println()
 
-		if !parser.existsArg("gendb") {
-			err = checkForAllConflicts(dc)
-			if err != nil {
-				return err
-			}
+		err = checkForAllConflicts(dc)
+		if err != nil {
+			return err
 		}
 
 		if len(dc.MakeOnly) > 0 {
@@ -167,25 +183,12 @@ func install(parser *arguments) error {
 		}
 
 		//inital srcinfo parse before pkgver() bump
-		err = parsesrcinfosFile(dc.Aur, srcinfosStale, dc.Bases)
+		err = parseSRCINFOFiles(dc.Aur, srcinfosStale, dc.Bases)
 		if err != nil {
 			return err
 		}
 
-		if arguments.existsArg("gendb") {
-			for _, pkg := range dc.Aur {
-				pkgbuild := srcinfosStale[pkg.PackageBase]
-
-				for _, pkg := range dc.Bases[pkg.PackageBase] {
-					updateVCSData(pkg.Name, pkgbuild.Source)
-				}
-			}
-
-			fmt.Println(bold(green(arrow + " GenDB finished. No packages were installed")))
-			return nil
-		}
-
-		incompatable, err = getIncompatable(dc.Aur, srcinfosStale, dc.Bases)
+		incompatible, err = getIncompatible(dc.Aur, srcinfosStale, dc.Bases)
 		if err != nil {
 			return err
 		}
@@ -196,7 +199,7 @@ func install(parser *arguments) error {
 		}
 	}
 
-	if !parser.existsArg("gendb") && (len(arguments.targets) > 0 || arguments.existsArg("u")) {
+	if len(arguments.targets) > 0 || arguments.existsArg("u") {
 		err := passToPacman(arguments)
 		if err != nil {
 			return fmt.Errorf("Error installing repo packages")
@@ -218,9 +221,12 @@ func install(parser *arguments) error {
 			}
 		}
 	} else if hasAur {
+		oldValue := config.NoConfirm
+		config.NoConfirm = false
 		if len(toEdit) > 0 && !continueTask("Proceed with install?", "nN") {
 			return fmt.Errorf("Aborting due to user")
 		}
+		config.NoConfirm = oldValue
 	}
 
 	if hasAur {
@@ -229,17 +235,17 @@ func install(parser *arguments) error {
 		uask := alpm.QuestionType(ask) | alpm.QuestionTypeConflictPkg
 		cmdArgs.globals["ask"] = fmt.Sprint(uask)
 
-		err = downloadPkgBuildsSources(dc.Aur, dc.Bases, incompatable)
+		err = downloadPkgBuildsSources(dc.Aur, dc.Bases, incompatible)
 		if err != nil {
 			return err
 		}
 
-		err = parsesrcinfosGenerate(dc.Aur, srcinfos, dc.Bases)
+		err = parseSRCINFOGenerate(dc.Aur, srcinfos, dc.Bases)
 		if err != nil {
 			return err
 		}
 
-		err = buildInstallPkgBuilds(dc.Aur, srcinfos, parser.targets, parser, dc.Bases, incompatable)
+		err = buildInstallPkgBuilds(dc.Aur, srcinfos, parser.targets, parser, dc.Bases, incompatible)
 		if err != nil {
 			return err
 		}
@@ -276,8 +282,8 @@ func install(parser *arguments) error {
 	return nil
 }
 
-func getIncompatable(pkgs []*rpc.Pkg, srcinfos map[string]*gopkg.PKGBUILD, bases map[string][]*rpc.Pkg) (stringSet, error) {
-	incompatable := make(stringSet)
+func getIncompatible(pkgs []*rpc.Pkg, srcinfos map[string]*gopkg.PKGBUILD, bases map[string][]*rpc.Pkg) (stringSet, error) {
+	incompatible := make(stringSet)
 	alpmArch, err := alpmHandle.Arch()
 	if err != nil {
 		return nil, err
@@ -291,13 +297,13 @@ nextpkg:
 			}
 		}
 
-		incompatable.set(pkg.PackageBase)
+		incompatible.set(pkg.PackageBase)
 	}
 
-	if len(incompatable) > 0 {
+	if len(incompatible) > 0 {
 		fmt.Print(
 			bold(green(("\nThe following packages are not compatable with your architecture:"))))
-		for pkg := range incompatable {
+		for pkg := range incompatible {
 			fmt.Print("  " + cyan(pkg))
 		}
 
@@ -308,7 +314,7 @@ nextpkg:
 		}
 	}
 
-	return incompatable, nil
+	return incompatible, nil
 }
 
 func cleanEditNumberMenu(pkgs []*rpc.Pkg, bases map[string][]*rpc.Pkg, installed stringSet) ([]*rpc.Pkg, []*rpc.Pkg, error) {
@@ -318,10 +324,6 @@ func cleanEditNumberMenu(pkgs []*rpc.Pkg, bases map[string][]*rpc.Pkg, installed
 	toClean := make([]*rpc.Pkg, 0)
 	toEdit := make([]*rpc.Pkg, 0)
 
-	if config.NoConfirm {
-		return toClean, toEdit, nil
-	}
-
 	for n, pkg := range pkgs {
 		dir := config.BuildDir + pkg.PackageBase + "/"
 
@@ -345,19 +347,11 @@ func cleanEditNumberMenu(pkgs []*rpc.Pkg, bases map[string][]*rpc.Pkg, installed
 		fmt.Println(bold(green(arrow + " Packages to cleanBuild?")))
 		fmt.Println(bold(green(arrow) + cyan(" [N]one ") + green("[A]ll [Ab]ort [I]nstalled [No]tInstalled or (1 2 3, 1-3, ^4)")))
 		fmt.Print(bold(green(arrow + " ")))
-		reader := bufio.NewReader(os.Stdin)
-
-		numberBuf, overflow, err := reader.ReadLine()
+		cleanInput, err := getInput(config.AnswerClean)
 		if err != nil {
 			return nil, nil, err
 		}
 
-		if overflow {
-			return nil, nil, fmt.Errorf("Input too long")
-		}
-
-		cleanInput := string(numberBuf)
-
 		cInclude, cExclude, cOtherInclude, cOtherExclude := parseNumberMenu(cleanInput)
 		cIsInclude := len(cExclude) == 0 && len(cOtherExclude) == 0
 
@@ -406,19 +400,12 @@ func cleanEditNumberMenu(pkgs []*rpc.Pkg, bases map[string][]*rpc.Pkg, installed
 	fmt.Println(bold(green(arrow) + cyan(" [N]one ") + green("[A]ll [Ab]ort [I]nstalled [No]tInstalled or (1 2 3, 1-3, ^4)")))
 
 	fmt.Print(bold(green(arrow + " ")))
-	reader := bufio.NewReader(os.Stdin)
 
-	numberBuf, overflow, err := reader.ReadLine()
+	editInput, err := getInput(config.AnswerEdit)
 	if err != nil {
 		return nil, nil, err
 	}
 
-	if overflow {
-		return nil, nil, fmt.Errorf("Input too long")
-	}
-
-	editInput := string(numberBuf)
-
 	eInclude, eExclude, eOtherInclude, eOtherExclude := parseNumberMenu(editInput)
 	eIsInclude := len(eExclude) == 0 && len(eOtherExclude) == 0
 
@@ -479,13 +466,13 @@ func editPkgBuilds(pkgs []*rpc.Pkg) error {
 	editcmd.Stdin, editcmd.Stdout, editcmd.Stderr = os.Stdin, os.Stdout, os.Stderr
 	err := editcmd.Run()
 	if err != nil {
-		return fmt.Errorf("Editor did not exit successfully, Abotring: %s", err)
+		return fmt.Errorf("Editor did not exit successfully, Aborting: %s", err)
 	}
 
 	return nil
 }
 
-func parsesrcinfosFile(pkgs []*rpc.Pkg, srcinfos map[string]*gopkg.PKGBUILD, bases map[string][]*rpc.Pkg) error {
+func parseSRCINFOFiles(pkgs []*rpc.Pkg, srcinfos map[string]*gopkg.PKGBUILD, bases map[string][]*rpc.Pkg) error {
 	for k, pkg := range pkgs {
 		dir := config.BuildDir + pkg.PackageBase + "/"
 
@@ -503,7 +490,24 @@ func parsesrcinfosFile(pkgs []*rpc.Pkg, srcinfos map[string]*gopkg.PKGBUILD, bas
 	return nil
 }
 
-func parsesrcinfosGenerate(pkgs []*rpc.Pkg, srcinfos map[string]*gopkg.PKGBUILD, bases map[string][]*rpc.Pkg) error {
+func tryParsesrcinfosFile(pkgs []*rpc.Pkg, srcinfos map[string]*gopkg.PKGBUILD, bases map[string][]*rpc.Pkg) {
+	for k, pkg := range pkgs {
+		dir := config.BuildDir + pkg.PackageBase + "/"
+
+		str := bold(cyan("::") + " Parsing SRCINFO (%d/%d): %s\n")
+		fmt.Printf(str, k+1, len(pkgs), formatPkgbase(pkg, bases))
+
+		pkgbuild, err := gopkg.ParseSRCINFO(dir + ".SRCINFO")
+		if err != nil {
+			fmt.Printf("cannot parse %s skipping: %s\n", pkg.Name, err)
+			continue
+		}
+
+		srcinfos[pkg.PackageBase] = pkgbuild
+	}
+}
+
+func parseSRCINFOGenerate(pkgs []*rpc.Pkg, srcinfos map[string]*gopkg.PKGBUILD, bases map[string][]*rpc.Pkg) error {
 	for k, pkg := range pkgs {
 		dir := config.BuildDir + pkg.PackageBase + "/"
 
@@ -580,25 +584,18 @@ func downloadPkgBuildsSources(pkgs []*rpc.Pkg, bases map[string][]*rpc.Pkg, inco
 }
 
 func buildInstallPkgBuilds(pkgs []*rpc.Pkg, srcinfos map[string]*gopkg.PKGBUILD, targets stringSet, parser *arguments, bases map[string][]*rpc.Pkg, incompatable stringSet) error {
-	alpmArch, err := alpmHandle.Arch()
+	arch, err := alpmHandle.Arch()
 	if err != nil {
 		return err
 	}
 
 	for _, pkg := range pkgs {
-		var arch string
 		dir := config.BuildDir + pkg.PackageBase + "/"
 		built := true
 
 		srcinfo := srcinfos[pkg.PackageBase]
 		version := srcinfo.CompleteVersion()
 
-		if srcinfos[pkg.PackageBase].Arch[0] == "any" {
-			arch = "any"
-		} else {
-			arch = alpmArch
-		}
-
 		if config.ReBuild == "no" || (config.ReBuild == "yes" && !targets.get(pkg.Name)) {
 			for _, split := range bases[pkg.PackageBase] {
 				file, err := completeFileName(dir, split.Name+"-"+version.String()+"-"+arch+".pkg")
@@ -607,6 +604,13 @@ func buildInstallPkgBuilds(pkgs []*rpc.Pkg, srcinfos map[string]*gopkg.PKGBUILD,
 				}
 
 				if file == "" {
+					file, err = completeFileName(dir, split.Name+"-"+version.String()+"-"+"any"+".pkg")
+					if err != nil {
+						return err
+					}
+				}
+
+				if file == "" {
 					built = false
 				}
 			}
@@ -651,6 +655,13 @@ func buildInstallPkgBuilds(pkgs []*rpc.Pkg, srcinfos map[string]*gopkg.PKGBUILD,
 			}
 
 			if file == "" {
+				file, err = completeFileName(dir, split.Name+"-"+version.String()+"-"+"any"+".pkg")
+				if err != nil {
+					return err
+				}
+			}
+
+			if file == "" {
 				return fmt.Errorf("Could not find built package " + split.Name + "-" + version.String() + "-" + arch + ".pkg")
 			}
 

+ 4 - 1
main.go

@@ -203,7 +203,10 @@ func main() {
 
 	err = handleCmd()
 	if err != nil {
-		fmt.Println(err)
+		if err.Error() != "" {
+			fmt.Println(err)
+		}
+
 		status = 1
 		goto cleanup
 	}

+ 31 - 24
parser.go

@@ -445,6 +445,14 @@ func hasParam(arg string) bool {
 		return true
 	case "requestsplitn":
 		return true
+	case "answerclean":
+		return true
+	case "answeredit":
+		return true
+	case "answerupgrade":
+		return true
+	case "sortby":
+		return true
 	default:
 		return false
 	}
@@ -526,34 +534,33 @@ func (parser *arguments) parseCommandLine() (err error) {
 	usedNext := false
 
 	if len(args) < 1 {
-		err = fmt.Errorf("no operation specified (use -h for help)")
-		return
-	}
-
-	for k, arg := range args {
-		var nextArg string
+		parser.parseShortOption("-Syu", "")
+	} else {
+		for k, arg := range args {
+			var nextArg string
 
-		if usedNext {
-			usedNext = false
-			continue
-		}
+			if usedNext {
+				usedNext = false
+				continue
+			}
 
-		if k+1 < len(args) {
-			nextArg = args[k+1]
-		}
+			if k+1 < len(args) {
+				nextArg = args[k+1]
+			}
 
-		if parser.existsArg("--") {
-			parser.addTarget(arg)
-		} else if strings.HasPrefix(arg, "--") {
-			usedNext, err = parser.parseLongOption(arg, nextArg)
-		} else if strings.HasPrefix(arg, "-") {
-			usedNext, err = parser.parseShortOption(arg, nextArg)
-		} else {
-			parser.addTarget(arg)
-		}
+			if parser.existsArg("--") {
+				parser.addTarget(arg)
+			} else if strings.HasPrefix(arg, "--") {
+				usedNext, err = parser.parseLongOption(arg, nextArg)
+			} else if strings.HasPrefix(arg, "-") {
+				usedNext, err = parser.parseShortOption(arg, nextArg)
+			} else {
+				parser.addTarget(arg)
+			}
 
-		if err != nil {
-			return
+			if err != nil {
+				return
+			}
 		}
 	}
 

+ 24 - 8
print.go

@@ -288,9 +288,7 @@ func printNumberOfUpdates() error {
 	//todo
 	old := os.Stdout // keep backup of the real stdout
 	os.Stdout = nil
-	_, _, localNames, remoteNames, err := filterPackages()
-	dt, _ := getDepTree(append(localNames, remoteNames...))
-	aurUp, repoUp, err := upList(dt)
+	aurUp, repoUp, err := upList()
 	os.Stdout = old // restoring the real stdout
 	if err != nil {
 		return err
@@ -302,13 +300,11 @@ func printNumberOfUpdates() error {
 
 //TODO: Make it less hacky
 func printUpdateList(parser *arguments) error {
-	old := os.Stdout // Keep backup of the real stdout
+	old := os.Stdout // keep backup of the real stdout
 	os.Stdout = nil
 	_, _, localNames, remoteNames, err := filterPackages()
-	dt, _ := getDepTree(append(localNames, remoteNames...))
-	aurUp, repoUp, err := upList(dt)
-
-	os.Stdout = old // Restoring the real stdout
+	aurUp, repoUp, err := upList()
+	os.Stdout = old // restoring the real stdout
 	if err != nil {
 		return err
 	}
@@ -333,8 +329,28 @@ func printUpdateList(parser *arguments) error {
 		}
 	}
 
+	missing := false
+
+outer:
 	for pkg := range parser.targets {
+		for _, name := range localNames {
+			if name == pkg {
+				continue outer
+			}
+		}
+
+		for _, name := range remoteNames {
+			if name == pkg {
+				continue outer
+			}
+		}
+
 		fmt.Println(red(bold("error:")), "package '"+pkg+"' was not found")
+		missing = true
+	}
+
+	if missing {
+		return fmt.Errorf("")
 	}
 
 	return nil

+ 55 - 13
query.go

@@ -21,10 +21,32 @@ func (q aurQuery) Len() int {
 }
 
 func (q aurQuery) Less(i, j int) bool {
+	var result bool
+
+	switch config.SortBy {
+	case "votes":
+		result = q[i].NumVotes > q[j].NumVotes
+	case "popularity":
+		result = q[i].Popularity > q[j].Popularity
+	case "name":
+		result = lessRunes([]rune(q[i].Name), []rune(q[j].Name))
+	case "base":
+		result = lessRunes([]rune(q[i].PackageBase), []rune(q[j].PackageBase))
+	case "submitted":
+		result = q[i].FirstSubmitted < q[j].FirstSubmitted
+	case "modified":
+		result = q[i].LastModified < q[j].LastModified
+	case "id":
+		result = q[i].ID < q[j].ID
+	case "baseid":
+		result = q[i].PackageBaseID < q[j].PackageBaseID
+	}
+
 	if config.SortMode == BottomUp {
-		return q[i].NumVotes < q[j].NumVotes
+		return !result
 	}
-	return q[i].NumVotes > q[j].NumVotes
+
+	return result
 }
 
 func (q aurQuery) Swap(i, j int) {
@@ -72,11 +94,22 @@ func filterPackages() (local []alpm.Package, remote []alpm.Package,
 
 // NarrowSearch searches AUR and narrows based on subarguments
 func narrowSearch(pkgS []string, sortS bool) (aurQuery, error) {
+	var r []rpc.Pkg
+	var err error
+	var usedIndex int
+
 	if len(pkgS) == 0 {
 		return nil, nil
 	}
 
-	r, err := rpc.Search(pkgS[0])
+	for i, word := range pkgS {
+		r, err = rpc.Search(word)
+		if err == nil {
+			usedIndex = i
+			break
+		}
+	}
+
 	if err != nil {
 		return nil, err
 	}
@@ -93,7 +126,11 @@ func narrowSearch(pkgS []string, sortS bool) (aurQuery, error) {
 
 	for _, res := range r {
 		match := true
-		for _, pkgN := range pkgS[1:] {
+		for i, pkgN := range pkgS {
+			if usedIndex == i {
+				continue
+			}
+
 			if !(strings.Contains(res.Name, pkgN) || strings.Contains(strings.ToLower(res.Description), pkgN)) {
 				match = false
 				break
@@ -115,10 +152,7 @@ func narrowSearch(pkgS []string, sortS bool) (aurQuery, error) {
 
 // SyncSearch presents a query to the local repos and to the AUR.
 func syncSearch(pkgS []string) (err error) {
-	aq, err := narrowSearch(pkgS, true)
-	if err != nil {
-		return err
-	}
+	aq, aurErr := narrowSearch(pkgS, true)
 	pq, _, err := queryRepo(pkgS)
 	if err != nil {
 		return err
@@ -132,12 +166,17 @@ func syncSearch(pkgS []string) (err error) {
 		aq.printSearch(1)
 	}
 
+	if aurErr != nil {
+		fmt.Printf("Error during AUR search: %s\n", aurErr)
+		fmt.Println("Showing Repo packags only")
+	}
+
 	return nil
 }
 
 // SyncInfo serves as a pacman -Si for repo packages and AUR packages.
 func syncInfo(pkgS []string) (err error) {
-	var info []rpc.Pkg
+	var info []*rpc.Pkg
 	aurS, repoS, err := packageSlices(pkgS)
 	if err != nil {
 		return
@@ -170,7 +209,7 @@ func syncInfo(pkgS []string) (err error) {
 
 	if len(aurS) != 0 {
 		for _, pkg := range info {
-			PrintInfo(&pkg)
+			PrintInfo(pkg)
 		}
 	}
 
@@ -401,8 +440,8 @@ func statistics() (info struct {
 // of packages exceeds the number set in config.RequestSplitN.
 // If the number does exceed config.RequestSplitN multiple rpc requests will be
 // performed concurrently.
-func aurInfo(names []string) ([]rpc.Pkg, error) {
-	info := make([]rpc.Pkg, 0, len(names))
+func aurInfo(names []string) ([]*rpc.Pkg, error) {
+	info := make([]*rpc.Pkg, 0, len(names))
 	seen := make(map[string]int)
 	var mux sync.Mutex
 	var wg sync.WaitGroup
@@ -423,7 +462,10 @@ func aurInfo(names []string) ([]rpc.Pkg, error) {
 			return
 		}
 		mux.Lock()
-		info = append(info, tempInfo...)
+		for _, _i := range tempInfo {
+			i := _i
+			info = append(info, &i)
+		}
 		mux.Unlock()
 	}
 

+ 50 - 30
upgrade.go

@@ -1,14 +1,13 @@
 package main
 
 import (
-	"bufio"
 	"fmt"
-	"os"
 	"sort"
 	"strings"
 	"sync"
 
 	alpm "github.com/jguer/go-alpm"
+	rpc "github.com/mikkeloscar/aur"
 	pkgb "github.com/mikkeloscar/gopkgbuild"
 )
 
@@ -27,15 +26,40 @@ func (u upSlice) Len() int      { return len(u) }
 func (u upSlice) Swap(i, j int) { u[i], u[j] = u[j], u[i] }
 
 func (u upSlice) Less(i, j int) bool {
-	if u[i].Repository != u[j].Repository {
+	if u[i].Repository == u[j].Repository {
+		iRunes := []rune(u[i].Name)
+		jRunes := []rune(u[j].Name)
+		return lessRunes(iRunes, jRunes)
+	}
+
+	syncDb, err := alpmHandle.SyncDbs()
+	if err != nil {
 		iRunes := []rune(u[i].Repository)
 		jRunes := []rune(u[j].Repository)
 		return lessRunes(iRunes, jRunes)
+	}
+
+	less := false
+	found := syncDb.ForEach(func(db alpm.Db) error {
+		if db.Name() == u[i].Repository {
+			less = true
+		} else if db.Name() == u[j].Repository {
+			less = false
+		} else {
+			return nil
+		}
+
+		return fmt.Errorf("")
+	})
+
+	if found != nil {
+		return less
 	} else {
-		iRunes := []rune(u[i].Name)
-		jRunes := []rune(u[j].Name)
+		iRunes := []rune(u[i].Repository)
+		jRunes := []rune(u[j].Repository)
 		return lessRunes(iRunes, jRunes)
 	}
+
 }
 
 func getVersionDiff(oldVersion, newversion string) (left, right string) {
@@ -63,7 +87,7 @@ func getVersionDiff(oldVersion, newversion string) (left, right string) {
 }
 
 // upList returns lists of packages to upgrade from each source.
-func upList(dt *depTree) (aurUp upSlice, repoUp upSlice, err error) {
+func upList() (aurUp upSlice, repoUp upSlice, err error) {
 	local, remote, _, remoteNames, err := filterPackages()
 	if err != nil {
 		return nil, nil, err
@@ -86,7 +110,7 @@ func upList(dt *depTree) (aurUp upSlice, repoUp upSlice, err error) {
 	fmt.Println(bold(cyan("::") + " Searching AUR for updates..."))
 	wg.Add(1)
 	go func() {
-		aurUp, aurErr = upAUR(remote, remoteNames, dt)
+		aurUp, aurErr = upAUR(remote, remoteNames)
 		wg.Done()
 	}()
 
@@ -180,9 +204,20 @@ func upDevel(remote []alpm.Package) (toUpgrade upSlice, err error) {
 
 // upAUR gathers foreign packages and checks if they have new versions.
 // Output: Upgrade type package list.
-func upAUR(remote []alpm.Package, remoteNames []string, dt *depTree) (toUpgrade upSlice, err error) {
+func upAUR(remote []alpm.Package, remoteNames []string) (upSlice, error) {
+	toUpgrade := make(upSlice, 0)
+	_pkgdata, err := aurInfo(remoteNames)
+	if err != nil {
+		return nil, err
+	}
+
+	pkgdata := make(map[string]*rpc.Pkg)
+	for _, pkg := range _pkgdata {
+		pkgdata[pkg.Name] = pkg
+	}
+
 	for _, pkg := range remote {
-		aurPkg, ok := dt.Aur[pkg.Name()]
+		aurPkg, ok := pkgdata[pkg.Name()]
 		if !ok {
 			continue
 		}
@@ -199,7 +234,7 @@ func upAUR(remote []alpm.Package, remoteNames []string, dt *depTree) (toUpgrade
 		}
 	}
 
-	return
+	return toUpgrade, nil
 }
 
 // upRepo gathers local packages and checks if they have new versions.
@@ -228,15 +263,12 @@ func upRepo(local []alpm.Package) (upSlice, error) {
 }
 
 // upgradePkgs handles updating the cache and installing updates.
-func upgradePkgs(dt *depTree) (stringSet, stringSet, error) {
+func upgradePkgs(aurUp, repoUp upSlice) (stringSet, stringSet, error) {
 	ignore := make(stringSet)
 	aurNames := make(stringSet)
 
-	aurUp, repoUp, err := upList(dt)
-	if err != nil {
-		return ignore, aurNames, err
-	} else if len(aurUp)+len(repoUp) == 0 {
-		return ignore, aurNames, err
+	if len(aurUp)+len(repoUp) == 0 {
+		return ignore, aurNames, nil
 	}
 
 	sort.Sort(repoUp)
@@ -245,30 +277,18 @@ func upgradePkgs(dt *depTree) (stringSet, stringSet, error) {
 	repoUp.Print(len(aurUp) + 1)
 	aurUp.Print(1)
 
-	if config.NoConfirm {
-		for _, up := range aurUp {
-			aurNames.set(up.Name)
-		}
-		return ignore, aurNames, nil
-	}
-
 	fmt.Println(bold(green(arrow + " Packages to not upgrade (eg: 1 2 3, 1-3, ^4 or repo name)")))
 	fmt.Print(bold(green(arrow + " ")))
-	reader := bufio.NewReader(os.Stdin)
 
-	numberBuf, overflow, err := reader.ReadLine()
+	numbers, err := getInput(config.AnswerUpgrade)
 	if err != nil {
 		return nil, nil, err
 	}
 
-	if overflow {
-		return nil, nil, fmt.Errorf("Input too long")
-	}
-
 	//upgrade menu asks you which packages to NOT upgrade so in this case
 	//include and exclude are kind of swaped
 	//include, exclude, other := parseNumberMenu(string(numberBuf))
-	include, exclude, otherInclude, otherExclude := parseNumberMenu(string(numberBuf))
+	include, exclude, otherInclude, otherExclude := parseNumberMenu(numbers)
 
 	isInclude := len(exclude) == 0 && len(otherExclude) == 0
 

+ 36 - 5
vcs.go

@@ -3,10 +3,14 @@ package main
 import (
 	"bytes"
 	"encoding/json"
+	"fmt"
 	"os"
 	"os/exec"
 	"strings"
 	"time"
+
+	rpc "github.com/mikkeloscar/aur"
+	gopkg "github.com/mikkeloscar/gopkgbuild"
 )
 
 // Info contains the last commit sha of a repo
@@ -20,16 +24,41 @@ type shaInfo struct {
 
 // createDevelDB forces yay to create a DB of the existing development packages
 func createDevelDB() error {
+	infoMap := make(map[string]*rpc.Pkg)
+	srcinfosStale := make(map[string]*gopkg.PKGBUILD)
+
 	_, _, _, remoteNames, err := filterPackages()
 	if err != nil {
 		return err
 	}
 
-	config.NoConfirm = true
-	arguments := makeArguments()
-	arguments.addArg("gendb")
-	arguments.addTarget(remoteNames...)
-	err = install(arguments)
+	info, err := aurInfo(remoteNames)
+	if err != nil {
+		return err
+	}
+
+	for _, pkg := range info {
+		infoMap[pkg.Name] = pkg
+	}
+
+	bases := getBases(infoMap)
+
+	downloadPkgBuilds(info, sliceToStringSet(remoteNames), bases)
+	tryParsesrcinfosFile(info, srcinfosStale, bases)
+
+	for _, pkg := range info {
+		pkgbuild, ok := srcinfosStale[pkg.PackageBase]
+		if !ok {
+			continue
+		}
+
+		for _, pkg := range bases[pkg.PackageBase] {
+			updateVCSData(pkg.Name, pkgbuild.Source)
+		}
+	}
+
+	fmt.Println(bold(green(arrow + " GenDB finished. No packages were installed")))
+
 	return err
 }
 
@@ -95,6 +124,8 @@ func updateVCSData(pkgName string, sources []string) {
 		}
 
 		savedInfo[pkgName] = info
+
+		fmt.Println(bold(green(arrow+" Found git repo: ")) + cyan(url))
 		saveVCSInfo()
 	}
 }