Browse Source

Merged flatten branch

Jguer 7 years atrás
parent
commit
4b78c23fb9
72 changed files with 8046 additions and 1384 deletions
  1. 27 0
      Gopkg.lock
  2. 34 0
      Gopkg.toml
  3. 4 1
      README.md
  4. 0 76
      actions.go
  5. 0 257
      aur/aur.go
  6. 0 44
      aur/query.go
  7. 0 251
      aur/result.go
  8. 60 0
      clean.go
  9. 115 51
      yay.go
  10. 61 0
      completions.go
  11. 27 117
      config/config.go
  12. 119 0
      dependencies.go
  13. 122 0
      download.go
  14. 190 0
      install.go
  15. 0 420
      pacman/pacman.go
  16. 0 62
      pacman/pacman_test.go
  17. 183 0
      print.go
  18. 36 0
      print_test.go
  19. 309 53
      query.go
  20. 27 0
      query_test.go
  21. 342 0
      upgrade.go
  22. 18 48
      aur/vcs/github.go
  23. 4 4
      aur/vcs/github_test.go
  24. 1 0
      vendor/github.com/jguer/go-alpm/.gitignore
  25. 19 0
      vendor/github.com/jguer/go-alpm/LICENSE
  26. 30 0
      vendor/github.com/jguer/go-alpm/README.md
  27. 29 0
      vendor/github.com/jguer/go-alpm/alpm.go
  28. 82 0
      vendor/github.com/jguer/go-alpm/alpm_test.go
  29. 31 0
      vendor/github.com/jguer/go-alpm/callbacks.c
  30. 36 0
      vendor/github.com/jguer/go-alpm/callbacks.go
  31. 288 0
      vendor/github.com/jguer/go-alpm/conf.go
  32. 66 0
      vendor/github.com/jguer/go-alpm/conf_test.go
  33. 153 0
      vendor/github.com/jguer/go-alpm/db.go
  34. 44 0
      vendor/github.com/jguer/go-alpm/dependency.go
  35. 98 0
      vendor/github.com/jguer/go-alpm/enums.go
  36. 21 0
      vendor/github.com/jguer/go-alpm/error.go
  37. 13 0
      vendor/github.com/jguer/go-alpm/examples/Makefile
  38. 1 0
      vendor/github.com/jguer/go-alpm/examples/README.md
  39. 38 0
      vendor/github.com/jguer/go-alpm/examples/installed.go
  40. 30 0
      vendor/github.com/jguer/go-alpm/examples/search.go
  41. 78 0
      vendor/github.com/jguer/go-alpm/examples/updates.go
  42. 85 0
      vendor/github.com/jguer/go-alpm/handle.go
  43. 246 0
      vendor/github.com/jguer/go-alpm/package.go
  44. 89 0
      vendor/github.com/jguer/go-alpm/package_test.go
  45. 1 0
      vendor/github.com/jguer/go-alpm/testing/README.md
  46. 41 0
      vendor/github.com/jguer/go-alpm/testing/conf/good_pacman.conf
  47. 125 0
      vendor/github.com/jguer/go-alpm/types.go
  48. 674 0
      vendor/github.com/mikkeloscar/aur/LICENSE
  49. 23 0
      vendor/github.com/mikkeloscar/aur/README.md
  50. 104 0
      vendor/github.com/mikkeloscar/aur/aur.go
  51. 69 0
      vendor/github.com/mikkeloscar/aur/aur_test.go
  52. 674 0
      vendor/github.com/mikkeloscar/gopkgbuild/LICENSE
  53. 65 0
      vendor/github.com/mikkeloscar/gopkgbuild/README.md
  54. 279 0
      vendor/github.com/mikkeloscar/gopkgbuild/lex.go
  55. 530 0
      vendor/github.com/mikkeloscar/gopkgbuild/pkgbuild.go
  56. 211 0
      vendor/github.com/mikkeloscar/gopkgbuild/pkgbuild_test.go
  57. 150 0
      vendor/github.com/mikkeloscar/gopkgbuild/test_pkgbuilds/PKGBUILD_glibc
  58. 389 0
      vendor/github.com/mikkeloscar/gopkgbuild/test_pkgbuilds/PKGBUILD_grub
  59. 301 0
      vendor/github.com/mikkeloscar/gopkgbuild/test_pkgbuilds/PKGBUILD_linux
  60. 88 0
      vendor/github.com/mikkeloscar/gopkgbuild/test_pkgbuilds/PKGBUILD_openssh
  61. 96 0
      vendor/github.com/mikkeloscar/gopkgbuild/test_pkgbuilds/PKGBUILD_pacman
  62. 66 0
      vendor/github.com/mikkeloscar/gopkgbuild/test_pkgbuilds/PKGBUILD_sudo
  63. 197 0
      vendor/github.com/mikkeloscar/gopkgbuild/test_pkgbuilds/PKGBUILD_systemd
  64. 36 0
      vendor/github.com/mikkeloscar/gopkgbuild/test_pkgbuilds/SRCINFO_glibc
  65. 75 0
      vendor/github.com/mikkeloscar/gopkgbuild/test_pkgbuilds/SRCINFO_grub
  66. 57 0
      vendor/github.com/mikkeloscar/gopkgbuild/test_pkgbuilds/SRCINFO_linux
  67. 38 0
      vendor/github.com/mikkeloscar/gopkgbuild/test_pkgbuilds/SRCINFO_openssh
  68. 44 0
      vendor/github.com/mikkeloscar/gopkgbuild/test_pkgbuilds/SRCINFO_pacman
  69. 28 0
      vendor/github.com/mikkeloscar/gopkgbuild/test_pkgbuilds/SRCINFO_sudo
  70. 118 0
      vendor/github.com/mikkeloscar/gopkgbuild/test_pkgbuilds/SRCINFO_systemd
  71. 289 0
      vendor/github.com/mikkeloscar/gopkgbuild/version.go
  72. 122 0
      vendor/github.com/mikkeloscar/gopkgbuild/version_test.go

+ 27 - 0
Gopkg.lock

@@ -0,0 +1,27 @@
+# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.
+
+
+[[projects]]
+  branch = "master"
+  name = "github.com/jguer/go-alpm"
+  packages = ["."]
+  revision = "f82ad11b38f675991ef2425dbeff03ef346bc113"
+
+[[projects]]
+  branch = "master"
+  name = "github.com/mikkeloscar/aur"
+  packages = ["."]
+  revision = "dc2f99767ec5d809269bd3bac3878f6e949f8e64"
+
+[[projects]]
+  branch = "master"
+  name = "github.com/mikkeloscar/gopkgbuild"
+  packages = ["."]
+  revision = "46d010163d87513b0f05fb67400475348bd50cc9"
+
+[solve-meta]
+  analyzer-name = "dep"
+  analyzer-version = 1
+  inputs-digest = "456465ee334310996a51a2282bf4cfe9f6269db508479c962474d61a4ce0a08c"
+  solver-name = "gps-cdcl"
+  solver-version = 1

+ 34 - 0
Gopkg.toml

@@ -0,0 +1,34 @@
+
+# Gopkg.toml example
+#
+# Refer to https://github.com/golang/dep/blob/master/docs/Gopkg.toml.md
+# for detailed Gopkg.toml documentation.
+#
+# required = ["github.com/user/thing/cmd/thing"]
+# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"]
+#
+# [[constraint]]
+#   name = "github.com/user/project"
+#   version = "1.0.0"
+#
+# [[constraint]]
+#   name = "github.com/user/project2"
+#   branch = "dev"
+#   source = "github.com/myfork/project2"
+#
+# [[override]]
+#  name = "github.com/x/y"
+#  version = "2.4.0"
+
+
+[[constraint]]
+  branch = "master"
+  name = "github.com/jguer/go-alpm"
+
+[[constraint]]
+  branch = "master"
+  name = "github.com/mikkeloscar/aur"
+
+[[constraint]]
+  branch = "master"
+  name = "github.com/mikkeloscar/gopkgbuild"

+ 4 - 1
README.md

@@ -29,11 +29,15 @@ Yay was created with a few objectives in mind and based on the design of yaourt
 - `yay -Cd` cleans unneeded dependencies
 - `yay -G` downloads PKGBuild from ABS or AUR
 
+![Yay Syu](http://jguer.github.io/yay/yayupgrade.png "yay -Syu")
 ![Yay Qstats](http://jguer.github.io/yay/yay2.png "yay -Qstats")
 ![Yay NumberMenu](http://jguer.github.io/yay/yay3.png "yay gtk-theme")
 
 ### Changelog
 
+#### 2.165
+- Upgrade list now allows skipping upgrade install.
+
 #### 2.159
 - Qstats now warns about packages not available in AUR.
 
@@ -43,7 +47,6 @@ Yay was created with a few objectives in mind and based on the design of yaourt
 - Pacman backend rewritten and simplified
 - Added config framework.
 
-
 #### 1.115
 - Added AUR completions (updates on first completion every 48h)
 

+ 0 - 76
actions.go

@@ -1,76 +0,0 @@
-package main
-
-import (
-	"fmt"
-	"os"
-
-	aur "github.com/jguer/yay/aur"
-	"github.com/jguer/yay/config"
-	pac "github.com/jguer/yay/pacman"
-)
-
-// Install handles package installs
-func install(pkgs []string, flags []string) error {
-	aurs, repos, _ := pac.PackageSlices(pkgs)
-
-	if len(repos) != 0 {
-		err := config.PassToPacman("-S", repos, flags)
-		if err != nil {
-			fmt.Println("Error installing repo packages.")
-		}
-	}
-
-	if len(aurs) != 0 {
-		err := aur.Install(aurs, flags)
-		if err != nil {
-			fmt.Println("Error installing aur packages.")
-		}
-	}
-	return nil
-}
-
-// Upgrade handles updating the cache and installing updates.
-func upgrade(flags []string) error {
-	errp := config.PassToPacman("-Syu", nil, flags)
-	erra := aur.Upgrade(flags)
-
-	if errp != nil {
-		return errp
-	}
-
-	return erra
-}
-
-// CleanDependencies removels all dangling dependencies in system
-func cleanDependencies(pkgs []string) error {
-	hanging, err := pac.HangingPackages()
-	if err != nil {
-		return err
-	}
-
-	if len(hanging) != 0 {
-		if !config.ContinueTask("Confirm Removal?", "nN") {
-			return nil
-		}
-		err = pac.CleanRemove(hanging)
-	}
-
-	return err
-}
-
-// GetPkgbuild gets the pkgbuild of the package 'pkg' trying the ABS first and then the AUR trying the ABS first and then the AUR.
-func getPkgbuild(pkg string) (err error) {
-	wd, err := os.Getwd()
-	if err != nil {
-		return
-	}
-	wd = wd + "/"
-
-	err = pac.GetPkgbuild(pkg, wd)
-	if err == nil {
-		return
-	}
-
-	err = aur.GetPkgbuild(pkg, wd)
-	return
-}

+ 0 - 257
aur/aur.go

@@ -1,257 +0,0 @@
-package aur
-
-import (
-	"bufio"
-	"bytes"
-	"fmt"
-	"net/http"
-	"os"
-	"sort"
-	"strings"
-
-	alpm "github.com/jguer/go-alpm"
-	vcs "github.com/jguer/yay/aur/vcs"
-	"github.com/jguer/yay/config"
-	"github.com/jguer/yay/pacman"
-	rpc "github.com/mikkeloscar/aur"
-)
-
-// BaseURL givers the AUR default address.
-const BaseURL string = "https://aur.archlinux.org"
-
-var specialDBsauce bool = false
-
-// NarrowSearch searches AUR and narrows based on subarguments
-func NarrowSearch(pkgS []string, sortS bool) (Query, error) {
-	if len(pkgS) == 0 {
-		return nil, nil
-	}
-
-	r, err := rpc.Search(pkgS[0])
-	if err != nil {
-		return nil, err
-	}
-
-	if len(pkgS) == 1 {
-		if sortS {
-			sort.Sort(Query(r))
-		}
-		return r, err
-	}
-
-	var aq Query
-	var n int
-
-	for _, res := range r {
-		match := true
-		for _, pkgN := range pkgS[1:] {
-			if !(strings.Contains(res.Name, pkgN) || strings.Contains(strings.ToLower(res.Description), pkgN)) {
-				match = false
-				break
-			}
-		}
-
-		if match {
-			n++
-			aq = append(aq, res)
-		}
-	}
-
-	if sortS {
-		sort.Sort(aq)
-	}
-
-	return aq, err
-}
-
-// Install sends system commands to make and install a package from pkgName
-func Install(pkgName []string, flags []string) (err error) {
-	q, err := rpc.Info(pkgName)
-	if err != nil {
-		return
-	}
-
-	if len(q) != len(pkgName) {
-		fmt.Printf("Some package from list\n%+v\ndoes not exist", pkgName)
-	}
-
-	var finalrm []string
-	for _, i := range q {
-		mrm, err := PkgInstall(&i, flags)
-		if err != nil {
-			fmt.Println("Error installing", i.Name, ":", err)
-		}
-		finalrm = append(finalrm, mrm...)
-	}
-
-	if len(finalrm) != 0 {
-		err = RemoveMakeDeps(finalrm)
-	}
-
-	return err
-}
-
-// CreateDevelDB forces yay to create a DB of the existing development packages
-func CreateDevelDB() error {
-	foreign, err := pacman.ForeignPackages()
-	if err != nil {
-		return err
-	}
-
-	keys := make([]string, len(foreign))
-	i := 0
-	for k := range foreign {
-		keys[i] = k
-		i++
-	}
-
-	config.YayConf.NoConfirm = true
-	specialDBsauce = true
-	err = Install(keys, nil)
-	return err
-}
-
-func develUpgrade(foreign map[string]alpm.Package, flags []string) error {
-	fmt.Println(" Checking development packages...")
-	develUpdates := vcs.CheckUpdates(foreign)
-	if len(develUpdates) != 0 {
-		for _, q := range develUpdates {
-			fmt.Printf("\x1b[1m\x1b[32m==>\x1b[33;1m %s\x1b[0m\n", q)
-		}
-		// Install updated packages
-		if !config.ContinueTask("Proceed with upgrade?", "nN") {
-			return nil
-		}
-
-		err := Install(develUpdates, flags)
-		if err != nil {
-			fmt.Println(err)
-		}
-	}
-
-	return nil
-}
-
-// Upgrade tries to update every foreign package installed in the system
-func Upgrade(flags []string) error {
-	fmt.Println("\x1b[1;36;1m::\x1b[0m\x1b[1m Starting AUR upgrade...\x1b[0m")
-
-	foreign, err := pacman.ForeignPackages()
-	if err != nil {
-		return err
-	}
-	keys := make([]string, len(foreign))
-	i := 0
-	for k := range foreign {
-		keys[i] = k
-		i++
-	}
-
-	if config.YayConf.Devel {
-		err := develUpgrade(foreign, flags)
-		if err != nil {
-			fmt.Println(err)
-		}
-	}
-
-	var q Query
-	var j int
-	for i = len(keys); i != 0; i = j {
-		j = i - config.YayConf.RequestSplitN
-		if j < 0 {
-			j = 0
-		}
-		qtemp, err := rpc.Info(keys[j:i])
-		q = append(q, qtemp...)
-		if err != nil {
-			return err
-		}
-	}
-
-	var buffer bytes.Buffer
-	buffer.WriteString("\n")
-	outdated := q[:0]
-	for i, res := range q {
-		fmt.Printf("\r Checking %d/%d packages...", i+1, len(q))
-
-		if _, ok := foreign[res.Name]; ok {
-			// Leaving this here for now, warn about downgrades later
-			if (config.YayConf.TimeUpdate && (int64(res.LastModified) > foreign[res.Name].BuildDate().Unix())) ||
-				alpm.VerCmp(foreign[res.Name].Version(), res.Version) < 0 {
-				buffer.WriteString(fmt.Sprintf("\x1b[1m\x1b[32m==>\x1b[33;1m %s: \x1b[0m%s \x1b[33;1m-> \x1b[0m%s\n",
-					res.Name, foreign[res.Name].Version(), res.Version))
-				outdated = append(outdated, res)
-			}
-		}
-	}
-	fmt.Println(buffer.String())
-
-	//If there are no outdated packages, don't prompt
-	if len(outdated) == 0 {
-		fmt.Println("there is nothing to do")
-		return nil
-	}
-
-	// Install updated packages
-	if !config.ContinueTask("Proceed with upgrade?", "nN") {
-		return nil
-	}
-
-	var finalmdeps []string
-	for _, pkgi := range outdated {
-		mdeps, err := PkgInstall(&pkgi, flags)
-		finalmdeps = append(finalmdeps, mdeps...)
-		if err != nil {
-			fmt.Println(err)
-		}
-	}
-
-	err = pacman.CleanRemove(finalmdeps)
-	if err != nil {
-		fmt.Println(err)
-	}
-
-	return nil
-}
-
-// GetPkgbuild downloads pkgbuild from the AUR.
-func GetPkgbuild(pkgN string, dir string) (err error) {
-	aq, err := rpc.Info([]string{pkgN})
-	if err != nil {
-		return err
-	}
-
-	if len(aq) == 0 {
-		return fmt.Errorf("no results")
-	}
-
-	fmt.Printf("\x1b[1;32m==>\x1b[1;33m %s \x1b[1;32mfound in AUR.\x1b[0m\n", pkgN)
-	config.DownloadAndUnpack(BaseURL+aq[0].URLPath, dir, false)
-	return
-}
-
-//CreateAURList creates a new completion file
-func CreateAURList(out *os.File) (err error) {
-	resp, err := http.Get("https://aur.archlinux.org/packages.gz")
-	if err != nil {
-		return err
-	}
-	defer resp.Body.Close()
-
-	scanner := bufio.NewScanner(resp.Body)
-
-	scanner.Scan()
-	for scanner.Scan() {
-		fmt.Print(scanner.Text())
-		out.WriteString(scanner.Text())
-		if config.YayConf.Shell == "fish" {
-			fmt.Print("\tAUR\n")
-			out.WriteString("\tAUR\n")
-		} else {
-			fmt.Print("\n")
-			out.WriteString("\n")
-		}
-	}
-
-	return nil
-}

+ 0 - 44
aur/query.go

@@ -1,44 +0,0 @@
-package aur
-
-import (
-	"fmt"
-
-	"github.com/jguer/yay/config"
-	rpc "github.com/mikkeloscar/aur"
-)
-
-// Query is a collection of Results
-type Query []rpc.Pkg
-
-func (q Query) Len() int {
-	return len(q)
-}
-
-func (q Query) Less(i, j int) bool {
-	if config.YayConf.SortMode == config.BottomUp {
-		return q[i].NumVotes < q[j].NumVotes
-	}
-	return q[i].NumVotes > q[j].NumVotes
-}
-
-func (q Query) Swap(i, j int) {
-	q[i], q[j] = q[j], q[i]
-}
-
-// MissingPackage warns if the Query was unable to find a package
-func (q Query) MissingPackage(pkgS []string) {
-	for _, depName := range pkgS {
-		found := false
-		for _, dep := range q {
-			if dep.Name == depName {
-				found = true
-				break
-			}
-		}
-
-		if !found {
-			fmt.Println("\x1b[31mUnable to find", depName, "in AUR\x1b[0m")
-		}
-	}
-	return
-}

+ 0 - 251
aur/result.go

@@ -1,251 +0,0 @@
-package aur
-
-import (
-	"fmt"
-	"os"
-	"os/exec"
-
-	vcs "github.com/jguer/yay/aur/vcs"
-	"github.com/jguer/yay/config"
-	"github.com/jguer/yay/pacman"
-	rpc "github.com/mikkeloscar/aur"
-	gopkg "github.com/mikkeloscar/gopkgbuild"
-)
-
-// PkgDependencies returns package dependencies not installed belonging to AUR
-// 0 is Repo, 1 is Foreign.
-func PkgDependencies(a *rpc.Pkg) (runDeps [2][]string, makeDeps [2][]string, err error) {
-	var q Query
-	if len(a.Depends) == 0 && len(a.MakeDepends) == 0 {
-		q, err = rpc.Info([]string{a.Name})
-		if len(q) == 0 || err != nil {
-			err = fmt.Errorf("Unable to search dependencies, %s", err)
-			return
-		}
-	} else {
-		q = append(q, *a)
-	}
-
-	depSearch := pacman.BuildDependencies(a.Depends)
-	if len(a.Depends) != 0 {
-		runDeps[0], runDeps[1] = depSearch(q[0].Depends, true, false)
-		if len(runDeps[0]) != 0 || len(runDeps[1]) != 0 {
-			fmt.Println("\x1b[1;32m=>\x1b[1;33m Run Dependencies: \x1b[0m")
-			printDeps(runDeps[0], runDeps[1])
-		}
-	}
-
-	if len(a.MakeDepends) != 0 {
-		makeDeps[0], makeDeps[1] = depSearch(q[0].MakeDepends, false, false)
-		if len(makeDeps[0]) != 0 || len(makeDeps[1]) != 0 {
-			fmt.Println("\x1b[1;32m=>\x1b[1;33m Make Dependencies: \x1b[0m")
-			printDeps(makeDeps[0], makeDeps[1])
-		}
-	}
-	depSearch(a.MakeDepends, false, true)
-
-	err = nil
-	return
-}
-
-func printDeps(repoDeps []string, aurDeps []string) {
-	if len(repoDeps) != 0 {
-		fmt.Print("\x1b[1;32m==> Repository dependencies: \x1b[0m")
-		for _, repoD := range repoDeps {
-			fmt.Print("\x1b[33m", repoD, " \x1b[0m")
-		}
-		fmt.Print("\n")
-
-	}
-	if len(aurDeps) != 0 {
-		fmt.Print("\x1b[1;32m==> AUR dependencies: \x1b[0m")
-		for _, aurD := range aurDeps {
-			fmt.Print("\x1b[33m", aurD, " \x1b[0m")
-		}
-		fmt.Print("\n")
-	}
-}
-
-func setupPackageSpace(a *rpc.Pkg) (dir string, pkgbuild *gopkg.PKGBUILD, err error) {
-	dir = config.YayConf.BuildDir + a.PackageBase + "/"
-
-	if _, err = os.Stat(dir); !os.IsNotExist(err) {
-		if !config.ContinueTask("Directory exists. Clean Build?", "yY") {
-			_ = os.RemoveAll(config.YayConf.BuildDir + a.PackageBase)
-		}
-	}
-
-	if err = config.DownloadAndUnpack(BaseURL+a.URLPath, config.YayConf.BuildDir, false); err != nil {
-		return
-	}
-
-	if !config.ContinueTask("Edit PKGBUILD?", "yY") {
-		editcmd := exec.Command(config.Editor(), dir+"PKGBUILD")
-		editcmd.Stdin, editcmd.Stdout, editcmd.Stderr = os.Stdin, os.Stdout, os.Stderr
-		editcmd.Run()
-	}
-
-	pkgbuild, err = gopkg.ParseSRCINFO(dir + ".SRCINFO")
-	if err == nil {
-		for _, pkgsource := range pkgbuild.Source {
-			owner, repo := vcs.ParseSource(pkgsource)
-			if owner != "" && repo != "" {
-				err = vcs.BranchInfo(a.Name, owner, repo)
-				if err != nil {
-					fmt.Println(err)
-				}
-			}
-		}
-	}
-
-	return
-}
-
-// PkgInstall handles install from Info Result.
-func PkgInstall(a *rpc.Pkg, flags []string) (finalmdeps []string, err error) {
-	fmt.Printf("\x1b[1;32m==> Installing\x1b[33m %s\x1b[0m\n", a.Name)
-	if a.Maintainer == "" {
-		fmt.Println("\x1b[1;31;40m==> Warning:\x1b[0;;40m This package is orphaned.\x1b[0m")
-	}
-
-	dir, _, err := setupPackageSpace(a)
-	if err != nil {
-		return
-	}
-
-	if specialDBsauce {
-		return
-	}
-
-	runDeps, makeDeps, err := PkgDependencies(a)
-	if err != nil {
-		return
-	}
-
-	repoDeps := append(runDeps[0], makeDeps[0]...)
-	aurDeps := append(runDeps[1], makeDeps[1]...)
-	finalmdeps = append(finalmdeps, makeDeps[0]...)
-	finalmdeps = append(finalmdeps, makeDeps[1]...)
-
-	if len(aurDeps) != 0 || len(repoDeps) != 0 {
-		if !config.ContinueTask("Continue?", "nN") {
-			return finalmdeps, fmt.Errorf("user did not like the dependencies")
-		}
-	}
-
-	aurQ, _ := rpc.Info(aurDeps)
-	if len(aurQ) != len(aurDeps) {
-		(Query)(aurQ).MissingPackage(aurDeps)
-		if !config.ContinueTask("Continue?", "nN") {
-			return finalmdeps, fmt.Errorf("unable to install dependencies")
-		}
-	}
-
-	var depArgs []string
-	if config.YayConf.NoConfirm {
-		depArgs = []string{"--asdeps", "--noconfirm"}
-	} else {
-		depArgs = []string{"--asdeps"}
-	}
-	// Repo dependencies
-	if len(repoDeps) != 0 {
-		errR := config.PassToPacman("-S", repoDeps, depArgs)
-		if errR != nil {
-			return finalmdeps, errR
-		}
-	}
-
-	// Handle AUR dependencies
-	for _, dep := range aurQ {
-		finalmdepsR, errA := PkgInstall(&dep, depArgs)
-		finalmdeps = append(finalmdeps, finalmdepsR...)
-
-		if errA != nil {
-			pacman.CleanRemove(repoDeps)
-			pacman.CleanRemove(aurDeps)
-			return finalmdeps, errA
-		}
-	}
-
-	args := []string{"-sri"}
-	args = append(args, flags...)
-	makepkgcmd := exec.Command(config.YayConf.MakepkgBin, args...)
-	makepkgcmd.Stdin, makepkgcmd.Stdout, makepkgcmd.Stderr = os.Stdin, os.Stdout, os.Stderr
-	makepkgcmd.Dir = dir
-	err = makepkgcmd.Run()
-	if err == nil {
-		_ = vcs.SaveBranchInfo()
-	}
-	return
-}
-
-// PrintInfo prints package info like pacman -Si.
-func PrintInfo(a *rpc.Pkg) {
-	fmt.Println("\x1b[1;37mRepository      :\x1b[0m", "aur")
-	fmt.Println("\x1b[1;37mName            :\x1b[0m", a.Name)
-	fmt.Println("\x1b[1;37mVersion         :\x1b[0m", a.Version)
-	fmt.Println("\x1b[1;37mDescription     :\x1b[0m", a.Description)
-	if a.URL != "" {
-		fmt.Println("\x1b[1;37mURL             :\x1b[0m", a.URL)
-	} else {
-		fmt.Println("\x1b[1;37mURL             :\x1b[0m", "None")
-	}
-	fmt.Println("\x1b[1;37mLicenses        :\x1b[0m", a.License)
-
-	// if len(a.Provides) != 0 {
-	// 	fmt.Println("\x1b[1;37mProvides        :\x1b[0m", a.Provides)
-	// } else {
-	// 	fmt.Println("\x1b[1;37mProvides        :\x1b[0m", "None")
-	// }
-
-	if len(a.Depends) != 0 {
-		fmt.Println("\x1b[1;37mDepends On      :\x1b[0m", a.Depends)
-	} else {
-		fmt.Println("\x1b[1;37mDepends On      :\x1b[0m", "None")
-	}
-
-	if len(a.MakeDepends) != 0 {
-		fmt.Println("\x1b[1;37mMake depends On :\x1b[0m", a.MakeDepends)
-	} else {
-		fmt.Println("\x1b[1;37mMake depends On :\x1b[0m", "None")
-	}
-
-	if len(a.OptDepends) != 0 {
-		fmt.Println("\x1b[1;37mOptional Deps   :\x1b[0m", a.OptDepends)
-	} else {
-		fmt.Println("\x1b[1;37mOptional Deps   :\x1b[0m", "None")
-	}
-
-	if len(a.Conflicts) != 0 {
-		fmt.Println("\x1b[1;37mConflicts With  :\x1b[0m", a.Conflicts)
-	} else {
-		fmt.Println("\x1b[1;37mConflicts With  :\x1b[0m", "None")
-	}
-
-	if a.Maintainer != "" {
-		fmt.Println("\x1b[1;37mMaintainer      :\x1b[0m", a.Maintainer)
-	} else {
-		fmt.Println("\x1b[1;37mMaintainer      :\x1b[0m", "None")
-	}
-	fmt.Println("\x1b[1;37mVotes           :\x1b[0m", a.NumVotes)
-	fmt.Println("\x1b[1;37mPopularity      :\x1b[0m", a.Popularity)
-
-	if a.OutOfDate != 0 {
-		fmt.Println("\x1b[1;37mOut-of-date     :\x1b[0m", "Yes")
-	}
-}
-
-// RemoveMakeDeps receives a make dependency list and removes those
-// that are no longer necessary.
-func RemoveMakeDeps(depS []string) (err error) {
-	hanging := pacman.SliceHangingPackages(depS)
-
-	if len(hanging) != 0 {
-		if !config.ContinueTask("Confirm Removal?", "nN") {
-			return nil
-		}
-		err = pacman.CleanRemove(hanging)
-	}
-
-	return
-}

+ 60 - 0
clean.go

@@ -0,0 +1,60 @@
+package main
+
+// GetPkgbuild gets the pkgbuild of the package 'pkg' trying the ABS first and then the AUR trying the ABS first and then the AUR.
+
+// RemoveMakeDeps receives a make dependency list and removes those
+// that are no longer necessary.
+func removeMakeDeps(depS []string) (err error) {
+	hanging := sliceHangingPackages(depS)
+
+	if len(hanging) != 0 {
+		if !continueTask("Confirm Removal?", "nN") {
+			return nil
+		}
+		err = cleanRemove(hanging)
+	}
+
+	return
+}
+
+// RemovePackage removes package from VCS information
+func removeVCSPackage(pkgs []string) {
+	for _, pkgName := range pkgs {
+		for i, e := range savedInfo {
+			if e.Package == pkgName {
+				savedInfo[i] = savedInfo[len(savedInfo)-1]
+				savedInfo = savedInfo[:len(savedInfo)-1]
+			}
+		}
+	}
+
+	_ = saveVCSInfo()
+	return
+}
+
+// CleanDependencies removels all dangling dependencies in system
+func cleanDependencies(pkgs []string) error {
+	hanging, err := hangingPackages()
+	if err != nil {
+		return err
+	}
+
+	if len(hanging) != 0 {
+		if !continueTask("Confirm Removal?", "nN") {
+			return nil
+		}
+		err = cleanRemove(hanging)
+	}
+
+	return err
+}
+
+// CleanRemove sends a full removal command to pacman with the pkgName slice
+func cleanRemove(pkgName []string) (err error) {
+	if len(pkgName) == 0 {
+		return nil
+	}
+
+	err = passToPacman("-Rsnc", pkgName, []string{"--noconfirm"})
+	return err
+}

+ 115 - 51
yay.go

@@ -2,17 +2,13 @@ package main
 
 import (
 	"bufio"
+	"encoding/json"
 	"fmt"
 	"io"
 	"os"
 	"strconv"
 	"strings"
 	"time"
-
-	"github.com/jguer/yay/aur"
-	vcs "github.com/jguer/yay/aur/vcs"
-	"github.com/jguer/yay/config"
-	pac "github.com/jguer/yay/pacman"
 )
 
 func usage() {
@@ -42,7 +38,61 @@ func usage() {
 `)
 }
 
-var version = "2.116"
+func init() {
+	defaultSettings(&config)
+
+	var err error
+	configfile := os.Getenv("HOME") + "/.config/yay/config.json"
+
+	if _, err = os.Stat(configfile); os.IsNotExist(err) {
+		_ = os.MkdirAll(os.Getenv("HOME")+"/.config/yay", 0755)
+		// Save the default config if nothing is found
+		config.saveConfig()
+	} else {
+		file, err := os.Open(configfile)
+		if err != nil {
+			fmt.Println("Error reading config:", err)
+		} else {
+			decoder := json.NewDecoder(file)
+			err = decoder.Decode(&config)
+			if err != nil {
+				fmt.Println("Loading default Settings\nError reading config:", err)
+				defaultSettings(&config)
+			}
+		}
+	}
+
+	AlpmConf, err = readAlpmConfig(config.PacmanConf)
+	if err != nil {
+		fmt.Println("Unable to read Pacman conf", err)
+		os.Exit(1)
+	}
+
+	AlpmHandle, err = AlpmConf.CreateHandle()
+	if err != nil {
+		fmt.Println("Unable to CreateHandle", err)
+		os.Exit(1)
+	}
+
+	updated = false
+	configfile = os.Getenv("HOME") + "/.config/yay/yay_vcs.json"
+
+	if _, err := os.Stat(configfile); os.IsNotExist(err) {
+		_ = os.MkdirAll(os.Getenv("HOME")+"/.config/yay", 0755)
+		return
+	}
+
+	file, err := os.Open(configfile)
+	if err != nil {
+		fmt.Println("error:", err)
+		return
+	}
+	decoder := json.NewDecoder(file)
+	err = decoder.Decode(&savedInfo)
+	if err != nil {
+		fmt.Println("error:", err)
+	}
+}
 
 func parser() (op string, options []string, packages []string, changedConfig bool, err error) {
 	if len(os.Args) < 2 {
@@ -65,41 +115,44 @@ func parser() (op string, options []string, packages []string, changedConfig boo
 			changedConfig = true
 			switch arg {
 			case "--printconfig":
-				fmt.Printf("%+v", config.YayConf)
+				fmt.Printf("%+v", config)
 				os.Exit(0)
 			case "--gendb":
-				err = aur.CreateDevelDB()
+				err = createDevelDB()
 				if err != nil {
 					fmt.Println(err)
 				}
-				err = vcs.SaveBranchInfo()
+				err = saveVCSInfo()
 				if err != nil {
 					fmt.Println(err)
 				}
 				os.Exit(0)
 			case "--devel":
-				config.YayConf.Devel = true
+				config.Devel = true
 			case "--nodevel":
-				config.YayConf.Devel = false
+				config.Devel = false
 			case "--timeupdate":
-				config.YayConf.TimeUpdate = true
+				config.TimeUpdate = true
 			case "--notimeupdate":
-				config.YayConf.TimeUpdate = false
+				config.TimeUpdate = false
 			case "--topdown":
-				config.YayConf.SortMode = config.TopDown
+				config.SortMode = TopDown
 			case "--complete":
-				config.YayConf.Shell = "sh"
+				config.Shell = "sh"
 				_ = complete()
 				os.Exit(0)
 			case "--fcomplete":
-				config.YayConf.Shell = "fish"
+				config.Shell = "fish"
 				_ = complete()
 				os.Exit(0)
 			case "--help":
 				usage()
 				os.Exit(0)
+			case "--version":
+				fmt.Printf("yay v%s\n", version)
+				os.Exit(0)
 			case "--noconfirm":
-				config.YayConf.NoConfirm = true
+				config.NoConfirm = true
 				fallthrough
 			default:
 				options = append(options, arg)
@@ -132,9 +185,9 @@ func main() {
 		err = localStatistics(version)
 	case "-Ss", "-Ssq", "-Sqs":
 		if op == "-Ss" {
-			config.YayConf.SearchMode = config.Detailed
+			config.SearchMode = Detailed
 		} else {
-			config.YayConf.SearchMode = config.Minimal
+			config.SearchMode = Minimal
 		}
 
 		if pkgs != nil {
@@ -142,41 +195,52 @@ func main() {
 		}
 	case "-S":
 		err = install(pkgs, options)
-	case "-Syu", "-Suy":
-		err = upgrade(options)
+	case "-Sy":
+		err = passToPacman("-Sy", nil, nil)
+		if err != nil {
+			break
+		}
+		err = install(pkgs, options)
+	case "-Syu", "-Suy", "-Su":
+		if strings.Contains(op, "y") {
+			err = passToPacman("-Sy", nil, nil)
+			if err != nil {
+				break
+			}
+		}
+		err = upgradePkgs(options)
 	case "-Si":
 		err = syncInfo(pkgs, options)
 	case "yogurt":
-		config.YayConf.SearchMode = config.NumberMenu
+		config.SearchMode = NumberMenu
 
 		if pkgs != nil {
 			err = numberMenu(pkgs, options)
 		}
 	default:
 		if op[0] == 'R' {
-			vcs.RemovePackage(pkgs)
+			removeVCSPackage(pkgs)
 		}
-		err = config.PassToPacman(op, pkgs, options)
+		err = passToPacman(op, pkgs, options)
 	}
 
 	var erra error
-	if vcs.Updated {
-		erra = vcs.SaveBranchInfo()
+	if updated {
+		erra = saveVCSInfo()
 		if erra != nil {
 			fmt.Println(err)
 		}
-
 	}
 
 	if changedConfig {
-		erra = config.SaveConfig()
+		erra = config.saveConfig()
 		if erra != nil {
 			fmt.Println(err)
 		}
 
 	}
 
-	erra = config.AlpmHandle.Release()
+	erra = AlpmHandle.Release()
 	if erra != nil {
 		fmt.Println(err)
 	}
@@ -191,12 +255,12 @@ func main() {
 func numberMenu(pkgS []string, flags []string) (err error) {
 	var num int
 
-	aq, err := aur.NarrowSearch(pkgS, true)
+	aq, err := narrowSearch(pkgS, true)
 	if err != nil {
 		fmt.Println("Error during AUR search:", err)
 	}
 	numaq := len(aq)
-	pq, numpq, err := pac.Search(pkgS)
+	pq, numpq, err := queryRepo(pkgS)
 	if err != nil {
 		return
 	}
@@ -205,12 +269,12 @@ func numberMenu(pkgS []string, flags []string) (err error) {
 		return fmt.Errorf("no packages match search")
 	}
 
-	if config.YayConf.SortMode == config.BottomUp {
-		printAURSearch(aq, numpq)
-		pq.PrintSearch()
+	if config.SortMode == BottomUp {
+		aq.printSearch(numpq)
+		pq.printSearch()
 	} else {
-		pq.PrintSearch()
-		printAURSearch(aq, numpq)
+		pq.printSearch()
+		aq.printSearch(numpq)
 	}
 
 	fmt.Printf("\x1b[32m%s\x1b[0m\nNumbers: ", "Type numbers to install. Separate each number with a space.")
@@ -222,8 +286,8 @@ func numberMenu(pkgS []string, flags []string) (err error) {
 	}
 
 	numberString := string(numberBuf)
-	var aurInstall []string
-	var repoInstall []string
+	var aurI []string
+	var repoI []string
 	result := strings.Fields(numberString)
 	for _, numS := range result {
 		num, err = strconv.Atoi(numS)
@@ -235,26 +299,26 @@ func numberMenu(pkgS []string, flags []string) (err error) {
 		if num > numaq+numpq-1 || num < 0 {
 			continue
 		} else if num > numpq-1 {
-			if config.YayConf.SortMode == config.BottomUp {
-				aurInstall = append(aurInstall, aq[numaq+numpq-num-1].Name)
+			if config.SortMode == BottomUp {
+				aurI = append(aurI, aq[numaq+numpq-num-1].Name)
 			} else {
-				aurInstall = append(aurInstall, aq[num-numpq].Name)
+				aurI = append(aurI, aq[num-numpq].Name)
 			}
 		} else {
-			if config.YayConf.SortMode == config.BottomUp {
-				repoInstall = append(repoInstall, pq[numpq-num-1].Name())
+			if config.SortMode == BottomUp {
+				repoI = append(repoI, pq[numpq-num-1].Name())
 			} else {
-				repoInstall = append(repoInstall, pq[num].Name())
+				repoI = append(repoI, pq[num].Name())
 			}
 		}
 	}
 
-	if len(repoInstall) != 0 {
-		err = config.PassToPacman("-S", repoInstall, flags)
+	if len(repoI) != 0 {
+		err = passToPacman("-S", repoI, flags)
 	}
 
-	if len(aurInstall) != 0 {
-		err = aur.Install(aurInstall, flags)
+	if len(aurI) != 0 {
+		err = aurInstall(aurI, flags)
 	}
 
 	return err
@@ -262,7 +326,7 @@ func numberMenu(pkgS []string, flags []string) (err error) {
 
 // Complete provides completion info for shells
 func complete() (err error) {
-	path := os.Getenv("HOME") + "/.cache/yay/aur_" + config.YayConf.Shell + ".cache"
+	path := os.Getenv("HOME") + "/.cache/yay/aur_" + config.Shell + ".cache"
 
 	if info, err := os.Stat(path); os.IsNotExist(err) || time.Since(info.ModTime()).Hours() > 48 {
 		os.MkdirAll(os.Getenv("HOME")+"/.cache/yay/", 0755)
@@ -272,10 +336,10 @@ func complete() (err error) {
 			return err
 		}
 
-		if aur.CreateAURList(out) != nil {
+		if createAURList(out) != nil {
 			defer os.Remove(path)
 		}
-		err = pac.CreatePackageList(out)
+		err = createRepoList(out)
 
 		out.Close()
 		return err

+ 61 - 0
completions.go

@@ -0,0 +1,61 @@
+package main
+
+import (
+	"bufio"
+	"fmt"
+	"net/http"
+	"os"
+
+	alpm "github.com/jguer/go-alpm"
+)
+
+//CreateAURList creates a new completion file
+func createAURList(out *os.File) (err error) {
+	resp, err := http.Get("https://aur.archlinux.org/packages.gz")
+	if err != nil {
+		return err
+	}
+	defer resp.Body.Close()
+
+	scanner := bufio.NewScanner(resp.Body)
+
+	scanner.Scan()
+	for scanner.Scan() {
+		fmt.Print(scanner.Text())
+		out.WriteString(scanner.Text())
+		if config.Shell == "fish" {
+			fmt.Print("\tAUR\n")
+			out.WriteString("\tAUR\n")
+		} else {
+			fmt.Print("\n")
+			out.WriteString("\n")
+		}
+	}
+
+	return nil
+}
+
+//CreatePackageList appends Repo packages to completion cache
+func createRepoList(out *os.File) (err error) {
+	dbList, err := AlpmHandle.SyncDbs()
+	if err != nil {
+		return
+	}
+
+	_ = dbList.ForEach(func(db alpm.Db) error {
+		_ = db.PkgCache().ForEach(func(pkg alpm.Package) error {
+			fmt.Print(pkg.Name())
+			out.WriteString(pkg.Name())
+			if config.Shell == "fish" {
+				fmt.Print("\t" + pkg.DB().Name() + "\n")
+				out.WriteString("\t" + pkg.DB().Name() + "\n")
+			} else {
+				fmt.Print("\n")
+				out.WriteString("\n")
+			}
+			return nil
+		})
+		return nil
+	})
+	return nil
+}

+ 27 - 117
config/config.go

@@ -1,10 +1,8 @@
-package config
+package main
 
 import (
 	"encoding/json"
 	"fmt"
-	"io"
-	"net/http"
 	"os"
 	"os/exec"
 	"os/user"
@@ -43,51 +41,28 @@ type Configuration struct {
 	TimeUpdate    bool   `json:"timeupdate"`
 }
 
-// YayConf holds the current config values for yay.
-var YayConf Configuration
+var version = "2.116"
 
-// AlpmConf holds the current config values for pacman.
-var AlpmConf alpm.PacmanConfig
+// baseURL givers the AUR default address.
+const baseURL string = "https://aur.archlinux.org"
 
-// AlpmHandle is the alpm handle used by yay.
-var AlpmHandle *alpm.Handle
+var specialDBsauce = false
 
-func init() {
-	defaultSettings(&YayConf)
+var savedInfo infos
 
-	var err error
-	configfile := os.Getenv("HOME") + "/.config/yay/config.json"
+var configfile string
 
-	if _, err = os.Stat(configfile); os.IsNotExist(err) {
-		_ = os.MkdirAll(os.Getenv("HOME")+"/.config/yay", 0755)
-		// Save the default config if nothing is found
-		SaveConfig()
-	} else {
-		file, err := os.Open(configfile)
-		if err != nil {
-			fmt.Println("Error reading config:", err)
-		} else {
-			decoder := json.NewDecoder(file)
-			err = decoder.Decode(&YayConf)
-			if err != nil {
-				fmt.Println("Loading default Settings\nError reading config:", err)
-				defaultSettings(&YayConf)
-			}
-		}
-	}
+// Updated returns if database has been updated
+var updated bool
 
-	AlpmConf, err = readAlpmConfig(YayConf.PacmanConf)
-	if err != nil {
-		fmt.Println("Unable to read Pacman conf", err)
-		os.Exit(1)
-	}
+// YayConf holds the current config values for yay.
+var config Configuration
 
-	AlpmHandle, err = AlpmConf.CreateHandle()
-	if err != nil {
-		fmt.Println("Unable to CreateHandle", err)
-		os.Exit(1)
-	}
-}
+// AlpmConf holds the current config values for pacman.
+var AlpmConf alpm.PacmanConfig
+
+// AlpmHandle is the alpm handle used by yay.
+var AlpmHandle *alpm.Handle
 
 func readAlpmConfig(pacmanconf string) (conf alpm.PacmanConfig, err error) {
 	file, err := os.Open(pacmanconf)
@@ -102,10 +77,10 @@ func readAlpmConfig(pacmanconf string) (conf alpm.PacmanConfig, err error) {
 }
 
 // SaveConfig writes yay config to file.
-func SaveConfig() error {
-	YayConf.NoConfirm = false
+func (config *Configuration) saveConfig() error {
+	config.NoConfirm = false
 	configfile := os.Getenv("HOME") + "/.config/yay/config.json"
-	marshalledinfo, _ := json.MarshalIndent(YayConf, "", "\t")
+	marshalledinfo, _ := json.MarshalIndent(config, "", "\t")
 	in, err := os.OpenFile(configfile, os.O_RDWR|os.O_CREATE, 0755)
 	if err != nil {
 		return err
@@ -138,10 +113,10 @@ func defaultSettings(config *Configuration) {
 }
 
 // Editor returns the preferred system editor.
-func Editor() string {
+func editor() string {
 	switch {
-	case YayConf.Editor != "":
-		editor, err := exec.LookPath(YayConf.Editor)
+	case config.Editor != "":
+		editor, err := exec.LookPath(config.Editor)
 		if err != nil {
 			fmt.Println(err)
 		} else {
@@ -187,8 +162,8 @@ func Editor() string {
 
 // ContinueTask prompts if user wants to continue task.
 //If NoConfirm is set the action will continue without user input.
-func ContinueTask(s string, def string) (cont bool) {
-	if YayConf.NoConfirm {
+func continueTask(s string, def string) (cont bool) {
+	if config.NoConfirm {
 		return true
 	}
 	var postFix string
@@ -214,60 +189,8 @@ func ContinueTask(s string, def string) (cont bool) {
 	return true
 }
 
-func downloadFile(path string, url string) (err error) {
-	// Create the file
-	out, err := os.Create(path)
-	if err != nil {
-		return err
-	}
-	defer out.Close()
-
-	// Get the data
-	resp, err := http.Get(url)
-	if err != nil {
-		return err
-	}
-	defer resp.Body.Close()
-
-	// Writer the body to file
-	_, err = io.Copy(out, resp.Body)
-	return err
-}
-
-// DownloadAndUnpack downloads url tgz and extracts to path.
-func DownloadAndUnpack(url string, path string, trim bool) (err error) {
-	err = os.MkdirAll(path, 0755)
-	if err != nil {
-		return
-	}
-
-	tokens := strings.Split(url, "/")
-	fileName := tokens[len(tokens)-1]
-
-	tarLocation := path + fileName
-	defer os.Remove(tarLocation)
-
-	err = downloadFile(tarLocation, url)
-	if err != nil {
-		return
-	}
-
-	if trim {
-		err = exec.Command("/bin/sh", "-c",
-			YayConf.TarBin+" --strip-components 2 --include='*/"+fileName[:len(fileName)-7]+"/trunk/' -xf "+tarLocation+" -C "+path).Run()
-		os.Rename(path+"trunk", path+fileName[:len(fileName)-7]) // kurwa
-	} else {
-		err = exec.Command(YayConf.TarBin, "-xf", tarLocation, "-C", path).Run()
-	}
-	if err != nil {
-		return
-	}
-
-	return
-}
-
 // PassToPacman outsorces execution to pacman binary without modifications.
-func PassToPacman(op string, pkgs []string, flags []string) error {
+func passToPacman(op string, pkgs []string, flags []string) error {
 	var cmd *exec.Cmd
 	var args []string
 
@@ -281,9 +204,9 @@ func PassToPacman(op string, pkgs []string, flags []string) error {
 	}
 
 	if strings.Contains(op, "-Q") || op == "Si" {
-		cmd = exec.Command(YayConf.PacmanBin, args...)
+		cmd = exec.Command(config.PacmanBin, args...)
 	} else {
-		args = append([]string{YayConf.PacmanBin}, args...)
+		args = append([]string{config.PacmanBin}, args...)
 		cmd = exec.Command("sudo", args...)
 	}
 
@@ -291,16 +214,3 @@ func PassToPacman(op string, pkgs []string, flags []string) error {
 	err := cmd.Run()
 	return err
 }
-
-// Human returns results in Human readable format.
-func Human(size int64) string {
-	floatsize := float32(size)
-	units := [...]string{"", "Ki", "Mi", "Gi", "Ti", "Pi", "Ei", "Zi", "Yi"}
-	for _, unit := range units {
-		if floatsize < 1024 {
-			return fmt.Sprintf("%.1f %sB", floatsize, unit)
-		}
-		floatsize /= 1024
-	}
-	return fmt.Sprintf("%d%s", size, "B")
-}

+ 119 - 0
dependencies.go

@@ -0,0 +1,119 @@
+package main
+
+import (
+	"fmt"
+	"strings"
+
+	rpc "github.com/mikkeloscar/aur"
+)
+
+// BuildDependencies finds packages, on the second run
+// compares with a baselist and avoids searching those
+func buildDependencies(baselist []string) func(toCheck []string, isBaseList bool, last bool) (repo []string, notFound []string) {
+	localDb, err := AlpmHandle.LocalDb()
+	if err != nil {
+		panic(err)
+	}
+
+	dbList, err := AlpmHandle.SyncDbs()
+	if err != nil {
+		panic(err)
+	}
+
+	f := func(c rune) bool {
+		return c == '>' || c == '<' || c == '=' || c == ' '
+	}
+
+	return func(toCheck []string, isBaseList bool, close bool) (repo []string, notFound []string) {
+		if close {
+			return
+		}
+
+	Loop:
+		for _, dep := range toCheck {
+			if !isBaseList {
+				for _, base := range baselist {
+					if base == dep {
+						continue Loop
+					}
+				}
+			}
+			if _, erp := localDb.PkgCache().FindSatisfier(dep); erp == nil {
+				continue
+			} else if pkg, erp := dbList.FindSatisfier(dep); erp == nil {
+				repo = append(repo, pkg.Name())
+			} else {
+				field := strings.FieldsFunc(dep, f)
+				notFound = append(notFound, field[0])
+			}
+		}
+		return
+	}
+}
+
+// DepSatisfier receives a string slice, returns a slice of packages found in
+// repos and one of packages not found in repos. Leaves out installed packages.
+func depSatisfier(toCheck []string) (repo []string, notFound []string, err error) {
+	localDb, err := AlpmHandle.LocalDb()
+	if err != nil {
+		return
+	}
+	dbList, err := AlpmHandle.SyncDbs()
+	if err != nil {
+		return
+	}
+
+	f := func(c rune) bool {
+		return c == '>' || c == '<' || c == '=' || c == ' '
+	}
+
+	for _, dep := range toCheck {
+		if _, erp := localDb.PkgCache().FindSatisfier(dep); erp == nil {
+			continue
+		} else if pkg, erp := dbList.FindSatisfier(dep); erp == nil {
+			repo = append(repo, pkg.Name())
+		} else {
+			field := strings.FieldsFunc(dep, f)
+			notFound = append(notFound, field[0])
+		}
+	}
+
+	err = nil
+	return
+}
+
+// PkgDependencies returns package dependencies not installed belonging to AUR
+// 0 is Repo, 1 is Foreign.
+func pkgDependencies(a *rpc.Pkg) (runDeps [2][]string, makeDeps [2][]string, err error) {
+	var q aurQuery
+	if len(a.Depends) == 0 && len(a.MakeDepends) == 0 {
+		q, err = rpc.Info([]string{a.Name})
+		if len(q) == 0 || err != nil {
+			err = fmt.Errorf("Unable to search dependencies, %s", err)
+			return
+		}
+	} else {
+		q = append(q, *a)
+	}
+
+	depSearch := buildDependencies(a.Depends)
+	if len(a.Depends) != 0 {
+		runDeps[0], runDeps[1] = depSearch(q[0].Depends, true, false)
+		if len(runDeps[0]) != 0 || len(runDeps[1]) != 0 {
+			fmt.Println("\x1b[1;32m=>\x1b[1;33m Run Dependencies: \x1b[0m")
+			printDeps(runDeps[0], runDeps[1])
+		}
+	}
+
+	if len(a.MakeDepends) != 0 {
+		makeDeps[0], makeDeps[1] = depSearch(q[0].MakeDepends, false, false)
+		if len(makeDeps[0]) != 0 || len(makeDeps[1]) != 0 {
+			fmt.Println("\x1b[1;32m=>\x1b[1;33m Make Dependencies: \x1b[0m")
+			printDeps(makeDeps[0], makeDeps[1])
+		}
+	}
+	depSearch(a.MakeDepends, false, true)
+
+	err = nil
+	return
+}

+ 122 - 0
download.go

@@ -0,0 +1,122 @@
+package main
+
+import (
+	"fmt"
+	"io"
+	"net/http"
+	"os"
+	"os/exec"
+	"strings"
+
+	rpc "github.com/mikkeloscar/aur"
+)
+
+func downloadFile(path string, url string) (err error) {
+	// Create the file
+	out, err := os.Create(path)
+	if err != nil {
+		return err
+	}
+	defer out.Close()
+
+	// Get the data
+	resp, err := http.Get(url)
+	if err != nil {
+		return err
+	}
+	defer resp.Body.Close()
+
+	// Writer the body to file
+	_, err = io.Copy(out, resp.Body)
+	return err
+}
+
+// DownloadAndUnpack downloads url tgz and extracts to path.
+func downloadAndUnpack(url string, path string, trim bool) (err error) {
+	err = os.MkdirAll(path, 0755)
+	if err != nil {
+		return
+	}
+
+	tokens := strings.Split(url, "/")
+	fileName := tokens[len(tokens)-1]
+
+	tarLocation := path + fileName
+	defer os.Remove(tarLocation)
+
+	err = downloadFile(tarLocation, url)
+	if err != nil {
+		return
+	}
+
+	if trim {
+		err = exec.Command("/bin/sh", "-c",
+			config.TarBin+" --strip-components 2 --include='*/"+fileName[:len(fileName)-7]+"/trunk/' -xf "+tarLocation+" -C "+path).Run()
+		os.Rename(path+"trunk", path+fileName[:len(fileName)-7]) // kurwa
+	} else {
+		err = exec.Command(config.TarBin, "-xf", tarLocation, "-C", path).Run()
+	}
+	if err != nil {
+		return
+	}
+
+	return
+}
+
+func getPkgbuild(pkg string) (err error) {
+	wd, err := os.Getwd()
+	if err != nil {
+		return
+	}
+	wd = wd + "/"
+
+	err = getPkgbuildfromABS(pkg, wd)
+	if err == nil {
+		return
+	}
+
+	err = getPkgbuildfromAUR(pkg, wd)
+	return
+}
+
+// GetPkgbuild downloads pkgbuild from the ABS.
+func getPkgbuildfromABS(pkgN string, path string) (err error) {
+	dbList, err := AlpmHandle.SyncDbs()
+	if err != nil {
+		return
+	}
+
+	for _, db := range dbList.Slice() {
+		pkg, err := db.PkgByName(pkgN)
+		if err == nil {
+			var url string
+			if db.Name() == "core" || db.Name() == "extra" {
+				url = "https://projects.archlinux.org/svntogit/packages.git/snapshot/packages/" + pkg.Name() + ".tar.gz"
+			} else if db.Name() == "community" {
+				url = "https://projects.archlinux.org/svntogit/community.git/snapshot/community-packages/" + pkg.Name() + ".tar.gz"
+			} else {
+				return fmt.Errorf("Not in standard repositories")
+			}
+			fmt.Printf("\x1b[1;32m==>\x1b[1;33m %s \x1b[1;32mfound in ABS.\x1b[0m\n", pkgN)
+			errD := downloadAndUnpack(url, path, true)
+			return errD
+		}
+	}
+	return fmt.Errorf("package not found")
+}
+
+// GetPkgbuild downloads pkgbuild from the AUR.
+func getPkgbuildfromAUR(pkgN string, dir string) (err error) {
+	aq, err := rpc.Info([]string{pkgN})
+	if err != nil {
+		return err
+	}
+
+	if len(aq) == 0 {
+		return fmt.Errorf("no results")
+	}
+
+	fmt.Printf("\x1b[1;32m==>\x1b[1;33m %s \x1b[1;32mfound in AUR.\x1b[0m\n", pkgN)
+	downloadAndUnpack(baseURL+aq[0].URLPath, dir, false)
+	return
+}

+ 190 - 0
install.go

@@ -0,0 +1,190 @@
+package main
+
+import (
+	"fmt"
+	"os"
+	"os/exec"
+
+	rpc "github.com/mikkeloscar/aur"
+	gopkg "github.com/mikkeloscar/gopkgbuild"
+)
+
+func newInstall(pkgs []string, flags []string) error {
+	aurs, repos, _ := packageSlices(pkgs)
+
+	if len(repos) != 0 {
+		err := passToPacman("-S", repos, flags)
+		if err != nil {
+			fmt.Println("Error installing repo packages.")
+		}
+	}
+
+	if len(aurs) != 0 {
+		err := aurInstall(aurs, flags)
+		if err != nil {
+			fmt.Println("Error installing aur packages.")
+		}
+	}
+	return nil
+
+}
+
+// Install handles package installs
+func install(pkgs []string, flags []string) error {
+	aurs, repos, _ := packageSlices(pkgs)
+
+	if len(repos) != 0 {
+		err := passToPacman("-S", repos, flags)
+		if err != nil {
+			fmt.Println("Error installing repo packages.")
+		}
+	}
+
+	if len(aurs) != 0 {
+		err := aurInstall(aurs, flags)
+		if err != nil {
+			fmt.Println("Error installing aur packages.")
+		}
+	}
+	return nil
+}
+
+// Install sends system commands to make and install a package from pkgName
+func aurInstall(pkgName []string, flags []string) (err error) {
+	q, err := rpc.Info(pkgName)
+	if err != nil {
+		return
+	}
+
+	if len(q) != len(pkgName) {
+		fmt.Printf("Some package from list\n%+v\ndoes not exist", pkgName)
+	}
+
+	var finalrm []string
+	for _, i := range q {
+		mrm, err := PkgInstall(&i, flags)
+		if err != nil {
+			fmt.Println("Error installing", i.Name, ":", err)
+		}
+		finalrm = append(finalrm, mrm...)
+	}
+
+	if len(finalrm) != 0 {
+		err = removeMakeDeps(finalrm)
+	}
+
+	return err
+}
+
+func setupPackageSpace(a *rpc.Pkg) (dir string, pkgbuild *gopkg.PKGBUILD, err error) {
+	dir = config.BuildDir + a.PackageBase + "/"
+
+	if _, err = os.Stat(dir); !os.IsNotExist(err) {
+		if !continueTask("Directory exists. Clean Build?", "yY") {
+			_ = os.RemoveAll(config.BuildDir + a.PackageBase)
+		}
+	}
+
+	if err = downloadAndUnpack(baseURL+a.URLPath, config.BuildDir, false); err != nil {
+		return
+	}
+
+	if !continueTask("Edit PKGBUILD?", "yY") {
+		editcmd := exec.Command(editor(), dir+"PKGBUILD")
+		editcmd.Stdin, editcmd.Stdout, editcmd.Stderr = os.Stdin, os.Stdout, os.Stderr
+		editcmd.Run()
+	}
+
+	pkgbuild, err = gopkg.ParseSRCINFO(dir + ".SRCINFO")
+	if err == nil {
+		for _, pkgsource := range pkgbuild.Source {
+			owner, repo := parseSource(pkgsource)
+			if owner != "" && repo != "" {
+				err = branchInfo(a.Name, owner, repo)
+				if err != nil {
+					fmt.Println(err)
+				}
+			}
+		}
+	}
+
+	return
+}
+
+// PkgInstall handles install from Info Result.
+func PkgInstall(a *rpc.Pkg, flags []string) (finalmdeps []string, err error) {
+	fmt.Printf("\x1b[1;32m==> Installing\x1b[33m %s\x1b[0m\n", a.Name)
+	if a.Maintainer == "" {
+		fmt.Println("\x1b[1;31;40m==> Warning:\x1b[0;;40m This package is orphaned.\x1b[0m")
+	}
+
+	dir, _, err := setupPackageSpace(a)
+	if err != nil {
+		return
+	}
+
+	if specialDBsauce {
+		return
+	}
+
+	runDeps, makeDeps, err := pkgDependencies(a)
+	if err != nil {
+		return
+	}
+
+	repoDeps := append(runDeps[0], makeDeps[0]...)
+	aurDeps := append(runDeps[1], makeDeps[1]...)
+	finalmdeps = append(finalmdeps, makeDeps[0]...)
+	finalmdeps = append(finalmdeps, makeDeps[1]...)
+
+	if len(aurDeps) != 0 || len(repoDeps) != 0 {
+		if !continueTask("Continue?", "nN") {
+			return finalmdeps, fmt.Errorf("user did not like the dependencies")
+		}
+	}
+
+	aurQ, _ := rpc.Info(aurDeps)
+	if len(aurQ) != len(aurDeps) {
+		(aurQuery)(aurQ).missingPackage(aurDeps)
+		if !continueTask("Continue?", "nN") {
+			return finalmdeps, fmt.Errorf("unable to install dependencies")
+		}
+	}
+
+	var depArgs []string
+	if config.NoConfirm {
+		depArgs = []string{"--asdeps", "--noconfirm"}
+	} else {
+		depArgs = []string{"--asdeps"}
+	}
+	// Repo dependencies
+	if len(repoDeps) != 0 {
+		errR := passToPacman("-S", repoDeps, depArgs)
+		if errR != nil {
+			return finalmdeps, errR
+		}
+	}
+
+	// Handle AUR dependencies
+	for _, dep := range aurQ {
+		finalmdepsR, errA := PkgInstall(&dep, depArgs)
+		finalmdeps = append(finalmdeps, finalmdepsR...)
+
+		if errA != nil {
+			cleanRemove(repoDeps)
+			cleanRemove(aurDeps)
+			return finalmdeps, errA
+		}
+	}
+
+	args := []string{"-sri"}
+	args = append(args, flags...)
+	makepkgcmd := exec.Command(config.MakepkgBin, args...)
+	makepkgcmd.Stdin, makepkgcmd.Stdout, makepkgcmd.Stderr = os.Stdin, os.Stdout, os.Stderr
+	makepkgcmd.Dir = dir
+	err = makepkgcmd.Run()
+	if err == nil {
+		_ = saveVCSInfo()
+	}
+	return
+}

+ 0 - 420
pacman/pacman.go

@@ -1,420 +0,0 @@
-package pacman
-
-import (
-	"fmt"
-	"os"
-	"strings"
-
-	"github.com/jguer/go-alpm"
-	"github.com/jguer/yay/config"
-)
-
-// Query holds the results of a repository search.
-type Query []alpm.Package
-
-// Search handles repo searches. Creates a RepoSearch struct.
-func Search(pkgInputN []string) (s Query, n int, err error) {
-	dbList, err := config.AlpmHandle.SyncDbs()
-	if err != nil {
-		return
-	}
-
-	// BottomUp functions
-	initL := func(len int) int {
-		if config.YayConf.SortMode == config.TopDown {
-			return 0
-		} else {
-			return len - 1
-		}
-	}
-	compL := func(len int, i int) bool {
-		if config.YayConf.SortMode == config.TopDown {
-			return i < len
-		} else {
-			return i > -1
-		}
-	}
-	finalL := func(i int) int {
-		if config.YayConf.SortMode == config.TopDown {
-			return i + 1
-		} else {
-			return i - 1
-		}
-	}
-
-	dbS := dbList.Slice()
-	lenDbs := len(dbS)
-	for f := initL(lenDbs); compL(lenDbs, f); f = finalL(f) {
-		pkgS := dbS[f].PkgCache().Slice()
-		lenPkgs := len(pkgS)
-		for i := initL(lenPkgs); compL(lenPkgs, i); i = finalL(i) {
-			match := true
-			for _, pkgN := range pkgInputN {
-				if !(strings.Contains(pkgS[i].Name(), pkgN) || strings.Contains(strings.ToLower(pkgS[i].Description()), pkgN)) {
-					match = false
-					break
-				}
-			}
-
-			if match {
-				n++
-				s = append(s, pkgS[i])
-			}
-		}
-	}
-	return
-}
-
-//PrintSearch receives a RepoSearch type and outputs pretty text.
-func (s Query) PrintSearch() {
-	for i, res := range s {
-		var toprint string
-		if config.YayConf.SearchMode == config.NumberMenu {
-			if config.YayConf.SortMode == config.BottomUp {
-				toprint += fmt.Sprintf("\x1b[33m%d\x1b[0m ", len(s)-i-1)
-			} else {
-				toprint += fmt.Sprintf("\x1b[33m%d\x1b[0m ", i)
-			}
-		} else if config.YayConf.SearchMode == config.Minimal {
-			fmt.Println(res.Name())
-			continue
-		}
-		toprint += fmt.Sprintf("\x1b[1m%s/\x1b[33m%s \x1b[36m%s \x1b[0m",
-			res.DB().Name(), res.Name(), res.Version())
-
-		if len(res.Groups().Slice()) != 0 {
-			toprint += fmt.Sprint(res.Groups().Slice(), " ")
-		}
-
-		localDb, err := config.AlpmHandle.LocalDb()
-		if err == nil {
-			if _, err = localDb.PkgByName(res.Name()); err == nil {
-				toprint += fmt.Sprintf("\x1b[32;40mInstalled\x1b[0m")
-			}
-		}
-
-		toprint += "\n    " + res.Description()
-		fmt.Println(toprint)
-	}
-}
-
-// PackageSlices separates an input slice into aur and repo slices
-func PackageSlices(toCheck []string) (aur []string, repo []string, err error) {
-	dbList, err := config.AlpmHandle.SyncDbs()
-	if err != nil {
-		return
-	}
-
-	for _, pkg := range toCheck {
-		found := false
-
-		_ = dbList.ForEach(func(db alpm.Db) error {
-			if found {
-				return nil
-			}
-
-			_, err = db.PkgByName(pkg)
-			if err == nil {
-				found = true
-				repo = append(repo, pkg)
-			}
-			return nil
-		})
-
-		if !found {
-			if _, errdb := dbList.PkgCachebyGroup(pkg); errdb == nil {
-				repo = append(repo, pkg)
-			} else {
-				aur = append(aur, pkg)
-			}
-		}
-	}
-
-	err = nil
-	return
-}
-
-// BuildDependencies finds packages, on the second run
-// compares with a baselist and avoids searching those
-func BuildDependencies(baselist []string) func(toCheck []string, isBaseList bool, last bool) (repo []string, notFound []string) {
-	localDb, _ := config.AlpmHandle.LocalDb()
-	dbList, _ := config.AlpmHandle.SyncDbs()
-
-	f := func(c rune) bool {
-		return c == '>' || c == '<' || c == '=' || c == ' '
-	}
-
-	return func(toCheck []string, isBaseList bool, close bool) (repo []string, notFound []string) {
-		if close {
-			return
-		}
-
-	Loop:
-		for _, dep := range toCheck {
-			if !isBaseList {
-				for _, base := range baselist {
-					if base == dep {
-						continue Loop
-					}
-				}
-			}
-			if _, erp := localDb.PkgCache().FindSatisfier(dep); erp == nil {
-				continue
-			} else if pkg, erp := dbList.FindSatisfier(dep); erp == nil {
-				repo = append(repo, pkg.Name())
-			} else {
-				field := strings.FieldsFunc(dep, f)
-				notFound = append(notFound, field[0])
-			}
-		}
-		return
-	}
-}
-
-// DepSatisfier receives a string slice, returns a slice of packages found in
-// repos and one of packages not found in repos. Leaves out installed packages.
-func DepSatisfier(toCheck []string) (repo []string, notFound []string, err error) {
-	localDb, err := config.AlpmHandle.LocalDb()
-	if err != nil {
-		return
-	}
-	dbList, err := config.AlpmHandle.SyncDbs()
-	if err != nil {
-		return
-	}
-
-	f := func(c rune) bool {
-		return c == '>' || c == '<' || c == '=' || c == ' '
-	}
-
-	for _, dep := range toCheck {
-		if _, erp := localDb.PkgCache().FindSatisfier(dep); erp == nil {
-			continue
-		} else if pkg, erp := dbList.FindSatisfier(dep); erp == nil {
-			repo = append(repo, pkg.Name())
-		} else {
-			field := strings.FieldsFunc(dep, f)
-			notFound = append(notFound, field[0])
-		}
-	}
-
-	err = nil
-	return
-}
-
-// PkgNameSlice returns a slice of package names
-// func (s Query) PkgNameSlice() (pkgNames []string) {
-// 	for _, e := range s {
-// 		pkgNames = append(pkgNames, e.Name())
-// 	}
-// 	return
-// }
-
-// CleanRemove sends a full removal command to pacman with the pkgName slice
-func CleanRemove(pkgName []string) (err error) {
-	if len(pkgName) == 0 {
-		return nil
-	}
-
-	err = config.PassToPacman("-Rsnc", pkgName, []string{"--noconfirm"})
-	return err
-}
-
-// ForeignPackages returns a map of foreign packages, with their version and date as values.
-func ForeignPackages() (foreign map[string]alpm.Package, err error) {
-	localDb, err := config.AlpmHandle.LocalDb()
-	if err != nil {
-		return
-	}
-	dbList, err := config.AlpmHandle.SyncDbs()
-	if err != nil {
-		return
-	}
-
-	foreign = make(map[string]alpm.Package)
-
-	f := func(k alpm.Package) error {
-		found := false
-		_ = dbList.ForEach(func(d alpm.Db) error {
-			if found {
-				return nil
-			}
-			_, err = d.PkgByName(k.Name())
-			if err == nil {
-				found = true
-			}
-			return nil
-		})
-
-		if !found {
-			foreign[k.Name()] = k
-		}
-		return nil
-	}
-
-	err = localDb.PkgCache().ForEach(f)
-	return
-}
-
-// Statistics returns statistics about packages installed in system
-func Statistics() (info struct {
-	Totaln    int
-	Expln     int
-	TotalSize int64
-}, err error) {
-	var tS int64 // TotalSize
-	var nPkg int
-	var ePkg int
-
-	localDb, err := config.AlpmHandle.LocalDb()
-	if err != nil {
-		return
-	}
-
-	for _, pkg := range localDb.PkgCache().Slice() {
-		tS += pkg.ISize()
-		nPkg++
-		if pkg.Reason() == 0 {
-			ePkg++
-		}
-	}
-
-	info = struct {
-		Totaln    int
-		Expln     int
-		TotalSize int64
-	}{
-		nPkg, ePkg, tS,
-	}
-
-	return
-}
-
-// BiggestPackages prints the name of the ten biggest packages in the system.
-func BiggestPackages() {
-
-	localDb, err := config.AlpmHandle.LocalDb()
-	if err != nil {
-		return
-	}
-
-	pkgCache := localDb.PkgCache()
-	pkgS := pkgCache.SortBySize().Slice()
-
-	if len(pkgS) < 10 {
-		return
-	}
-
-	for i := 0; i < 10; i++ {
-		fmt.Printf("%s: \x1B[0;33m%s\x1B[0m\n", pkgS[i].Name(), config.Human(pkgS[i].ISize()))
-	}
-	// Could implement size here as well, but we just want the general idea
-}
-
-// HangingPackages returns a list of packages installed as deps
-// and unneeded by the system
-func HangingPackages() (hanging []string, err error) {
-	localDb, err := config.AlpmHandle.LocalDb()
-	if err != nil {
-		return
-	}
-
-	f := func(pkg alpm.Package) error {
-		if pkg.Reason() != alpm.PkgReasonDepend {
-			return nil
-		}
-		requiredby := pkg.ComputeRequiredBy()
-		if len(requiredby) == 0 {
-			hanging = append(hanging, pkg.Name())
-			fmt.Printf("%s: \x1B[0;33m%s\x1B[0m\n", pkg.Name(), config.Human(pkg.ISize()))
-
-		}
-		return nil
-	}
-
-	err = localDb.PkgCache().ForEach(f)
-	return
-}
-
-// SliceHangingPackages returns a list of packages installed as deps
-// and unneeded by the system from a provided list of package names.
-func SliceHangingPackages(pkgS []string) (hanging []string) {
-	localDb, err := config.AlpmHandle.LocalDb()
-	if err != nil {
-		return
-	}
-
-big:
-	for _, pkgName := range pkgS {
-		for _, hangN := range hanging {
-			if hangN == pkgName {
-				continue big
-			}
-		}
-
-		pkg, err := localDb.PkgByName(pkgName)
-		if err == nil {
-			if pkg.Reason() != alpm.PkgReasonDepend {
-				continue
-			}
-
-			requiredby := pkg.ComputeRequiredBy()
-			if len(requiredby) == 0 {
-				hanging = append(hanging, pkgName)
-				fmt.Printf("%s: \x1B[0;33m%s\x1B[0m\n", pkg.Name(), config.Human(pkg.ISize()))
-			}
-		}
-	}
-	return
-}
-
-// GetPkgbuild downloads pkgbuild from the ABS.
-func GetPkgbuild(pkgN string, path string) (err error) {
-	dbList, err := config.AlpmHandle.SyncDbs()
-	if err != nil {
-		return
-	}
-
-	for _, db := range dbList.Slice() {
-		pkg, err := db.PkgByName(pkgN)
-		if err == nil {
-			var url string
-			if db.Name() == "core" || db.Name() == "extra" {
-				url = "https://projects.archlinux.org/svntogit/packages.git/snapshot/packages/" + pkg.Name() + ".tar.gz"
-			} else if db.Name() == "community" {
-				url = "https://projects.archlinux.org/svntogit/community.git/snapshot/community-packages/" + pkg.Name() + ".tar.gz"
-			} else {
-				return fmt.Errorf("Not in standard repositories")
-			}
-			fmt.Printf("\x1b[1;32m==>\x1b[1;33m %s \x1b[1;32mfound in ABS.\x1b[0m\n", pkgN)
-			errD := config.DownloadAndUnpack(url, path, true)
-			return errD
-		}
-	}
-	return fmt.Errorf("package not found")
-}
-
-//CreatePackageList appends Repo packages to completion cache
-func CreatePackageList(out *os.File) (err error) {
-	dbList, err := config.AlpmHandle.SyncDbs()
-	if err != nil {
-		return
-	}
-
-	_ = dbList.ForEach(func(db alpm.Db) error {
-		_ = db.PkgCache().ForEach(func(pkg alpm.Package) error {
-			fmt.Print(pkg.Name())
-			out.WriteString(pkg.Name())
-			if config.YayConf.Shell == "fish" {
-				fmt.Print("\t" + pkg.DB().Name() + "\n")
-				out.WriteString("\t" + pkg.DB().Name() + "\n")
-			} else {
-				fmt.Print("\n")
-				out.WriteString("\n")
-			}
-			return nil
-		})
-		return nil
-	})
-	return nil
-}

+ 0 - 62
pacman/pacman_test.go

@@ -1,62 +0,0 @@
-package pacman
-
-import (
-	"os"
-	"testing"
-
-	"github.com/jguer/yay/config"
-)
-
-func benchmarkPrintSearch(search string, b *testing.B) {
-	old := os.Stdout
-	_, w, _ := os.Pipe()
-	os.Stdout = w
-
-	for n := 0; n < b.N; n++ {
-		res, _, _ := Search(append([]string{}, search))
-		res.PrintSearch()
-	}
-	os.Stdout = old
-}
-
-func BenchmarkPrintSearchSimpleTopDown(b *testing.B) {
-	config.YayConf.SortMode = config.TopDown
-	benchmarkPrintSearch("chromium", b)
-}
-func BenchmarkPrintSearchComplexTopDown(b *testing.B) {
-	config.YayConf.SortMode = config.TopDown
-	benchmarkPrintSearch("linux", b)
-}
-
-func BenchmarkPrintSearchSimpleBottomUp(b *testing.B) {
-	config.YayConf.SortMode = config.BottomUp
-	benchmarkPrintSearch("chromium", b)
-}
-func BenchmarkPrintSearchComplexBottomUp(b *testing.B) {
-	config.YayConf.SortMode = config.BottomUp
-	benchmarkPrintSearch("linux", b)
-}
-
-func benchmarkSearch(search string, b *testing.B) {
-	for n := 0; n < b.N; n++ {
-		Search(append([]string{}, search))
-	}
-}
-func BenchmarkSearchSimpleTopDown(b *testing.B) {
-	config.YayConf.SortMode = config.TopDown
-	benchmarkSearch("chromium", b)
-}
-
-func BenchmarkSearchSimpleBottomUp(b *testing.B) {
-	config.YayConf.SortMode = config.BottomUp
-	benchmarkSearch("chromium", b)
-}
-
-func BenchmarkSearchComplexTopDown(b *testing.B) {
-	config.YayConf.SortMode = config.TopDown
-	benchmarkSearch("linux", b)
-}
-func BenchmarkSearchComplexBottomUp(b *testing.B) {
-	config.YayConf.SortMode = config.BottomUp
-	benchmarkSearch("linux", b)
-}

+ 183 - 0
print.go

@@ -0,0 +1,183 @@
+package main
+
+import (
+	"fmt"
+
+	rpc "github.com/mikkeloscar/aur"
+)
+
+// Human returns results in Human readable format.
+func human(size int64) string {
+	floatsize := float32(size)
+	units := [...]string{"", "Ki", "Mi", "Gi", "Ti", "Pi", "Ei", "Zi", "Yi"}
+	for _, unit := range units {
+		if floatsize < 1024 {
+			return fmt.Sprintf("%.1f %sB", floatsize, unit)
+		}
+		floatsize /= 1024
+	}
+	return fmt.Sprintf("%d%s", size, "B")
+}
+
+// PrintSearch handles printing search results in a given format
+func (q aurQuery) printSearch(start int) {
+	localDb, _ := AlpmHandle.LocalDb()
+
+	for i, res := range q {
+		var toprint string
+		if config.SearchMode == NumberMenu {
+			if config.SortMode == BottomUp {
+				toprint += fmt.Sprintf("\x1b[33m%d\x1b[0m ", len(q)+start-i-1)
+			} else {
+				toprint += fmt.Sprintf("\x1b[33m%d\x1b[0m ", start+i)
+			}
+		} else if config.SearchMode == Minimal {
+			fmt.Println(res.Name)
+			continue
+		}
+		toprint += fmt.Sprintf("\x1b[1m%s/\x1b[33m%s \x1b[36m%s \x1b[0m(%d) ", "aur", res.Name, res.Version, res.NumVotes)
+		if res.Maintainer == "" {
+			toprint += fmt.Sprintf("\x1b[31;40m(Orphaned)\x1b[0m ")
+		}
+
+		if res.OutOfDate != 0 {
+			toprint += fmt.Sprintf("\x1b[31;40m(Out-of-date)\x1b[0m ")
+		}
+
+		if _, err := localDb.PkgByName(res.Name); err == nil {
+			toprint += fmt.Sprintf("\x1b[32;40mInstalled\x1b[0m")
+		}
+		toprint += "\n    " + res.Description
+		fmt.Println(toprint)
+	}
+
+	return
+}
+
+//PrintSearch receives a RepoSearch type and outputs pretty text.
+func (s repoQuery) printSearch() {
+	for i, res := range s {
+		var toprint string
+		if config.SearchMode == NumberMenu {
+			if config.SortMode == BottomUp {
+				toprint += fmt.Sprintf("\x1b[33m%d\x1b[0m ", len(s)-i-1)
+			} else {
+				toprint += fmt.Sprintf("\x1b[33m%d\x1b[0m ", i)
+			}
+		} else if config.SearchMode == Minimal {
+			fmt.Println(res.Name())
+			continue
+		}
+		toprint += fmt.Sprintf("\x1b[1m%s/\x1b[33m%s \x1b[36m%s \x1b[0m",
+			res.DB().Name(), res.Name(), res.Version())
+
+		if len(res.Groups().Slice()) != 0 {
+			toprint += fmt.Sprint(res.Groups().Slice(), " ")
+		}
+
+		localDb, err := AlpmHandle.LocalDb()
+		if err == nil {
+			if _, err = localDb.PkgByName(res.Name()); err == nil {
+				toprint += fmt.Sprintf("\x1b[32;40mInstalled\x1b[0m")
+			}
+		}
+
+		toprint += "\n    " + res.Description()
+		fmt.Println(toprint)
+	}
+}
+
+func printDeps(repoDeps []string, aurDeps []string) {
+	if len(repoDeps) != 0 {
+		fmt.Print("\x1b[1;32m==> Repository dependencies: \x1b[0m")
+		for _, repoD := range repoDeps {
+			fmt.Print("\x1b[33m", repoD, " \x1b[0m")
+		}
+		fmt.Print("\n")
+
+	}
+	if len(aurDeps) != 0 {
+		fmt.Print("\x1b[1;32m==> AUR dependencies: \x1b[0m")
+		for _, aurD := range aurDeps {
+			fmt.Print("\x1b[33m", aurD, " \x1b[0m")
+		}
+		fmt.Print("\n")
+	}
+}
+
+// PrintInfo prints package info like pacman -Si.
+func PrintInfo(a *rpc.Pkg) {
+	fmt.Println("\x1b[1;37mRepository      :\x1b[0m", "aur")
+	fmt.Println("\x1b[1;37mName            :\x1b[0m", a.Name)
+	fmt.Println("\x1b[1;37mVersion         :\x1b[0m", a.Version)
+	fmt.Println("\x1b[1;37mDescription     :\x1b[0m", a.Description)
+	if a.URL != "" {
+		fmt.Println("\x1b[1;37mURL             :\x1b[0m", a.URL)
+	} else {
+		fmt.Println("\x1b[1;37mURL             :\x1b[0m", "None")
+	}
+	fmt.Println("\x1b[1;37mLicenses        :\x1b[0m", a.License)
+
+	// if len(a.Provides) != 0 {
+	// 	fmt.Println("\x1b[1;37mProvides        :\x1b[0m", a.Provides)
+	// } else {
+	// 	fmt.Println("\x1b[1;37mProvides        :\x1b[0m", "None")
+	// }
+
+	if len(a.Depends) != 0 {
+		fmt.Println("\x1b[1;37mDepends On      :\x1b[0m", a.Depends)
+	} else {
+		fmt.Println("\x1b[1;37mDepends On      :\x1b[0m", "None")
+	}
+
+	if len(a.MakeDepends) != 0 {
+		fmt.Println("\x1b[1;37mMake depends On :\x1b[0m", a.MakeDepends)
+	} else {
+		fmt.Println("\x1b[1;37mMake depends On :\x1b[0m", "None")
+	}
+
+	if len(a.OptDepends) != 0 {
+		fmt.Println("\x1b[1;37mOptional Deps   :\x1b[0m", a.OptDepends)
+	} else {
+		fmt.Println("\x1b[1;37mOptional Deps   :\x1b[0m", "None")
+	}
+
+	if len(a.Conflicts) != 0 {
+		fmt.Println("\x1b[1;37mConflicts With  :\x1b[0m", a.Conflicts)
+	} else {
+		fmt.Println("\x1b[1;37mConflicts With  :\x1b[0m", "None")
+	}
+
+	if a.Maintainer != "" {
+		fmt.Println("\x1b[1;37mMaintainer      :\x1b[0m", a.Maintainer)
+	} else {
+		fmt.Println("\x1b[1;37mMaintainer      :\x1b[0m", "None")
+	}
+	fmt.Println("\x1b[1;37mVotes           :\x1b[0m", a.NumVotes)
+	fmt.Println("\x1b[1;37mPopularity      :\x1b[0m", a.Popularity)
+
+	if a.OutOfDate != 0 {
+		fmt.Println("\x1b[1;37mOut-of-date     :\x1b[0m", "Yes")
+	}
+}
+
+// BiggestPackages prints the name of the ten biggest packages in the system.
+func biggestPackages() {
+
+	localDb, err := AlpmHandle.LocalDb()
+	if err != nil {
+		return
+	}
+
+	pkgCache := localDb.PkgCache()
+	pkgS := pkgCache.SortBySize().Slice()
+
+	if len(pkgS) < 10 {
+		return
+	}
+
+	for i := 0; i < 10; i++ {
+		fmt.Printf("%s: \x1B[0;33m%s\x1B[0m\n", pkgS[i].Name(), human(pkgS[i].ISize()))
+	}
+	// Could implement size here as well, but we just want the general idea
+}

+ 36 - 0
print_test.go

@@ -0,0 +1,36 @@
+package main
+
+import (
+	"os"
+	"testing"
+)
+
+func benchmarkPrintSearch(search string, b *testing.B) {
+	old := os.Stdout
+	_, w, _ := os.Pipe()
+	os.Stdout = w
+
+	for n := 0; n < b.N; n++ {
+		res, _, _ := queryRepo(append([]string{}, search))
+		res.printSearch()
+	}
+	os.Stdout = old
+}
+
+func BenchmarkPrintSearchSimpleTopDown(b *testing.B) {
+	config.SortMode = TopDown
+	benchmarkPrintSearch("chromium", b)
+}
+func BenchmarkPrintSearchComplexTopDown(b *testing.B) {
+	config.SortMode = TopDown
+	benchmarkPrintSearch("linux", b)
+}
+
+func BenchmarkPrintSearchSimpleBottomUp(b *testing.B) {
+	config.SortMode = BottomUp
+	benchmarkPrintSearch("chromium", b)
+}
+func BenchmarkPrintSearchComplexBottomUp(b *testing.B) {
+	config.SortMode = BottomUp
+	benchmarkPrintSearch("linux", b)
+}

+ 309 - 53
query.go

@@ -2,65 +2,151 @@ package main
 
 import (
 	"fmt"
+	"sort"
+	"strings"
 
-	"github.com/jguer/yay/aur"
-	"github.com/jguer/yay/config"
-	pac "github.com/jguer/yay/pacman"
+	alpm "github.com/jguer/go-alpm"
 	rpc "github.com/mikkeloscar/aur"
 )
 
-// PrintSearch handles printing search results in a given format
-func printAURSearch(q aur.Query, start int) {
-	localDb, _ := config.AlpmHandle.LocalDb()
+// Query is a collection of Results
+type aurQuery []rpc.Pkg
 
-	for i, res := range q {
-		var toprint string
-		if config.YayConf.SearchMode == config.NumberMenu {
-			if config.YayConf.SortMode == config.BottomUp {
-				toprint += fmt.Sprintf("\x1b[33m%d\x1b[0m ", len(q)+start-i-1)
-			} else {
-				toprint += fmt.Sprintf("\x1b[33m%d\x1b[0m ", start+i)
+// Query holds the results of a repository search.
+type repoQuery []alpm.Package
+
+func (q aurQuery) Len() int {
+	return len(q)
+}
+
+func (q aurQuery) Less(i, j int) bool {
+	if config.SortMode == BottomUp {
+		return q[i].NumVotes < q[j].NumVotes
+	}
+	return q[i].NumVotes > q[j].NumVotes
+}
+
+func (q aurQuery) Swap(i, j int) {
+	q[i], q[j] = q[j], q[i]
+}
+
+// FilterPackages filters packages based on source and type from local repository.
+func filterPackages() (local []alpm.Package, remote []alpm.Package,
+	localNames []string, remoteNames []string, err error) {
+	localDb, err := AlpmHandle.LocalDb()
+	if err != nil {
+		return
+	}
+	dbList, err := AlpmHandle.SyncDbs()
+	if err != nil {
+		return
+	}
+
+	f := func(k alpm.Package) error {
+		found := false
+		// For each DB search for our secret package.
+		_ = dbList.ForEach(func(d alpm.Db) error {
+			if found {
+				return nil
 			}
-		} else if config.YayConf.SearchMode == config.Minimal {
-			fmt.Println(res.Name)
-			continue
+			_, err := d.PkgByName(k.Name())
+			if err == nil {
+				found = true
+				local = append(local, k)
+				localNames = append(localNames, k.Name())
+			}
+			return nil
+		})
+
+		if !found {
+			remote = append(remote, k)
+			remoteNames = append(remoteNames, k.Name())
 		}
-		toprint += fmt.Sprintf("\x1b[1m%s/\x1b[33m%s \x1b[36m%s \x1b[0m(%d) ", "aur", res.Name, res.Version, res.NumVotes)
-		if res.Maintainer == "" {
-			toprint += fmt.Sprintf("\x1b[31;40m(Orphaned)\x1b[0m ")
+		return nil
+	}
+
+	err = localDb.PkgCache().ForEach(f)
+	return
+}
+
+// MissingPackage warns if the Query was unable to find a package
+func (q aurQuery) missingPackage(pkgS []string) {
+	for _, depName := range pkgS {
+		found := false
+		for _, dep := range q {
+			if dep.Name == depName {
+				found = true
+				break
+			}
 		}
 
-		if res.OutOfDate != 0 {
-			toprint += fmt.Sprintf("\x1b[31;40m(Out-of-date)\x1b[0m ")
+		if !found {
+			fmt.Println("\x1b[31mUnable to find", depName, "in AUR\x1b[0m")
 		}
+	}
+	return
+}
 
-		if _, err := localDb.PkgByName(res.Name); err == nil {
-			toprint += fmt.Sprintf("\x1b[32;40mInstalled\x1b[0m")
+// NarrowSearch searches AUR and narrows based on subarguments
+func narrowSearch(pkgS []string, sortS bool) (aurQuery, error) {
+	if len(pkgS) == 0 {
+		return nil, nil
+	}
+
+	r, err := rpc.Search(pkgS[0])
+	if err != nil {
+		return nil, err
+	}
+
+	if len(pkgS) == 1 {
+		if sortS {
+			sort.Sort(aurQuery(r))
 		}
-		toprint += "\n    " + res.Description
-		fmt.Println(toprint)
+		return r, err
 	}
 
-	return
+	var aq aurQuery
+	var n int
+
+	for _, res := range r {
+		match := true
+		for _, pkgN := range pkgS[1:] {
+			if !(strings.Contains(res.Name, pkgN) || strings.Contains(strings.ToLower(res.Description), pkgN)) {
+				match = false
+				break
+			}
+		}
+
+		if match {
+			n++
+			aq = append(aq, res)
+		}
+	}
+
+	if sortS {
+		sort.Sort(aq)
+	}
+
+	return aq, err
 }
 
 // SyncSearch presents a query to the local repos and to the AUR.
 func syncSearch(pkgS []string) (err error) {
-	aq, err := aur.NarrowSearch(pkgS, true)
+	aq, err := narrowSearch(pkgS, true)
 	if err != nil {
 		return err
 	}
-	pq, _, err := pac.Search(pkgS)
+	pq, _, err := queryRepo(pkgS)
 	if err != nil {
 		return err
 	}
 
-	if config.YayConf.SortMode == config.BottomUp {
-		printAURSearch(aq, 0)
-		pq.PrintSearch()
+	if config.SortMode == BottomUp {
+		aq.printSearch(0)
+		pq.printSearch()
 	} else {
-		pq.PrintSearch()
-		printAURSearch(aq, 0)
+		pq.printSearch()
+		aq.printSearch(0)
 	}
 
 	return nil
@@ -68,7 +154,7 @@ func syncSearch(pkgS []string) (err error) {
 
 // SyncInfo serves as a pacman -Si for repo packages and AUR packages.
 func syncInfo(pkgS []string, flags []string) (err error) {
-	aurS, repoS, err := pac.PackageSlices(pkgS)
+	aurS, repoS, err := packageSlices(pkgS)
 	if err != nil {
 		return
 	}
@@ -79,12 +165,12 @@ func syncInfo(pkgS []string, flags []string) (err error) {
 			fmt.Println(err)
 		}
 		for _, aurP := range q {
-			aur.PrintInfo(&aurP)
+			PrintInfo(&aurP)
 		}
 	}
 
 	if len(repoS) != 0 {
-		err = config.PassToPacman("-Si", repoS, flags)
+		err = passToPacman("-Si", repoS, flags)
 	}
 
 	return
@@ -92,12 +178,12 @@ func syncInfo(pkgS []string, flags []string) (err error) {
 
 // LocalStatistics returns installed packages statistics.
 func localStatistics(version string) error {
-	info, err := pac.Statistics()
+	info, err := statistics()
 	if err != nil {
 		return err
 	}
 
-	foreignS, err := pac.ForeignPackages()
+	_, _, _, remoteNames, err := filterPackages()
 	if err != nil {
 		return err
 	}
@@ -105,29 +191,22 @@ func localStatistics(version string) error {
 	fmt.Printf("\n Yay version r%s\n", version)
 	fmt.Println("\x1B[1;34m===========================================\x1B[0m")
 	fmt.Printf("\x1B[1;32mTotal installed packages: \x1B[0;33m%d\x1B[0m\n", info.Totaln)
-	fmt.Printf("\x1B[1;32mTotal foreign installed packages: \x1B[0;33m%d\x1B[0m\n", len(foreignS))
+	fmt.Printf("\x1B[1;32mTotal foreign installed packages: \x1B[0;33m%d\x1B[0m\n", len(remoteNames))
 	fmt.Printf("\x1B[1;32mExplicitly installed packages: \x1B[0;33m%d\x1B[0m\n", info.Expln)
-	fmt.Printf("\x1B[1;32mTotal Size occupied by packages: \x1B[0;33m%s\x1B[0m\n", config.Human(info.TotalSize))
+	fmt.Printf("\x1B[1;32mTotal Size occupied by packages: \x1B[0;33m%s\x1B[0m\n", human(info.TotalSize))
 	fmt.Println("\x1B[1;34m===========================================\x1B[0m")
 	fmt.Println("\x1B[1;32mTen biggest packages\x1B[0m")
-	pac.BiggestPackages()
+	biggestPackages()
 	fmt.Println("\x1B[1;34m===========================================\x1B[0m")
 
-	keys := make([]string, len(foreignS))
-	i := 0
-	for k := range foreignS {
-		keys[i] = k
-		i++
-	}
-
-	var q aur.Query
+	var q aurQuery
 	var j int
-	for i = len(keys); i != 0; i = j {
-		j = i - config.YayConf.RequestSplitN
+	for i := len(remoteNames); i != 0; i = j {
+		j = i - config.RequestSplitN
 		if j < 0 {
 			j = 0
 		}
-		qtemp, err := rpc.Info(keys[j:i])
+		qtemp, err := rpc.Info(remoteNames[j:i])
 		q = append(q, qtemp...)
 		if err != nil {
 			return err
@@ -135,7 +214,7 @@ func localStatistics(version string) error {
 	}
 
 	var outcast []string
-	for _, s := range keys {
+	for _, s := range remoteNames {
 		found := false
 		for _, i := range q {
 			if s == i.Name {
@@ -167,3 +246,180 @@ func localStatistics(version string) error {
 
 	return nil
 }
+
+// Search handles repo searches. Creates a RepoSearch struct.
+func queryRepo(pkgInputN []string) (s repoQuery, n int, err error) {
+	dbList, err := AlpmHandle.SyncDbs()
+	if err != nil {
+		return
+	}
+
+	// BottomUp functions
+	initL := func(len int) int {
+		if config.SortMode == TopDown {
+			return 0
+		}
+		return len - 1
+	}
+	compL := func(len int, i int) bool {
+		if config.SortMode == TopDown {
+			return i < len
+		}
+		return i > -1
+	}
+	finalL := func(i int) int {
+		if config.SortMode == TopDown {
+			return i + 1
+		}
+		return i - 1
+	}
+
+	dbS := dbList.Slice()
+	lenDbs := len(dbS)
+	for f := initL(lenDbs); compL(lenDbs, f); f = finalL(f) {
+		pkgS := dbS[f].PkgCache().Slice()
+		lenPkgs := len(pkgS)
+		for i := initL(lenPkgs); compL(lenPkgs, i); i = finalL(i) {
+			match := true
+			for _, pkgN := range pkgInputN {
+				if !(strings.Contains(pkgS[i].Name(), pkgN) || strings.Contains(strings.ToLower(pkgS[i].Description()), pkgN)) {
+					match = false
+					break
+				}
+			}
+
+			if match {
+				n++
+				s = append(s, pkgS[i])
+			}
+		}
+	}
+	return
+}
+
+// PackageSlices separates an input slice into aur and repo slices
+func packageSlices(toCheck []string) (aur []string, repo []string, err error) {
+	dbList, err := AlpmHandle.SyncDbs()
+	if err != nil {
+		return
+	}
+
+	for _, pkg := range toCheck {
+		found := false
+
+		_ = dbList.ForEach(func(db alpm.Db) error {
+			if found {
+				return nil
+			}
+
+			_, err = db.PkgByName(pkg)
+			if err == nil {
+				found = true
+				repo = append(repo, pkg)
+			}
+			return nil
+		})
+
+		if !found {
+			if _, errdb := dbList.PkgCachebyGroup(pkg); errdb == nil {
+				repo = append(repo, pkg)
+			} else {
+				aur = append(aur, pkg)
+			}
+		}
+	}
+
+	err = nil
+	return
+}
+
+// HangingPackages returns a list of packages installed as deps
+// and unneeded by the system
+func hangingPackages() (hanging []string, err error) {
+	localDb, err := AlpmHandle.LocalDb()
+	if err != nil {
+		return
+	}
+
+	f := func(pkg alpm.Package) error {
+		if pkg.Reason() != alpm.PkgReasonDepend {
+			return nil
+		}
+		requiredby := pkg.ComputeRequiredBy()
+		if len(requiredby) == 0 {
+			hanging = append(hanging, pkg.Name())
+			fmt.Printf("%s: \x1B[0;33m%s\x1B[0m\n", pkg.Name(), human(pkg.ISize()))
+
+		}
+		return nil
+	}
+
+	err = localDb.PkgCache().ForEach(f)
+	return
+}
+
+// Statistics returns statistics about packages installed in system
+func statistics() (info struct {
+	Totaln    int
+	Expln     int
+	TotalSize int64
+}, err error) {
+	var tS int64 // TotalSize
+	var nPkg int
+	var ePkg int
+
+	localDb, err := AlpmHandle.LocalDb()
+	if err != nil {
+		return
+	}
+
+	for _, pkg := range localDb.PkgCache().Slice() {
+		tS += pkg.ISize()
+		nPkg++
+		if pkg.Reason() == 0 {
+			ePkg++
+		}
+	}
+
+	info = struct {
+		Totaln    int
+		Expln     int
+		TotalSize int64
+	}{
+		nPkg, ePkg, tS,
+	}
+
+	return
+}
+
+// SliceHangingPackages returns a list of packages installed as deps
+// and unneeded by the system from a provided list of package names.
+func sliceHangingPackages(pkgS []string) (hanging []string) {
+	localDb, err := AlpmHandle.LocalDb()
+	if err != nil {
+		return
+	}
+
+big:
+	for _, pkgName := range pkgS {
+		for _, hangN := range hanging {
+			if hangN == pkgName {
+				continue big
+			}
+		}
+
+		pkg, err := localDb.PkgByName(pkgName)
+		if err == nil {
+			if pkg.Reason() != alpm.PkgReasonDepend {
+				continue
+			}
+
+			requiredby := pkg.ComputeRequiredBy()
+			if len(requiredby) == 0 {
+				hanging = append(hanging, pkgName)
+				fmt.Printf("%s: \x1B[0;33m%s\x1B[0m\n", pkg.Name(), human(pkg.ISize()))
+			}
+		}
+	}
+	return
+}

+ 27 - 0
query_test.go

@@ -0,0 +1,27 @@
+package main
+
+import "testing"
+
+func benchmarkSearch(search string, b *testing.B) {
+	for n := 0; n < b.N; n++ {
+		queryRepo(append([]string{}, search))
+	}
+}
+func BenchmarkSearchSimpleTopDown(b *testing.B) {
+	config.SortMode = TopDown
+	benchmarkSearch("chromium", b)
+}
+
+func BenchmarkSearchSimpleBottomUp(b *testing.B) {
+	config.SortMode = BottomUp
+	benchmarkSearch("chromium", b)
+}
+
+func BenchmarkSearchComplexTopDown(b *testing.B) {
+	config.SortMode = TopDown
+	benchmarkSearch("linux", b)
+}
+func BenchmarkSearchComplexBottomUp(b *testing.B) {
+	config.SortMode = BottomUp
+	benchmarkSearch("linux", b)
+}

+ 342 - 0
upgrade.go

@@ -0,0 +1,342 @@
+package main
+
+import (
+	"bufio"
+	"fmt"
+	"os"
+	"sort"
+	"strconv"
+	"strings"
+	"unicode"
+
+	alpm "github.com/jguer/go-alpm"
+	rpc "github.com/mikkeloscar/aur"
+	pkgb "github.com/mikkeloscar/gopkgbuild"
+)
+
+// upgrade type describes a system upgrade.
+type upgrade struct {
+	Name          string
+	Repository    string
+	LocalVersion  string
+	RemoteVersion string
+}
+
+// Slice is a slice of Upgrades
+type upSlice []upgrade
+
+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 {
+	iRunes := []rune(u[i].Repository)
+	jRunes := []rune(u[j].Repository)
+
+	max := len(iRunes)
+	if max > len(jRunes) {
+		max = len(jRunes)
+	}
+
+	for idx := 0; idx < max; idx++ {
+		ir := iRunes[idx]
+		jr := jRunes[idx]
+
+		lir := unicode.ToLower(ir)
+		ljr := unicode.ToLower(jr)
+
+		if lir != ljr {
+			return lir > ljr
+		}
+
+		// the lowercase runes are the same, so compare the original
+		if ir != jr {
+			return ir > jr
+		}
+	}
+
+	return false
+}
+
+// Print prints the details of the packages to upgrade.
+func (u upSlice) Print(start int) {
+	for k, i := range u {
+		old, err := pkgb.NewCompleteVersion(i.LocalVersion)
+		if err != nil {
+			fmt.Println(i.Name, err)
+		}
+		new, err := pkgb.NewCompleteVersion(i.RemoteVersion)
+		if err != nil {
+			fmt.Println(i.Name, err)
+		}
+
+		f := func(name string) (color int) {
+			var hash = 5381
+			for i := 0; i < len(name); i++ {
+				hash = int(name[i]) + ((hash << 5) + (hash))
+			}
+			return hash%6 + 31
+		}
+		fmt.Printf("\x1b[33m%-2d\x1b[0m ", len(u)+start-k-1)
+		fmt.Printf("\x1b[1;%dm%s\x1b[0m/\x1b[1;39m%-25s\t\t\x1b[0m", f(i.Repository), i.Repository, i.Name)
+
+		if old.Version != new.Version {
+			fmt.Printf("\x1b[31m%18s\x1b[0m-%d -> \x1b[1;32m%s\x1b[0m-%d\x1b[0m",
+				old.Version, old.Pkgrel,
+				new.Version, new.Pkgrel)
+		} else {
+			fmt.Printf("\x1b[0m%18s-\x1b[31m%d\x1b[0m -> %s-\x1b[32m%d\x1b[0m",
+				old.Version, old.Pkgrel,
+				new.Version, new.Pkgrel)
+		}
+		print("\n")
+	}
+}
+
+// List returns lists of packages to upgrade from each source.
+func upList() (aurUp upSlice, repoUp upSlice, err error) {
+	local, remote, _, remoteNames, err := filterPackages()
+	if err != nil {
+		return
+	}
+
+	repoC := make(chan upSlice)
+	aurC := make(chan upSlice)
+	errC := make(chan error)
+
+	fmt.Println("\x1b[1;36;1m::\x1b[0m\x1b[1m Searching databases for updates...\x1b[0m")
+	go func() {
+		repoUpList, err := upRepo(local)
+		errC <- err
+		repoC <- repoUpList
+	}()
+
+	fmt.Println("\x1b[1;36;1m::\x1b[0m\x1b[1m Searching AUR for updates...\x1b[0m")
+	go func() {
+		aurUpList, err := upAUR(remote, remoteNames)
+		errC <- err
+		aurC <- aurUpList
+	}()
+
+	var i = 0
+loop:
+	for {
+		select {
+		case repoUp = <-repoC:
+			i++
+		case aurUp = <-aurC:
+			i++
+		case err := <-errC:
+			if err != nil {
+				fmt.Println(err)
+			}
+		default:
+			if i == 2 {
+				close(repoC)
+				close(aurC)
+				close(errC)
+				break loop
+			}
+		}
+	}
+	return
+}
+
+// aur gathers foreign packages and checks if they have new versions.
+// Output: Upgrade type package list.
+func upAUR(remote []alpm.Package, remoteNames []string) (toUpgrade upSlice, err error) {
+	var j int
+	var routines int
+	var routineDone int
+
+	packageC := make(chan upgrade)
+	done := make(chan bool)
+
+	for i := len(remote); i != 0; i = j {
+		//Split requests so AUR RPC doesn't get mad at us.
+		j = i - config.RequestSplitN
+		if j < 0 {
+			j = 0
+		}
+
+		routines++
+		go func(local []alpm.Package, remote []string) {
+			qtemp, err := rpc.Info(remoteNames)
+			if err != nil {
+				fmt.Println(err)
+				done <- true
+				return
+			}
+			// For each item in query: Search equivalent in foreign.
+			// We assume they're ordered and are returned ordered
+			// and will only be missing if they don't exist in AUR.
+			max := len(qtemp) - 1
+			var missing, x int
+
+			for i := range local {
+				x = i - missing
+				if x > max {
+					break
+				} else if qtemp[x].Name == local[i].Name() {
+					if (config.TimeUpdate && (int64(qtemp[x].LastModified) > local[i].BuildDate().Unix())) ||
+						(alpm.VerCmp(local[i].Version(), qtemp[x].Version) < 0) {
+						packageC <- upgrade{qtemp[x].Name, "aur", local[i].Version(), qtemp[x].Version}
+					}
+					continue
+				} else {
+					missing++
+				}
+			}
+			done <- true
+		}(remote[j:i], remoteNames[j:i])
+	}
+
+	for {
+		select {
+		case pkg := <-packageC:
+			toUpgrade = append(toUpgrade, pkg)
+		case <-done:
+			routineDone++
+			if routineDone == routines {
+				err = nil
+				return
+			}
+		}
+	}
+}
+
+// repo gathers local packages and checks if they have new versions.
+// Output: Upgrade type package list.
+func upRepo(local []alpm.Package) (upSlice, error) {
+	dbList, err := AlpmHandle.SyncDbs()
+	if err != nil {
+		return nil, err
+	}
+
+	slice := upSlice{}
+primeloop:
+	for _, pkg := range local {
+		newPkg := pkg.NewVersion(dbList)
+
+		if newPkg != nil {
+			for _, ignorePkg := range AlpmConf.IgnorePkg {
+				if pkg.Name() == ignorePkg {
+					fmt.Printf("\x1b[33mwarning:\x1b[0m %s (ignored pkg) ignoring upgrade (%s -> %s)\n", pkg.Name(), pkg.Version(), newPkg.Version())
+					continue primeloop
+				}
+			}
+
+			for _, ignoreGroup := range AlpmConf.IgnoreGroup {
+				for _, group := range pkg.Groups().Slice() {
+					if group == ignoreGroup {
+						fmt.Printf("\x1b[33mwarning:\x1b[0m %s (ignored group) ignoring upgrade (%s -> %s)\n", pkg.Name(), pkg.Version(), newPkg.Version())
+						continue primeloop
+
+					}
+				}
+			}
+
+			slice = append(slice, upgrade{pkg.Name(), newPkg.DB().Name(), pkg.Version(), newPkg.Version()})
+		}
+	}
+	return slice, nil
+}
+
+// Upgrade handles updating the cache and installing updates.
+func upgradePkgs(flags []string) error {
+	aurUp, repoUp, err := upList()
+	if err != nil {
+		return err
+	} else if len(aurUp)+len(repoUp) == 0 {
+		fmt.Println("\nthere is nothing to do")
+		return err
+	}
+
+	var repoNums []int
+	var aurNums []int
+	sort.Sort(repoUp)
+	fmt.Printf("\x1b[1;34;1m:: \x1b[0m\x1b[1m%d Packages to upgrade.\x1b[0m\n", len(aurUp)+len(repoUp))
+	repoUp.Print(len(aurUp))
+	aurUp.Print(0)
+
+	if !config.NoConfirm {
+		fmt.Print("\x1b[32mEnter packages you don't want to upgrade.\x1b[0m\nNumbers: ")
+		reader := bufio.NewReader(os.Stdin)
+
+		numberBuf, overflow, err := reader.ReadLine()
+		if err != nil || overflow {
+			fmt.Println(err)
+			return err
+		}
+
+		result := strings.Fields(string(numberBuf))
+		for _, numS := range result {
+			num, err := strconv.Atoi(numS)
+			if err != nil {
+				continue
+			}
+			if num > len(aurUp)+len(repoUp)-1 || num < 0 {
+				continue
+			} else if num < len(aurUp) {
+				num = len(aurUp) - num - 1
+				aurNums = append(aurNums, num)
+			} else {
+				num = len(aurUp) + len(repoUp) - num - 1
+				repoNums = append(repoNums, num)
+			}
+		}
+	}
+
+	if len(repoUp) != 0 {
+		var repoNames []string
+	repoloop:
+		for i, k := range repoUp {
+			for _, j := range repoNums {
+				if j == i {
+					continue repoloop
+				}
+			}
+			repoNames = append(repoNames, k.Name)
+		}
+
+		err := passToPacman("-S", repoNames, append(flags, "--noconfirm"))
+		if err != nil {
+			fmt.Println("Error upgrading repo packages.")
+		}
+	}
+
+	if len(aurUp) != 0 {
+		var aurNames []string
+	aurloop:
+		for i, k := range aurUp {
+			for _, j := range aurNums {
+				if j == i {
+					continue aurloop
+				}
+			}
+			aurNames = append(aurNames, k.Name)
+		}
+		aurInstall(aurNames, flags)
+	}
+	return nil
+}
+
+func develUpgrade(foreign map[string]alpm.Package, flags []string) error {
+	fmt.Println(" Checking development packages...")
+	develUpdates := checkUpdates(foreign)
+	if len(develUpdates) != 0 {
+		for _, q := range develUpdates {
+			fmt.Printf("\x1b[1m\x1b[32m==>\x1b[33;1m %s\x1b[0m\n", q)
+		}
+		// Install updated packages
+		if !continueTask("Proceed with upgrade?", "nN") {
+			return nil
+		}
+
+		err := aurInstall(develUpdates, flags)
+		if err != nil {
+			fmt.Println(err)
+		}
+	}
+
+	return nil
+}

+ 18 - 48
aur/vcs/github.go

@@ -1,4 +1,4 @@
-package github
+package main
 
 import (
 	"encoding/json"
@@ -30,35 +30,21 @@ type Info struct {
 
 type infos []Info
 
-var savedInfo infos
-var configfile string
-
-// Updated returns if database has been updated
-var Updated bool
-
-func init() {
-	Updated = false
-	configfile = os.Getenv("HOME") + "/.config/yay/yay_vcs.json"
-
-	if _, err := os.Stat(configfile); os.IsNotExist(err) {
-		_ = os.MkdirAll(os.Getenv("HOME")+"/.config/yay", 0755)
-		return
-	}
-
-	file, err := os.Open(configfile)
+// CreateDevelDB forces yay to create a DB of the existing development packages
+func createDevelDB() error {
+	_, _, _, remoteNames, err := filterPackages()
 	if err != nil {
-		fmt.Println("error:", err)
-		return
-	}
-	decoder := json.NewDecoder(file)
-	err = decoder.Decode(&savedInfo)
-	if err != nil {
-		fmt.Println("error:", err)
+		return err
 	}
+
+	config.NoConfirm = true
+	specialDBsauce = true
+	err = aurInstall(remoteNames, nil)
+	return err
 }
 
 // ParseSource returns owner and repo from source
-func ParseSource(source string) (owner string, repo string) {
+func parseSource(source string) (owner string, repo string) {
 	if !(strings.Contains(source, "git://") ||
 		strings.Contains(source, ".git") ||
 		strings.Contains(source, "git+https://")) {
@@ -97,22 +83,21 @@ func (info *Info) needsUpdate() bool {
 		if e.Name == "master" {
 			if e.Commit.SHA != info.SHA {
 				return true
-			} else {
-				return false
 			}
+			return false
 		}
 	}
 	return false
 }
 
 // CheckUpdates returns list of outdated packages
-func CheckUpdates(foreign map[string]alpm.Package) (toUpdate []string) {
+func checkUpdates(foreign map[string]alpm.Package) (toUpdate []string) {
 	for _, e := range savedInfo {
 		if e.needsUpdate() {
 			if _, ok := foreign[e.Package]; ok {
 				toUpdate = append(toUpdate, e.Package)
 			} else {
-				RemovePackage([]string{e.Package})
+				removeVCSPackage([]string{e.Package})
 			}
 		}
 	}
@@ -128,24 +113,9 @@ func inStore(pkgName string) *Info {
 	return nil
 }
 
-// RemovePackage removes package from VCS information
-func RemovePackage(pkgs []string) {
-	for _, pkgName := range pkgs {
-		for i, e := range savedInfo {
-			if e.Package == pkgName {
-				savedInfo[i] = savedInfo[len(savedInfo)-1]
-				savedInfo = savedInfo[:len(savedInfo)-1]
-			}
-		}
-	}
-
-	_ = SaveBranchInfo()
-	return
-}
-
 // BranchInfo updates saved information
-func BranchInfo(pkgName string, owner string, repo string) (err error) {
-	Updated = true
+func branchInfo(pkgName string, owner string, repo string) (err error) {
+	updated = true
 	var newRepo branches
 	url := "https://api.github.com/repos/" + owner + "/" + repo + "/branches"
 	r, err := http.Get(url)
@@ -173,8 +143,8 @@ func BranchInfo(pkgName string, owner string, repo string) (err error) {
 	return
 }
 
-func SaveBranchInfo() error {
-	marshalledinfo, err := json.Marshal(savedInfo)
+func saveVCSInfo() error {
+	marshalledinfo, err := json.MarshalIndent(savedInfo, "", "\t")
 	if err != nil || string(marshalledinfo) == "null" {
 		return err
 	}

+ 4 - 4
aur/vcs/github_test.go

@@ -1,4 +1,4 @@
-package github
+package main
 
 import (
 	"testing"
@@ -12,20 +12,20 @@ func TestParsing(t *testing.T) {
 	}
 
 	neovim := source{sourceurl: "git+https://github.com/neovim/neovim.git"}
-	neovim.owner, neovim.repo = ParseSource(neovim.sourceurl)
+	neovim.owner, neovim.repo = parseSource(neovim.sourceurl)
 
 	if neovim.owner != "neovim" || neovim.repo != "neovim" {
 		t.Fatalf("Expected to find neovim/neovim, found %+v/%+v", neovim.owner, neovim.repo)
 	}
 
 	yay := source{sourceurl: "git://github.com/jguer/yay.git#branch=master"}
-	yay.owner, yay.repo = ParseSource(yay.sourceurl)
+	yay.owner, yay.repo = parseSource(yay.sourceurl)
 	if yay.owner != "jguer" || yay.repo != "yay" {
 		t.Fatalf("Expected to find jguer/yay, found %+v/%+v", yay.owner, yay.repo)
 	}
 
 	ack := source{sourceurl: "git://github.com/davidgiven/ack"}
-	ack.owner, ack.repo = ParseSource(ack.sourceurl)
+	ack.owner, ack.repo = parseSource(ack.sourceurl)
 	if ack.owner != "davidgiven" || ack.repo != "ack" {
 		t.Fatalf("Expected to find davidgiven/ack, found %+v/%+v", ack.owner, ack.repo)
 	}

+ 1 - 0
vendor/github.com/jguer/go-alpm/.gitignore

@@ -0,0 +1 @@
+_obj/

+ 19 - 0
vendor/github.com/jguer/go-alpm/LICENSE

@@ -0,0 +1,19 @@
+Copyright (C) 2013 The go-alpm Authors
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.

+ 30 - 0
vendor/github.com/jguer/go-alpm/README.md

@@ -0,0 +1,30 @@
+## go-alpm
+
+go-alpm is a Go package for binding libalpm. With go-alpm, it becomes possible
+to manipulate the Pacman databases and packages just as Pacman would.
+
+This project is MIT Licensed. See LICENSE for details.
+
+## Getting started
+
+1. Import the go-alpm repository in your go script
+
+	import "github.com/demizer/go-alpm"
+
+2. Copy the library to your GOPATH
+
+	mkdir ~/go
+	export GOPATH=~/go
+	go get github.com/demizer/go-alpm
+
+3. Try the included examples
+
+	cd $GOPATH/src/github.com/demizer/go-alpm/examples
+	go run installed.go
+
+## Contributors
+
+* Mike Rosset
+* Dave Reisner
+* Rémy Oudompheng
+* Jesus Alvarez

+ 29 - 0
vendor/github.com/jguer/go-alpm/alpm.go

@@ -0,0 +1,29 @@
+// alpm.go - Implements exported libalpm functions.
+//
+// Copyright (c) 2013 The go-alpm Authors
+//
+// MIT Licensed. See LICENSE for details.
+
+package alpm
+
+// #cgo LDFLAGS: -lalpm
+// #include <alpm.h>
+import "C"
+
+import "unsafe"
+
+// Version returns libalpm version string.
+func Version() string {
+	return C.GoString(C.alpm_version())
+}
+
+// VerCmp performs version comparison according to Pacman conventions. Return
+// value is <0 if and only if v1 is older than v2.
+func VerCmp(v1, v2 string) int {
+	c1 := C.CString(v1)
+	c2 := C.CString(v2)
+	defer C.free(unsafe.Pointer(c1))
+	defer C.free(unsafe.Pointer(c2))
+	result := C.alpm_pkg_vercmp(c1, c2)
+	return int(result)
+}

+ 82 - 0
vendor/github.com/jguer/go-alpm/alpm_test.go

@@ -0,0 +1,82 @@
+// alpm_test.go - Tests for alpm.go.
+//
+// Copyright (c) 2013 The go-alpm Authors
+//
+// MIT Licensed. See LICENSE for details.
+
+package alpm
+
+import (
+	"fmt"
+	"os"
+	"testing"
+)
+
+const (
+	root   = "/"
+	dbpath = "/var/lib/pacman"
+)
+
+var h *Handle
+
+func init() {
+	var err error
+	h, err = Init("/", "/var/lib/pacman")
+	if err != nil {
+		fmt.Printf("failed to Init(): %s", err)
+		os.Exit(1)
+	}
+}
+
+func ExampleVersion() {
+	fmt.Println(Version())
+	// output:
+	// 8.0.2
+}
+
+func ExampleVerCmp() {
+	fmt.Println(VerCmp("1.0-2", "2.0-1") < 0)
+	fmt.Println(VerCmp("1:1.0-2", "2.0-1") > 0)
+	fmt.Println(VerCmp("2.0.2-2", "2.0.2-2") == 0)
+	// output:
+	// true
+	// true
+	// true
+}
+
+func TestRevdeps(t *testing.T) {
+	db, _ := h.LocalDb()
+	pkg, _ := db.PkgByName("glibc")
+	for i, pkgname := range pkg.ComputeRequiredBy() {
+		t.Logf(pkgname)
+		if i == 10 {
+			t.Logf("and %d more...", len(pkg.ComputeRequiredBy())-10)
+			return
+		}
+	}
+}
+
+func TestLocalDB(t *testing.T) {
+	defer func() {
+		if recover() != nil {
+			t.Errorf("local db failed")
+		}
+	}()
+	db, _ := h.LocalDb()
+	number := 0
+	for _, pkg := range db.PkgCache().Slice() {
+		number++
+		if number <= 15 {
+			t.Logf("%v", pkg.Name())
+		}
+	}
+	if number > 15 {
+		t.Logf("%d more packages...", number-15)
+	}
+}
+
+func TestRelease(t *testing.T) {
+	if err := h.Release(); err != nil {
+		t.Error(err)
+	}
+}

+ 31 - 0
vendor/github.com/jguer/go-alpm/callbacks.c

@@ -0,0 +1,31 @@
+// callbacks.c - Sets alpm callbacks to Go functions.
+//
+// Copyright (c) 2013 The go-alpm Authors
+//
+// MIT Licensed. See LICENSE for details.
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <alpm.h>
+
+void logCallback(uint16_t level, char *cstring);
+
+void go_alpm_log_cb(alpm_loglevel_t level, const char *fmt, va_list arg) {
+  char *s = malloc(128);
+  if (s == NULL) return;
+  int16_t length = vsnprintf(s, 128, fmt, arg);
+  if (length > 128) {
+    length = (length + 16) & ~0xf;
+    s = realloc(s, length);
+  }
+  if (s != NULL) {
+		logCallback(level, s);
+		free(s);
+  }
+}
+
+void go_alpm_set_logging(alpm_handle_t *handle) {
+  alpm_option_set_logcb(handle, go_alpm_log_cb);
+}
+

+ 36 - 0
vendor/github.com/jguer/go-alpm/callbacks.go

@@ -0,0 +1,36 @@
+// callbacks.go - Handles libalpm callbacks.
+//
+// Copyright (c) 2013 The go-alpm Authors
+//
+// MIT Licensed. See LICENSE for details.
+
+package alpm
+
+/*
+#include <stdint.h>
+#include <alpm.h>
+void logCallback(uint16_t level, char *cstring);
+void go_alpm_log_cb(alpm_loglevel_t level, const char *fmt, va_list arg);
+void go_alpm_set_logging(alpm_handle_t *handle);
+*/
+import "C"
+
+var DefaultLogLevel = LogWarning
+
+func DefaultLogCallback(lvl uint16, s string) {
+	if lvl <= DefaultLogLevel {
+		print("go-alpm: ", s)
+	}
+}
+
+var log_callback = DefaultLogCallback
+
+//export logCallback
+func logCallback(level uint16, cstring *C.char) {
+	log_callback(level, C.GoString(cstring))
+}
+
+func (h *Handle) SetLogCallback(cb func(uint16, string)) {
+	log_callback = cb
+	C.go_alpm_set_logging(h.ptr)
+}

+ 288 - 0
vendor/github.com/jguer/go-alpm/conf.go

@@ -0,0 +1,288 @@
+// conf.go - Functions for pacman.conf parsing.
+//
+// Copyright (c) 2013 The go-alpm Authors
+//
+// MIT Licensed. See LICENSE for details.
+
+package alpm
+
+import (
+	"bufio"
+	"bytes"
+	"fmt"
+	"io"
+	"os"
+	"reflect"
+	"strings"
+	"syscall"
+)
+
+type PacmanOption uint
+
+const (
+	ConfUseSyslog PacmanOption = 1 << iota
+	ConfColor
+	ConfTotalDownload
+	ConfCheckSpace
+	ConfVerbosePkgLists
+	ConfILoveCandy
+)
+
+var optionsMap = map[string]PacmanOption{
+	"UseSyslog":       ConfUseSyslog,
+	"Color":           ConfColor,
+	"TotalDownload":   ConfTotalDownload,
+	"CheckSpace":      ConfCheckSpace,
+	"VerbosePkgLists": ConfVerbosePkgLists,
+	"ILoveCandy":      ConfILoveCandy,
+}
+
+// PacmanConfig is a type for holding pacman options parsed from pacman
+// configuration data passed to ParseConfig.
+type PacmanConfig struct {
+	RootDir            string
+	DBPath             string
+	CacheDir           []string
+	GPGDir             string
+	LogFile            string
+	HoldPkg            []string
+	IgnorePkg          []string
+	IgnoreGroup        []string
+	Include            []string
+	Architecture       string
+	XferCommand        string
+	NoUpgrade          []string
+	NoExtract          []string
+	CleanMethod        string
+	SigLevel           SigLevel
+	LocalFileSigLevel  SigLevel
+	RemoteFileSigLevel SigLevel
+	UseDelta           string
+	Options            PacmanOption
+	Repos              []RepoConfig
+}
+
+// RepoConfig is a type that stores the signature level of a repository
+// specified in the pacman config file.
+type RepoConfig struct {
+	Name     string
+	SigLevel SigLevel
+	Servers  []string
+}
+
+// Constants for pacman configuration parsing
+const (
+	tokenSection = iota
+	tokenKey
+	tokenComment
+)
+
+type iniToken struct {
+	Type   uint
+	Name   string
+	Values []string
+}
+
+type confReader struct {
+	*bufio.Reader
+	Lineno uint
+}
+
+// newConfReader reads from the io.Reader if it is buffered and returns a
+// confReader containing the number of bytes read and 0 for the first line. If
+// r is not a buffered reader, a new buffered reader is created using r as its
+// input and returned.
+func newConfReader(r io.Reader) confReader {
+	if buf, ok := r.(*bufio.Reader); ok {
+		return confReader{buf, 0}
+	}
+	buf := bufio.NewReader(r)
+	return confReader{buf, 0}
+}
+
+func (rdr *confReader) ParseLine() (tok iniToken, err error) {
+	line, overflow, err := rdr.ReadLine()
+	switch {
+	case err != nil:
+		return
+	case overflow:
+		err = fmt.Errorf("line %d too long", rdr.Lineno)
+		return
+	}
+	rdr.Lineno++
+
+	line = bytes.TrimSpace(line)
+	if len(line) == 0 {
+		tok.Type = tokenComment
+		return
+	}
+	switch line[0] {
+	case '#':
+		tok.Type = tokenComment
+		return
+	case '[':
+		closing := bytes.IndexByte(line, ']')
+		if closing < 0 {
+			err = fmt.Errorf("missing ']' is section name at line %d", rdr.Lineno)
+			return
+		}
+		tok.Name = string(line[1:closing])
+		if closing+1 < len(line) {
+			err = fmt.Errorf("trailing characters %q after section name %s",
+				line[closing+1:], tok.Name)
+			return
+		}
+		return
+	default:
+		tok.Type = tokenKey
+		if idx := bytes.IndexByte(line, '='); idx >= 0 {
+			optname := bytes.TrimSpace(line[:idx])
+			values := bytes.Split(line[idx+1:], []byte{' '})
+			tok.Name = string(optname)
+			tok.Values = make([]string, 0, len(values))
+			for _, word := range values {
+				word = bytes.TrimSpace(word)
+				if len(word) > 0 {
+					tok.Values = append(tok.Values, string(word))
+				}
+			}
+		} else {
+			// boolean option
+			tok.Name = string(line)
+			tok.Values = nil
+		}
+		return
+	}
+}
+
+func ParseConfig(r io.Reader) (conf PacmanConfig, err error) {
+	rdr := newConfReader(r)
+	rdrStack := []confReader{rdr}
+	conf.SetDefaults()
+	confReflect := reflect.ValueOf(&conf).Elem()
+	var currentSection string
+	var curRepo *RepoConfig
+lineloop:
+	for {
+		line, err := rdr.ParseLine()
+		// fmt.Printf("%+v\n", line)
+		switch err {
+		case io.EOF:
+			// pop reader stack.
+			l := len(rdrStack)
+			if l == 1 {
+				return conf, nil
+			}
+			rdr = rdrStack[l-2]
+			rdrStack = rdrStack[:l-1]
+		default:
+			return conf, err
+		case nil:
+			// Ok.
+		}
+
+		switch line.Type {
+		case tokenComment:
+		case tokenSection:
+			currentSection = line.Name
+			if currentSection != "options" {
+				conf.Repos = append(conf.Repos, RepoConfig{})
+				curRepo = &conf.Repos[len(conf.Repos)-1]
+				curRepo.Name = line.Name
+			}
+		case tokenKey:
+			switch line.Name {
+			case "SigLevel":
+				// TODO: implement SigLevel parsing.
+				continue lineloop
+			case "Server":
+				curRepo.Servers = append(curRepo.Servers, line.Values...)
+				continue lineloop
+			case "Include":
+				f, err := os.Open(line.Values[0])
+				if err != nil {
+					err = fmt.Errorf("error while processing Include directive at line %d: %s",
+						rdr.Lineno, err)
+					return conf, err
+				}
+				rdr = newConfReader(f)
+				rdrStack = append(rdrStack, rdr)
+				continue lineloop
+			}
+
+			if currentSection != "options" {
+				err = fmt.Errorf("option %s outside of [options] section, at line %d",
+					line.Name, rdr.Lineno)
+				return conf, err
+			}
+			// main options.
+			if opt, ok := optionsMap[line.Name]; ok {
+				// boolean option.
+				conf.Options |= opt
+			} else {
+				// key-value option.
+				fld := confReflect.FieldByName(line.Name)
+				if !fld.IsValid() || !fld.CanAddr() {
+					_ = fmt.Errorf("unknown option at line %d: %s", rdr.Lineno, line.Name)
+					continue
+				}
+
+				switch fieldP := fld.Addr().Interface().(type) {
+				case *string:
+					// single valued option.
+					*fieldP = strings.Join(line.Values, " ")
+				case *[]string:
+					//many valued option.
+					*fieldP = append(*fieldP, line.Values...)
+				}
+			}
+		}
+	}
+}
+
+func (conf *PacmanConfig) SetDefaults() {
+	conf.RootDir = "/"
+	conf.DBPath = "/var/lib/pacman"
+}
+
+func getArch() (string, error) {
+	var uname syscall.Utsname
+	err := syscall.Uname(&uname)
+	if err != nil {
+		return "", err
+	}
+	var arch [65]byte
+	for i, c := range uname.Machine {
+		if c == 0 {
+			return string(arch[:i]), nil
+		}
+		arch[i] = byte(c)
+	}
+	return string(arch[:]), nil
+}
+
+func (conf *PacmanConfig) CreateHandle() (*Handle, error) {
+	h, err := Init(conf.RootDir, conf.DBPath)
+	if err != nil {
+		return nil, err
+	}
+	if conf.Architecture == "auto" {
+		conf.Architecture, err = getArch()
+		if err != nil {
+			return nil, fmt.Errorf("architecture is 'auto' but couldn't uname()")
+		}
+	}
+	for _, repoconf := range conf.Repos {
+		// TODO: set SigLevel
+		db, err := h.RegisterSyncDb(repoconf.Name, 0)
+		if err == nil {
+			for i, addr := range repoconf.Servers {
+				addr = strings.Replace(addr, "$repo", repoconf.Name, -1)
+				addr = strings.Replace(addr, "$arch", conf.Architecture, -1)
+				repoconf.Servers[i] = addr
+			}
+			db.SetServers(repoconf.Servers)
+		}
+	}
+	return h, nil
+}

+ 66 - 0
vendor/github.com/jguer/go-alpm/conf_test.go

@@ -0,0 +1,66 @@
+// conf_test.go - Tests for conf.go.
+//
+// Copyright (c) 2013 The go-alpm Authors
+//
+// MIT Licensed. See LICENSE for details.
+
+package alpm
+
+import (
+	"os"
+	"reflect"
+	"testing"
+)
+
+var pacmanConfRef = PacmanConfig{
+	RootDir:      "/",
+	DBPath:       "/var/lib/pacman",
+	CacheDir:     []string{"/var/cache/pacman/pkg", "/other/cachedir"},
+	LogFile:      "/var/log/pacman.log",
+	GPGDir:       "/etc/pacman.d/gnupg/",
+	HoldPkg:      []string{"pacman", "glibc"},
+	XferCommand:  "/usr/bin/wget --passive-ftp -c -O %o %u",
+	Architecture: "auto",
+	CleanMethod:  "KeepInstalled",
+	UseDelta:     "0.7",
+	IgnorePkg:    []string{"hello", "world"},
+	IgnoreGroup:  []string{"kde"},
+	NoUpgrade:    nil,
+	NoExtract:    nil,
+
+	Options: ConfColor | ConfCheckSpace | ConfVerbosePkgLists,
+
+	Repos: []RepoConfig{
+		{Name: "core", Servers: []string{"ftp://ftp.example.com/foobar/$repo/os/$arch/"}},
+		{Name: "custom", Servers: []string{"file:///home/custompkgs"}},
+	},
+}
+
+func detailedDeepEqual(t *testing.T, x, y interface{}) {
+	v := reflect.ValueOf(x)
+	w := reflect.ValueOf(y)
+	if v.Type() != w.Type() {
+		t.Errorf("differing types %T vs. %T", x, y)
+		return
+	}
+	for i := 0; i < v.NumField(); i++ {
+		v_fld := v.Field(i).Interface()
+		w_fld := w.Field(i).Interface()
+		if !reflect.DeepEqual(v_fld, w_fld) {
+			t.Errorf("field %s differs: got %#v, expected %#v",
+				v.Type().Field(i).Name, v_fld, w_fld)
+		}
+	}
+}
+
+func TestParseConfigGood(t *testing.T) {
+	f, err := os.Open("testing/conf/good_pacman.conf")
+	if err != nil {
+		t.Error(err)
+	}
+	conf, err := ParseConfig(f)
+	if err != nil {
+		t.Error(err)
+	}
+	detailedDeepEqual(t, conf, pacmanConfRef)
+}

+ 153 - 0
vendor/github.com/jguer/go-alpm/db.go

@@ -0,0 +1,153 @@
+// db.go - Functions for database handling.
+//
+// Copyright (c) 2013 The go-alpm Authors
+//
+// MIT Licensed. See LICENSE for details.
+
+package alpm
+
+/*
+#include <alpm.h>
+*/
+import "C"
+
+import (
+	"fmt"
+	"io"
+	"unsafe"
+)
+
+// Db structure representing a alpm database.
+type Db struct {
+	ptr    *C.alpm_db_t
+	handle Handle
+}
+
+// DbList structure representing a alpm database list.
+type DbList struct {
+	*list
+	handle Handle
+}
+
+// ForEach executes an action on each Db.
+func (l DbList) ForEach(f func(Db) error) error {
+	return l.forEach(func(p unsafe.Pointer) error {
+		return f(Db{(*C.alpm_db_t)(p), l.handle})
+	})
+}
+
+// Slice converst Db list to Db slice.
+func (l DbList) Slice() []Db {
+	slice := []Db{}
+	l.ForEach(func(db Db) error {
+		slice = append(slice, db)
+		return nil
+	})
+	return slice
+}
+
+// LocalDb returns the local database relative to the given handle.
+func (h Handle) LocalDb() (*Db, error) {
+	db := C.alpm_get_localdb(h.ptr)
+	if db == nil {
+		return nil, h.LastError()
+	}
+	return &Db{db, h}, nil
+}
+
+// SyncDbs returns list of Synced DBs.
+func (h Handle) SyncDbs() (DbList, error) {
+	dblist := C.alpm_get_syncdbs(h.ptr)
+	if dblist == nil {
+		return DbList{nil, h}, h.LastError()
+	}
+	dblistPtr := unsafe.Pointer(dblist)
+	return DbList{(*list)(dblistPtr), h}, nil
+}
+
+// SyncDbByName finds a registered database by name.
+func (h Handle) SyncDbByName(name string) (db *Db, err error) {
+	dblist, err := h.SyncDbs()
+	if err != nil {
+		return nil, err
+	}
+	dblist.ForEach(func(b Db) error {
+		if b.Name() == name {
+			db = &b
+			return io.EOF
+		}
+		return nil
+	})
+	if db != nil {
+		return db, nil
+	}
+	return nil, fmt.Errorf("database %s not found", name)
+}
+
+// RegisterSyncDb Loads a sync database with given name and signature check level.
+func (h Handle) RegisterSyncDb(dbname string, siglevel SigLevel) (*Db, error) {
+	cName := C.CString(dbname)
+	defer C.free(unsafe.Pointer(cName))
+
+	db := C.alpm_register_syncdb(h.ptr, cName, C.alpm_siglevel_t(siglevel))
+	if db == nil {
+		return nil, h.LastError()
+	}
+	return &Db{db, h}, nil
+}
+
+// Name returns name of the db
+func (db Db) Name() string {
+	return C.GoString(C.alpm_db_get_name(db.ptr))
+}
+
+// Servers returns host server URL.
+func (db Db) Servers() []string {
+	ptr := unsafe.Pointer(C.alpm_db_get_servers(db.ptr))
+	return StringList{(*list)(ptr)}.Slice()
+}
+
+// SetServers sets server list to use.
+func (db Db) SetServers(servers []string) {
+	C.alpm_db_set_servers(db.ptr, nil)
+	for _, srv := range servers {
+		Csrv := C.CString(srv)
+		defer C.free(unsafe.Pointer(Csrv))
+		C.alpm_db_add_server(db.ptr, Csrv)
+	}
+}
+
+// PkgByName searches a package in db.
+func (db Db) PkgByName(name string) (*Package, error) {
+	cName := C.CString(name)
+	defer C.free(unsafe.Pointer(cName))
+	ptr := C.alpm_db_get_pkg(db.ptr, cName)
+	if ptr == nil {
+		return nil,
+			fmt.Errorf("Error when retrieving %s from database %s: %s",
+				name, db.Name(), db.handle.LastError())
+	}
+	return &Package{ptr, db.handle}, nil
+}
+
+// PkgCachebyGroup returns a PackageList of packages belonging to a group
+func (l DbList) PkgCachebyGroup(name string) (PackageList, error) {
+	cName := C.CString(name)
+	defer C.free(unsafe.Pointer(cName))
+	pkglist := (*C.struct___alpm_list_t)(unsafe.Pointer(l.list))
+
+	pkgcache := (*list)(unsafe.Pointer(C.alpm_find_group_pkgs(pkglist, cName)))
+	if pkgcache == nil {
+		return PackageList{pkgcache, l.handle},
+			fmt.Errorf("Error when retrieving group %s from database list: %s",
+				name, l.handle.LastError())
+	}
+
+	return PackageList{pkgcache, l.handle}, nil
+}
+
+// PkgCache returns the list of packages of the database
+func (db Db) PkgCache() PackageList {
+	pkgcache := (*list)(unsafe.Pointer(C.alpm_db_get_pkgcache(db.ptr)))
+	return PackageList{pkgcache, db.handle}
+}

+ 44 - 0
vendor/github.com/jguer/go-alpm/dependency.go

@@ -0,0 +1,44 @@
+package alpm
+
+/*
+#include <alpm.h>
+*/
+import "C"
+import (
+	"fmt"
+	"unsafe"
+)
+
+// FindSatisfier searches a DbList for a package that satisfies depstring
+// Example "glibc>=2.12"
+func (l DbList) FindSatisfier(depstring string) (*Package, error) {
+	cDepString := C.CString(depstring)
+	defer C.free(unsafe.Pointer(cDepString))
+
+	pkgList := (*C.struct___alpm_list_t)(unsafe.Pointer(l.list))
+	pkgHandle := (*C.struct___alpm_handle_t)(unsafe.Pointer(l.handle.ptr))
+
+	ptr := C.alpm_find_dbs_satisfier(pkgHandle, pkgList, cDepString)
+	if ptr == nil {
+		return nil,
+			fmt.Errorf("unable to satisfy dependency %s in Dblist", depstring)
+	}
+
+	return &Package{ptr, l.handle}, nil
+}
+
+// FindSatisfier finds a package that satisfies depstring from PkgList
+func (l PackageList) FindSatisfier(depstring string) (*Package, error) {
+	cDepString := C.CString(depstring)
+	defer C.free(unsafe.Pointer(cDepString))
+
+	pkgList := (*C.struct___alpm_list_t)(unsafe.Pointer(l.list))
+
+	ptr := C.alpm_find_satisfier(pkgList, cDepString)
+	if ptr == nil {
+		return nil,
+			fmt.Errorf("unable to find dependency %s in PackageList", depstring)
+	}
+
+	return &Package{ptr, l.handle}, nil
+}

+ 98 - 0
vendor/github.com/jguer/go-alpm/enums.go

@@ -0,0 +1,98 @@
+// enums.go - libaplm enumerations.
+//
+// Copyright (c) 2013 The go-alpm Authors
+//
+// MIT Licensed. See LICENSE for details.
+
+package alpm
+
+// Install reason of a package.
+type PkgReason uint
+
+const (
+	PkgReasonExplicit PkgReason = 0
+	PkgReasonDepend   PkgReason = 1
+)
+
+func (r PkgReason) String() string {
+	switch r {
+	case PkgReasonExplicit:
+		return "Explicitly installed"
+	case PkgReasonDepend:
+		return "Installed as a dependency of another package"
+	}
+	return ""
+}
+
+// Source of a package structure.
+type PkgFrom uint
+
+const (
+	FromFile PkgFrom = iota + 1
+	FromLocalDB
+	FromSyncDB
+)
+
+// Dependency constraint types.
+type DepMod uint
+
+const (
+	DepModAny DepMod = iota + 1 // Any version.
+	DepModEq                    // Specific version.
+	DepModGE                    // Test for >= some version.
+	DepModLE                    // Test for <= some version.
+	DepModGT                    // Test for > some version.
+	DepModLT                    // Test for < some version.
+)
+
+func (mod DepMod) String() string {
+	switch mod {
+	case DepModEq:
+		return "="
+	case DepModGE:
+		return ">="
+	case DepModLE:
+		return "<="
+	case DepModGT:
+		return ">"
+	case DepModLT:
+		return "<"
+	}
+	return ""
+}
+
+// Signature checking level.
+type SigLevel uint
+
+const (
+	SigPackage SigLevel = 1 << iota
+	SigPackageOptional
+	SigPackageMarginalOk
+	SigPackageUnknownOk
+)
+const (
+	SigDatabase SigLevel = 1 << (10 + iota)
+	SigDatabaseOptional
+	SigDatabaseMarginalOk
+	SigDatabaseUnknownOk
+)
+const SigUseDefault SigLevel = 1 << 31
+
+// Signature status
+type SigStatus uint
+
+const (
+	SigStatusValid SigStatus = iota
+	SigStatusKeyExpired
+	SigStatusSigExpired
+	SigStatusKeyUnknown
+	SigStatusKeyDisabled
+)
+
+// Logging levels.
+const (
+	LogError uint16 = 1 << iota
+	LogWarning
+	LogDebug
+	LogFunction
+)

+ 21 - 0
vendor/github.com/jguer/go-alpm/error.go

@@ -0,0 +1,21 @@
+// error.go - Functions for converting libalpm erros to Go errors.
+//
+// Copyright (c) 2013 The go-alpm Authors
+//
+// MIT Licensed. See LICENSE for details.
+
+package alpm
+
+// #include <alpm.h>
+import "C"
+
+// The Error type represents error codes from libalpm.
+type Error C.alpm_errno_t
+
+var _ error = Error(0)
+
+// The string representation of an error is given by C function
+// alpm_strerror().
+func (er Error) Error() string {
+	return C.GoString(C.alpm_strerror(C.alpm_errno_t(er)))
+}

+ 13 - 0
vendor/github.com/jguer/go-alpm/examples/Makefile

@@ -0,0 +1,13 @@
+all: alpm-installed alpm-search alpm-updates
+
+alpm-installed: installed.go
+	go build -x -o $@ $<
+
+alpm-search: search.go
+	go build -x -o $@ $<
+
+alpm-updates: updates.go
+	go build -x -o $@ $<
+
+clean:
+	rm -f alpm-installed alpm-search alpm-updates

+ 1 - 0
vendor/github.com/jguer/go-alpm/examples/README.md

@@ -0,0 +1 @@
+To build the examples, use make. The alpm library must be in your GOPATH.

+ 38 - 0
vendor/github.com/jguer/go-alpm/examples/installed.go

@@ -0,0 +1,38 @@
+// installed.go - Example of getting a list of installed packages.
+//
+// Copyright (c) 2013 The go-alpm Authors
+//
+// MIT Licensed. See LICENSE for details.
+
+package main
+
+import (
+	"github.com/demizer/go-alpm"
+	"os"
+	"fmt"
+)
+
+func main() {
+
+	h, er := alpm.Init("/", "/var/lib/pacman")
+	if er != nil {
+		print(er, "\n")
+		os.Exit(1)
+	}
+
+	db, er := h.LocalDb()
+	if er != nil {
+		fmt.Println(er)
+		os.Exit(1)
+	}
+
+	for _, pkg := range db.PkgCache().Slice() {
+		fmt.Printf("%s %s\n", pkg.Name(), pkg.Version())
+	}
+
+	if h.Release() != nil {
+		os.Exit(1)
+	}
+
+	os.Exit(0)
+}

+ 30 - 0
vendor/github.com/jguer/go-alpm/examples/search.go

@@ -0,0 +1,30 @@
+//
+//
+// Copyright (c) 2013 The go-alpm Authors
+//
+// MIT Licensed. See LICENSE for details.
+
+package main
+
+import (
+	"github.com/demizer/go-alpm"
+	"fmt"
+)
+
+func main() {
+	h, er := alpm.Init("/", "/var/lib/pacman")
+	if er != nil {
+		fmt.Println(er)
+		return
+	}
+	defer h.Release()
+
+	db, _ := h.RegisterSyncDb("core", 0)
+	h.RegisterSyncDb("community", 0)
+	h.RegisterSyncDb("extra", 0)
+
+	for _, pkg := range db.PkgCache().Slice() {
+		fmt.Printf("%s %s\n  %s\n",
+			pkg.Name(), pkg.Version(), pkg.Description())
+	}
+}

+ 78 - 0
vendor/github.com/jguer/go-alpm/examples/updates.go

@@ -0,0 +1,78 @@
+//
+//
+// Copyright (c) 2013 The go-alpm Authors
+//
+// MIT Licensed. See LICENSE for details.
+
+package main
+
+import (
+	"fmt"
+	"github.com/demizer/go-alpm"
+	"log"
+	"os"
+)
+
+func human(size int64) string {
+	floatsize := float32(size)
+	units := [...]string{"", "Ki", "Mi", "Gi", "Ti", "Pi", "Ei", "Zi", "Yi"}
+	for _, unit := range units {
+		if floatsize < 1024 {
+			return fmt.Sprintf("%.1f %sB", floatsize, unit)
+		}
+		floatsize /= 1024
+	}
+	return fmt.Sprintf("%d%s", size, "B")
+}
+
+func upgrades(h *alpm.Handle) ([]alpm.Package, error) {
+	localDb, err := h.LocalDb()
+	if err != nil {
+		return nil, err
+	}
+
+	syncDbs, err := h.SyncDbs()
+	if err != nil {
+		return nil, err
+	}
+
+	slice := []alpm.Package{}
+	for _, pkg := range localDb.PkgCache().Slice() {
+		newPkg := pkg.NewVersion(syncDbs)
+		if newPkg != nil {
+			slice = append(slice, *newPkg)
+		}
+	}
+	return slice, nil
+}
+
+func main() {
+
+	file, err := os.Open("/etc/pacman.conf")
+	if err != nil {
+		log.Fatalln(err)
+	}
+	conf, err := alpm.ParseConfig(file)
+	if err != nil {
+		log.Fatalln(err)
+	}
+
+	h, err := conf.CreateHandle()
+	defer h.Release()
+	if err != nil {
+		log.Fatalln(err)
+	}
+
+	upgrades, err := upgrades(h)
+	if err != nil {
+		log.Fatalln(err)
+	}
+
+	var size int64 = 0
+	for _, pkg := range upgrades {
+		size += pkg.Size()
+		fmt.Printf("%s %s -> %s\n", pkg.Name(), pkg.Version(),
+			pkg.Version())
+	}
+	fmt.Printf("Total Download Size: %s\n", human(size))
+}

+ 85 - 0
vendor/github.com/jguer/go-alpm/handle.go

@@ -0,0 +1,85 @@
+// handle.go - libalpm handle type and methods.
+//
+// Copyright (c) 2013 The go-alpm Authors
+//
+// MIT Licensed. See LICENSE for details.
+
+// Package alpm implements Go bindings to the libalpm library used by Pacman,
+// the Arch Linux package manager. Libalpm allows the creation of custom front
+// ends to the Arch Linux package ecosystem.
+//
+// Libalpm does not include support for the Arch User Repository (AUR).
+package alpm
+
+// #include <alpm.h>
+import "C"
+
+import (
+	"unsafe"
+)
+
+type Handle struct {
+	ptr *C.alpm_handle_t
+}
+
+// Initialize
+func Init(root, dbpath string) (*Handle, error) {
+	c_root := C.CString(root)
+	defer C.free(unsafe.Pointer(c_root))
+	c_dbpath := C.CString(dbpath)
+	defer C.free(unsafe.Pointer(c_dbpath))
+	var c_err C.alpm_errno_t
+	h := C.alpm_initialize(c_root, c_dbpath, &c_err)
+
+	if c_err != 0 {
+		return nil, Error(c_err)
+	}
+
+	return &Handle{h}, nil
+}
+
+func (h *Handle) Release() error {
+	if er := C.alpm_release(h.ptr); er != 0 {
+		return Error(er)
+	}
+	h.ptr = nil
+	return nil
+}
+
+func (h Handle) Root() string {
+	return C.GoString(C.alpm_option_get_root(h.ptr))
+}
+
+func (h Handle) DbPath() string {
+	return C.GoString(C.alpm_option_get_dbpath(h.ptr))
+}
+
+// LastError gets the last pm_error
+func (h Handle) LastError() error {
+	if h.ptr != nil {
+		c_err := C.alpm_errno(h.ptr)
+		if c_err != 0 {
+			return Error(c_err)
+		}
+	}
+	return nil
+}
+
+func (h Handle) UseSyslog() bool {
+	value := C.alpm_option_get_usesyslog(h.ptr)
+	return (value != 0)
+}
+
+func (h Handle) SetUseSyslog(value bool) error {
+	var int_value C.int
+	if value {
+		int_value = 1
+	} else {
+		int_value = 0
+	}
+	ok := C.alpm_option_set_usesyslog(h.ptr, int_value)
+	if ok < 0 {
+		return h.LastError()
+	}
+	return nil
+}

+ 246 - 0
vendor/github.com/jguer/go-alpm/package.go

@@ -0,0 +1,246 @@
+// package.go - libalpm package type and methods.
+//
+// Copyright (c) 2013 The go-alpm Authors
+//
+// MIT Licensed. See LICENSE for details.
+
+package alpm
+
+/*
+#include <alpm.h>
+
+int pkg_cmp(const void *v1, const void *v2)
+{
+    alpm_pkg_t *p1 = (alpm_pkg_t *)v1;
+    alpm_pkg_t *p2 = (alpm_pkg_t *)v2;
+    unsigned long int s1 = alpm_pkg_get_isize(p1);
+    unsigned long int s2 = alpm_pkg_get_isize(p2);
+    return(s2 - s1);
+}
+*/
+import "C"
+
+import (
+	"time"
+	"unsafe"
+)
+
+// Package describes a single package and associated handle.
+type Package struct {
+	pmpkg  *C.alpm_pkg_t
+	handle Handle
+}
+
+// PackageList describes a linked list of packages and associated handle.
+type PackageList struct {
+	*list
+	handle Handle
+}
+
+// ForEach executes an action on each package of the PackageList.
+func (l PackageList) ForEach(f func(Package) error) error {
+	return l.forEach(func(p unsafe.Pointer) error {
+		return f(Package{(*C.alpm_pkg_t)(p), l.handle})
+	})
+}
+
+// Slice converts the PackageList to a Package Slice.
+func (l PackageList) Slice() []Package {
+	slice := []Package{}
+	l.ForEach(func(p Package) error {
+		slice = append(slice, p)
+		return nil
+	})
+	return slice
+}
+
+// SortBySize returns a PackageList sorted by size.
+func (l PackageList) SortBySize() PackageList {
+	pkgList := (*C.struct___alpm_list_t)(unsafe.Pointer(l.list))
+
+	pkgCache := (*list)(unsafe.Pointer(
+		C.alpm_list_msort(pkgList,
+			C.alpm_list_count(pkgList),
+			C.alpm_list_fn_cmp(C.pkg_cmp))))
+
+	return PackageList{pkgCache, l.handle}
+}
+
+// DependList describes a linkedlist of dependency type packages.
+type DependList struct{ *list }
+
+// ForEach executes an action on each package of the DependList.
+func (l DependList) ForEach(f func(Depend) error) error {
+	return l.forEach(func(p unsafe.Pointer) error {
+		dep := convertDepend((*C.alpm_depend_t)(p))
+		return f(dep)
+	})
+}
+
+// Slice converts the DependList to a Depend Slice.
+func (l DependList) Slice() []Depend {
+	slice := []Depend{}
+	l.ForEach(func(dep Depend) error {
+		slice = append(slice, dep)
+		return nil
+	})
+	return slice
+}
+
+// Architecture returns the package target Architecture.
+func (pkg Package) Architecture() string {
+	return C.GoString(C.alpm_pkg_get_arch(pkg.pmpkg))
+}
+
+// Backup returns a list of package backups.
+func (pkg Package) Backup() BackupList {
+	ptr := unsafe.Pointer(C.alpm_pkg_get_backup(pkg.pmpkg))
+	return BackupList{(*list)(ptr)}
+}
+
+// BuildDate returns the BuildDate of the package.
+func (pkg Package) BuildDate() time.Time {
+	t := C.alpm_pkg_get_builddate(pkg.pmpkg)
+	return time.Unix(int64(t), 0)
+}
+
+// Conflicts returns the conflicts of the package as a DependList.
+func (pkg Package) Conflicts() DependList {
+	ptr := unsafe.Pointer(C.alpm_pkg_get_conflicts(pkg.pmpkg))
+	return DependList{(*list)(ptr)}
+}
+
+// DB returns the package's origin database.
+func (pkg Package) DB() *Db {
+	ptr := C.alpm_pkg_get_db(pkg.pmpkg)
+	if ptr == nil {
+		return nil
+	}
+	return &Db{ptr, pkg.handle}
+}
+
+// Depends returns the package's dependency list.
+func (pkg Package) Depends() DependList {
+	ptr := unsafe.Pointer(C.alpm_pkg_get_depends(pkg.pmpkg))
+	return DependList{(*list)(ptr)}
+}
+
+// Description returns the package's description.
+func (pkg Package) Description() string {
+	return C.GoString(C.alpm_pkg_get_desc(pkg.pmpkg))
+}
+
+// Files returns the file list of the package.
+func (pkg Package) Files() []File {
+	cFiles := C.alpm_pkg_get_files(pkg.pmpkg)
+	return convertFilelist(cFiles)
+}
+
+// Groups returns the groups the package belongs to.
+func (pkg Package) Groups() StringList {
+	ptr := unsafe.Pointer(C.alpm_pkg_get_groups(pkg.pmpkg))
+	return StringList{(*list)(ptr)}
+}
+
+// ISize returns the package installed size.
+func (pkg Package) ISize() int64 {
+	t := C.alpm_pkg_get_isize(pkg.pmpkg)
+	return int64(t)
+}
+
+// InstallDate returns the package install date.
+func (pkg Package) InstallDate() time.Time {
+	t := C.alpm_pkg_get_installdate(pkg.pmpkg)
+	return time.Unix(int64(t), 0)
+}
+
+// Licenses returns the package license list.
+func (pkg Package) Licenses() StringList {
+	ptr := unsafe.Pointer(C.alpm_pkg_get_licenses(pkg.pmpkg))
+	return StringList{(*list)(ptr)}
+}
+
+// SHA256Sum returns package SHA256Sum.
+func (pkg Package) SHA256Sum() string {
+	return C.GoString(C.alpm_pkg_get_sha256sum(pkg.pmpkg))
+}
+
+// MD5Sum returns package MD5Sum.
+func (pkg Package) MD5Sum() string {
+	return C.GoString(C.alpm_pkg_get_md5sum(pkg.pmpkg))
+}
+
+// Name returns package name.
+func (pkg Package) Name() string {
+	return C.GoString(C.alpm_pkg_get_name(pkg.pmpkg))
+}
+
+// Packager returns package packager name.
+func (pkg Package) Packager() string {
+	return C.GoString(C.alpm_pkg_get_packager(pkg.pmpkg))
+}
+
+// Provides returns DependList of packages provides by package.
+func (pkg Package) Provides() DependList {
+	ptr := unsafe.Pointer(C.alpm_pkg_get_provides(pkg.pmpkg))
+	return DependList{(*list)(ptr)}
+}
+
+// Reason returns package install reason.
+func (pkg Package) Reason() PkgReason {
+	reason := C.alpm_pkg_get_reason(pkg.pmpkg)
+	return PkgReason(reason)
+}
+
+// Origin returns package origin.
+func (pkg Package) Origin() PkgFrom {
+	origin := C.alpm_pkg_get_origin(pkg.pmpkg)
+	return PkgFrom(origin)
+}
+
+// Replaces returns a DependList with the packages this package replaces.
+func (pkg Package) Replaces() DependList {
+	ptr := unsafe.Pointer(C.alpm_pkg_get_replaces(pkg.pmpkg))
+	return DependList{(*list)(ptr)}
+}
+
+// Size returns the packed package size.
+func (pkg Package) Size() int64 {
+	t := C.alpm_pkg_get_size(pkg.pmpkg)
+	return int64(t)
+}
+
+// URL returns the upstream URL of the package.
+func (pkg Package) URL() string {
+	return C.GoString(C.alpm_pkg_get_url(pkg.pmpkg))
+}
+
+// Version returns the package version.
+func (pkg Package) Version() string {
+	return C.GoString(C.alpm_pkg_get_version(pkg.pmpkg))
+}
+
+// ComputeRequiredBy returns the names of reverse dependencies of a package
+func (pkg Package) ComputeRequiredBy() []string {
+	result := C.alpm_pkg_compute_requiredby(pkg.pmpkg)
+	requiredby := make([]string, 0)
+	for i := (*list)(unsafe.Pointer(result)); i != nil; i = i.Next {
+		defer C.free(unsafe.Pointer(i))
+		if i.Data != nil {
+			defer C.free(unsafe.Pointer(i.Data))
+			name := C.GoString((*C.char)(unsafe.Pointer(i.Data)))
+			requiredby = append(requiredby, name)
+		}
+	}
+	return requiredby
+}
+
+// NewVersion checks if there is a new version of the package in the Synced DBs.
+func (pkg Package) NewVersion(l DbList) *Package {
+	ptr := C.alpm_sync_newversion(pkg.pmpkg,
+		(*C.alpm_list_t)(unsafe.Pointer(l.list)))
+	if ptr == nil {
+		return nil
+	}
+	return &Package{ptr, l.handle}
+}

+ 89 - 0
vendor/github.com/jguer/go-alpm/package_test.go

@@ -0,0 +1,89 @@
+// package_test.go - Tests for package.go
+//
+// Copyright (c) 2013 The go-alpm Authors
+//
+// MIT Licensed. See LICENSE for details.
+
+package alpm
+
+import (
+	"bytes"
+	"fmt"
+	"testing"
+	"text/template"
+	"time"
+)
+
+// Auxiliary formatting
+const pkginfo_template = `
+Name         : {{ .Name }}
+Version      : {{ .Version }}
+Architecture : {{ .Architecture }}
+Description  : {{ .Description }}
+URL          : {{ .URL }}
+Groups       : {{ .Groups.Slice }}
+Licenses     : {{ .Licenses.Slice }}
+Dependencies : {{ range .Depends.Slice }}{{ . }} {{ end }}
+Provides     : {{ range .Provides.Slice }}{{ . }} {{ end }}
+Replaces     : {{ range .Replaces.Slice }}{{ . }} {{ end }}
+Conflicts    : {{ range .Conflicts.Slice }}{{ . }} {{ end }}
+Packager     : {{ .Packager }}
+Build Date   : {{ .PrettyBuildDate }}
+Install Date : {{ .PrettyInstallDate }}
+Package Size : {{ .Size }} bytes
+Install Size : {{ .ISize }} bytes
+MD5 Sum      : {{ .MD5Sum }}
+SHA256 Sum   : {{ .SHA256Sum }}
+Reason       : {{ .Reason }}
+
+Required By  : {{ .ComputeRequiredBy }}
+Files        : {{ range .Files }}
+               {{ .Name }} {{ .Size }}{{ end }}
+`
+
+var pkginfo_tpl *template.Template
+
+type PrettyPackage struct {
+	Package
+}
+
+func (p PrettyPackage) PrettyBuildDate() string {
+	return p.BuildDate().Format(time.RFC1123)
+}
+
+func (p PrettyPackage) PrettyInstallDate() string {
+	return p.InstallDate().Format(time.RFC1123)
+}
+
+func init() {
+	var er error
+	pkginfo_tpl, er = template.New("info").Parse(pkginfo_template)
+	if er != nil {
+		fmt.Printf("couldn't compile template: %s\n", er)
+		panic("template parsing error")
+	}
+}
+
+// Tests package attribute getters.
+func TestPkginfo(t *testing.T) {
+	h, er := Init(root, dbpath)
+	defer h.Release()
+	if er != nil {
+		t.Errorf("Failed at alpm initialization: %s", er)
+	}
+
+	t.Log("Printing package information for pacman")
+	db, _ := h.LocalDb()
+
+	pkg, _ := db.PkgByName("pacman")
+	buf := bytes.NewBuffer(nil)
+	pkginfo_tpl.Execute(buf, PrettyPackage{*pkg})
+	t.Logf("%s...", buf.Bytes()[:1024])
+
+	pkg, _ = db.PkgByName("linux")
+	if pkg != nil {
+		buf = bytes.NewBuffer(nil)
+		pkginfo_tpl.Execute(buf, PrettyPackage{*pkg})
+		t.Logf("%s...", buf.Bytes()[:1024])
+	}
+}

+ 1 - 0
vendor/github.com/jguer/go-alpm/testing/README.md

@@ -0,0 +1 @@
+This directory contains testing related files.

+ 41 - 0
vendor/github.com/jguer/go-alpm/testing/conf/good_pacman.conf

@@ -0,0 +1,41 @@
+#
+# GENERAL OPTIONS
+#
+[options]
+RootDir     = /
+DBPath      = /var/lib/pacman
+CacheDir    = /var/cache/pacman/pkg /other/cachedir
+LogFile     = /var/log/pacman.log
+GPGDir      = /etc/pacman.d/gnupg/
+HoldPkg     = pacman glibc
+#XferCommand = /usr/bin/curl -C - -f %u > %o
+XferCommand = /usr/bin/wget --passive-ftp -c -O %o %u
+CleanMethod = KeepInstalled
+UseDelta    = 0.7
+Architecture = auto
+
+# Pacman won't upgrade packages listed in IgnorePkg and members of IgnoreGroup
+IgnorePkg   = hello world
+IgnoreGroup = kde
+
+#NoUpgrade   =
+#NoExtract   =
+
+# Misc options
+#UseSyslog
+Color
+#TotalDownload
+CheckSpace
+VerbosePkgLists
+
+# By default, pacman accepts packages signed by keys that its local keyring
+# trusts (see pacman-key and its man page), as well as unsigned packages.
+SigLevel    = Required DatabaseOptional
+LocalFileSigLevel = Optional
+#RemoteFileSigLevel = Required
+
+[core]
+Server = ftp://ftp.example.com/foobar/$repo/os/$arch/
+
+[custom]
+Server = file:///home/custompkgs

+ 125 - 0
vendor/github.com/jguer/go-alpm/types.go

@@ -0,0 +1,125 @@
+// types.go - libalpm types.
+//
+// Copyright (c) 2013 The go-alpm Authors
+//
+// MIT Licensed. See LICENSE for details.
+
+package alpm
+
+// #cgo CFLAGS: -D_FILE_OFFSET_BITS=64
+// #include <alpm.h>
+import "C"
+
+import (
+	"reflect"
+	"unsafe"
+)
+
+// Description of a dependency.
+type Depend struct {
+	Name    string
+	Version string
+	Mod     DepMod
+}
+
+func convertDepend(dep *C.alpm_depend_t) Depend {
+	return Depend{
+		Name:    C.GoString(dep.name),
+		Version: C.GoString(dep.version),
+		Mod:     DepMod(dep.mod)}
+}
+
+func (dep Depend) String() string {
+	return dep.Name + dep.Mod.String() + dep.Version
+}
+
+// Description of package files.
+type File struct {
+	Name string
+	Size int64
+	Mode uint32
+}
+
+func convertFilelist(files *C.alpm_filelist_t) []File {
+	size := int(files.count)
+	items := make([]File, size)
+
+	raw_items := reflect.SliceHeader{
+		Len:  size,
+		Cap:  size,
+		Data: uintptr(unsafe.Pointer(files.files))}
+
+	c_files := *(*[]C.alpm_file_t)(unsafe.Pointer(&raw_items))
+
+	for i := 0; i < size; i++ {
+		items[i] = File{
+			Name: C.GoString(c_files[i].name),
+			Size: int64(c_files[i].size),
+			Mode: uint32(c_files[i].mode)}
+	}
+	return items
+}
+
+// Internal alpm list structure.
+type list struct {
+	Data unsafe.Pointer
+	Prev *list
+	Next *list
+}
+
+// Iterates a function on a list and stop on error.
+func (l *list) forEach(f func(unsafe.Pointer) error) error {
+	for ; l != nil; l = l.Next {
+		err := f(l.Data)
+		if err != nil {
+			return err
+		}
+	}
+	return nil
+}
+
+type StringList struct {
+	*list
+}
+
+func (l StringList) ForEach(f func(string) error) error {
+	return l.forEach(func(p unsafe.Pointer) error {
+		return f(C.GoString((*C.char)(p)))
+	})
+}
+
+func (l StringList) Slice() []string {
+	slice := []string{}
+	l.ForEach(func(s string) error {
+		slice = append(slice, s)
+		return nil
+	})
+	return slice
+}
+
+type BackupFile struct {
+	Name string
+	Hash string
+}
+
+type BackupList struct {
+	*list
+}
+
+func (l BackupList) ForEach(f func(BackupFile) error) error {
+	return l.forEach(func(p unsafe.Pointer) error {
+		bf := (*C.alpm_backup_t)(p)
+		return f(BackupFile{
+			Name: C.GoString(bf.name),
+			Hash: C.GoString(bf.hash),
+		})
+	})
+}
+
+func (l BackupList) Slice() (slice []BackupFile) {
+	l.ForEach(func(f BackupFile) error {
+		slice = append(slice, f)
+		return nil
+	})
+	return
+}

+ 674 - 0
vendor/github.com/mikkeloscar/aur/LICENSE

@@ -0,0 +1,674 @@
+                    GNU GENERAL PUBLIC LICENSE
+                       Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                            Preamble
+
+  The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+  The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works.  By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users.  We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors.  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+  To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights.  Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received.  You must make sure that they, too, receive
+or can get the source code.  And you must show them these terms so they
+know their rights.
+
+  Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+  For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software.  For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+  Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so.  This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software.  The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable.  Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products.  If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+  Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary.  To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                       TERMS AND CONDITIONS
+
+  0. Definitions.
+
+  "This License" refers to version 3 of the GNU General Public License.
+
+  "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+  "The Program" refers to any copyrightable work licensed under this
+License.  Each licensee is addressed as "you".  "Licensees" and
+"recipients" may be individuals or organizations.
+
+  To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy.  The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+  A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+  To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy.  Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+  To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies.  Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+  An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License.  If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+  1. Source Code.
+
+  The "source code" for a work means the preferred form of the work
+for making modifications to it.  "Object code" means any non-source
+form of a work.
+
+  A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+  The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form.  A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+  The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities.  However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work.  For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+  The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+  The Corresponding Source for a work in source code form is that
+same work.
+
+  2. Basic Permissions.
+
+  All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met.  This License explicitly affirms your unlimited
+permission to run the unmodified Program.  The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work.  This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+  You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force.  You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright.  Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+  Conveying under any other circumstances is permitted solely under
+the conditions stated below.  Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+  3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+  No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+  When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+  4. Conveying Verbatim Copies.
+
+  You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+  You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+  5. Conveying Modified Source Versions.
+
+  You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+    a) The work must carry prominent notices stating that you modified
+    it, and giving a relevant date.
+
+    b) The work must carry prominent notices stating that it is
+    released under this License and any conditions added under section
+    7.  This requirement modifies the requirement in section 4 to
+    "keep intact all notices".
+
+    c) You must license the entire work, as a whole, under this
+    License to anyone who comes into possession of a copy.  This
+    License will therefore apply, along with any applicable section 7
+    additional terms, to the whole of the work, and all its parts,
+    regardless of how they are packaged.  This License gives no
+    permission to license the work in any other way, but it does not
+    invalidate such permission if you have separately received it.
+
+    d) If the work has interactive user interfaces, each must display
+    Appropriate Legal Notices; however, if the Program has interactive
+    interfaces that do not display Appropriate Legal Notices, your
+    work need not make them do so.
+
+  A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit.  Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+  6. Conveying Non-Source Forms.
+
+  You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+    a) Convey the object code in, or embodied in, a physical product
+    (including a physical distribution medium), accompanied by the
+    Corresponding Source fixed on a durable physical medium
+    customarily used for software interchange.
+
+    b) Convey the object code in, or embodied in, a physical product
+    (including a physical distribution medium), accompanied by a
+    written offer, valid for at least three years and valid for as
+    long as you offer spare parts or customer support for that product
+    model, to give anyone who possesses the object code either (1) a
+    copy of the Corresponding Source for all the software in the
+    product that is covered by this License, on a durable physical
+    medium customarily used for software interchange, for a price no
+    more than your reasonable cost of physically performing this
+    conveying of source, or (2) access to copy the
+    Corresponding Source from a network server at no charge.
+
+    c) Convey individual copies of the object code with a copy of the
+    written offer to provide the Corresponding Source.  This
+    alternative is allowed only occasionally and noncommercially, and
+    only if you received the object code with such an offer, in accord
+    with subsection 6b.
+
+    d) Convey the object code by offering access from a designated
+    place (gratis or for a charge), and offer equivalent access to the
+    Corresponding Source in the same way through the same place at no
+    further charge.  You need not require recipients to copy the
+    Corresponding Source along with the object code.  If the place to
+    copy the object code is a network server, the Corresponding Source
+    may be on a different server (operated by you or a third party)
+    that supports equivalent copying facilities, provided you maintain
+    clear directions next to the object code saying where to find the
+    Corresponding Source.  Regardless of what server hosts the
+    Corresponding Source, you remain obligated to ensure that it is
+    available for as long as needed to satisfy these requirements.
+
+    e) Convey the object code using peer-to-peer transmission, provided
+    you inform other peers where the object code and Corresponding
+    Source of the work are being offered to the general public at no
+    charge under subsection 6d.
+
+  A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+  A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling.  In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage.  For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product.  A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+  "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source.  The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+  If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information.  But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+  The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed.  Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+  Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+  7. Additional Terms.
+
+  "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law.  If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+  When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it.  (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.)  You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+  Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+    a) Disclaiming warranty or limiting liability differently from the
+    terms of sections 15 and 16 of this License; or
+
+    b) Requiring preservation of specified reasonable legal notices or
+    author attributions in that material or in the Appropriate Legal
+    Notices displayed by works containing it; or
+
+    c) Prohibiting misrepresentation of the origin of that material, or
+    requiring that modified versions of such material be marked in
+    reasonable ways as different from the original version; or
+
+    d) Limiting the use for publicity purposes of names of licensors or
+    authors of the material; or
+
+    e) Declining to grant rights under trademark law for use of some
+    trade names, trademarks, or service marks; or
+
+    f) Requiring indemnification of licensors and authors of that
+    material by anyone who conveys the material (or modified versions of
+    it) with contractual assumptions of liability to the recipient, for
+    any liability that these contractual assumptions directly impose on
+    those licensors and authors.
+
+  All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10.  If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term.  If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+  If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+  Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+  8. Termination.
+
+  You may not propagate or modify a covered work except as expressly
+provided under this License.  Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+  However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+  Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+  Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License.  If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+  9. Acceptance Not Required for Having Copies.
+
+  You are not required to accept this License in order to receive or
+run a copy of the Program.  Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance.  However,
+nothing other than this License grants you permission to propagate or
+modify any covered work.  These actions infringe copyright if you do
+not accept this License.  Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+  10. Automatic Licensing of Downstream Recipients.
+
+  Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License.  You are not responsible
+for enforcing compliance by third parties with this License.
+
+  An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations.  If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+  You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License.  For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+  11. Patents.
+
+  A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based.  The
+work thus licensed is called the contributor's "contributor version".
+
+  A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version.  For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+  Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+  In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement).  To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+  If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients.  "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+  If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+  A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License.  You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+  Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+  12. No Surrender of Others' Freedom.
+
+  If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all.  For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+  13. Use with the GNU Affero General Public License.
+
+  Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work.  The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+  14. Revised Versions of this License.
+
+  The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+  Each version is given a distinguishing version number.  If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation.  If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+  If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+  Later license versions may give you additional or different
+permissions.  However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+  15. Disclaimer of Warranty.
+
+  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. Limitation of Liability.
+
+  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+  17. Interpretation of Sections 15 and 16.
+
+  If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+                     END OF TERMS AND CONDITIONS
+
+            How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+  If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+    <program>  Copyright (C) <year>  <name of author>
+    This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+  You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+<http://www.gnu.org/licenses/>.
+
+  The GNU General Public License does not permit incorporating your program
+into proprietary programs.  If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications with
+the library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.  But first, please read
+<http://www.gnu.org/philosophy/why-not-lgpl.html>.

+ 23 - 0
vendor/github.com/mikkeloscar/aur/README.md

@@ -0,0 +1,23 @@
+[![GoDoc](https://godoc.org/github.com/mikkeloscar/aur?status.svg)](https://godoc.org/github.com/mikkeloscar/aur)
+
+# go wrapper for the AUR JSON API
+
+Wrapper around the json API v5 for AUR found at
+http://aur.archlinux.org/rpc.php
+
+## LICENSE
+
+Copyright (C) 2016  Mikkel Oscar Lyderik Larsen
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.

+ 104 - 0
vendor/github.com/mikkeloscar/aur/aur.go

@@ -0,0 +1,104 @@
+package aur
+
+import (
+	"encoding/json"
+	"fmt"
+	"net/http"
+	"net/url"
+)
+
+const aurURL = "https://aur.archlinux.org/rpc.php?"
+
+type response struct {
+	Error       string `json:"error"`
+	Version     int    `json:"version"`
+	Type        string `json:"type"`
+	ResultCount int    `json:"resultcount"`
+	Results     []Pkg  `json:"results"`
+}
+
+// Pkg holds package information
+type Pkg struct {
+	ID             int      `json:"ID"`
+	Name           string   `json:"Name"`
+	PackageBaseID  int      `json:"PackageBaseID"`
+	PackageBase    string   `json:"PackageBase"`
+	Version        string   `json:"Version"`
+	Description    string   `json:"Description"`
+	URL            string   `json:"URL"`
+	NumVotes       int      `json:"NumVotes"`
+	Popularity     float64  `json:"Popularity"`
+	OutOfDate      int      `json:"OutOfDate"`
+	Maintainer     string   `json:"Maintainer"`
+	FirstSubmitted int      `json:"FirstSubmitted"`
+	LastModified   int      `json:"LastModified"`
+	URLPath        string   `json:"URLPath"`
+	Depends        []string `json:"Depends"`
+	MakeDepends    []string `json:"MakeDepends"`
+	Conflicts      []string `json:"Conflicts"`
+	Replaces       []string `json:"Replaces"`
+	OptDepends     []string `json:"OptDepends"`
+	License        []string `json:"License"`
+	Keywords       []string `json:"Keywords"`
+}
+
+func get(values url.Values) ([]Pkg, error) {
+	values.Set("v", "5")
+	resp, err := http.Get(aurURL + values.Encode())
+	if err != nil {
+		return nil, err
+	}
+	defer resp.Body.Close()
+
+	dec := json.NewDecoder(resp.Body)
+	result := new(response)
+	err = dec.Decode(result)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(result.Error) > 0 {
+		return nil, fmt.Errorf(result.Error)
+	}
+
+	return result.Results, nil
+}
+
+// Search searches for packages by package name.
+func Search(query string) ([]Pkg, error) {
+	v := url.Values{}
+	v.Set("type", "search")
+	v.Set("arg", query)
+
+	return get(v)
+}
+
+// SearchByNameDesc searches for package by package name and description.
+func SearchByNameDesc(query string) ([]Pkg, error) {
+	v := url.Values{}
+	v.Set("type", "search")
+	v.Set("by", "name-desc")
+	v.Set("arg", query)
+
+	return get(v)
+}
+
+// SearchByMaintainer searches for package by maintainer.
+func SearchByMaintainer(query string) ([]Pkg, error) {
+	v := url.Values{}
+	v.Set("type", "search")
+	v.Set("by", "maintainer")
+	v.Set("arg", query)
+
+	return get(v)
+}
+
+// Info shows info for one or multiple packages.
+func Info(pkgs []string) ([]Pkg, error) {
+	v := url.Values{}
+	v.Set("type", "info")
+	for _, arg := range pkgs {
+		v.Add("arg[]", arg)
+	}
+	return get(v)
+}

+ 69 - 0
vendor/github.com/mikkeloscar/aur/aur_test.go

@@ -0,0 +1,69 @@
+package aur
+
+import "testing"
+
+// TestSearch test searching for packages by name and/or description
+func TestSearch(t *testing.T) {
+	rs, err := Search("linux")
+	if err != nil {
+		t.Error(err)
+	}
+
+	if len(rs) < 100 {
+		t.Errorf("Expected more than 100 packages, got '%d'", len(rs))
+	}
+
+	rs, err = Search("li")
+	if err.Error() != "Too many package results." {
+		t.Errorf("Expected error 'Too many package results.', got '%s'", err.Error())
+	}
+
+	if len(rs) > 0 {
+		t.Errorf("Expected no results, got '%d'", len(rs))
+	}
+}
+
+// TestSearchByNameDesc test searching for packages package name and desc.
+func TestSearchByNameDesc(t *testing.T) {
+	rs, err := SearchByNameDesc("linux")
+	if err != nil {
+		t.Error(err)
+	}
+
+	if len(rs) < 100 {
+		t.Errorf("Expected more than 100 packages, got '%d'", len(rs))
+	}
+
+	rs, err = Search("li")
+	if err.Error() != "Too many package results." {
+		t.Errorf("Expected error 'Too many package results.', got '%s'", err.Error())
+	}
+
+	if len(rs) > 0 {
+		t.Errorf("Expected no results, got '%d'", len(rs))
+	}
+}
+
+// TestSearchByMaintainer test searching for packages by maintainer
+func TestSearchByMaintainer(t *testing.T) {
+	rs, err := SearchByMaintainer("moscar")
+	if err != nil {
+		t.Error(err)
+	}
+
+	if len(rs) < 3 {
+		t.Errorf("Expected more than 3 packages, got '%d'", len(rs))
+	}
+}
+
+// TestInfo test getting info for multiple packages
+func TestInfo(t *testing.T) {
+	rs, err := Info([]string{"neovim-git", "linux-mainline"})
+	if err != nil {
+		t.Error(err)
+	}
+
+	if len(rs) != 2 {
+		t.Errorf("Expected two packages, got %d", len(rs))
+	}
+}

+ 674 - 0
vendor/github.com/mikkeloscar/gopkgbuild/LICENSE

@@ -0,0 +1,674 @@
+                    GNU GENERAL PUBLIC LICENSE
+                       Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                            Preamble
+
+  The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+  The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works.  By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users.  We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors.  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+  To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights.  Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received.  You must make sure that they, too, receive
+or can get the source code.  And you must show them these terms so they
+know their rights.
+
+  Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+  For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software.  For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+  Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so.  This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software.  The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable.  Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products.  If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+  Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary.  To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                       TERMS AND CONDITIONS
+
+  0. Definitions.
+
+  "This License" refers to version 3 of the GNU General Public License.
+
+  "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+  "The Program" refers to any copyrightable work licensed under this
+License.  Each licensee is addressed as "you".  "Licensees" and
+"recipients" may be individuals or organizations.
+
+  To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy.  The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+  A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+  To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy.  Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+  To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies.  Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+  An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License.  If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+  1. Source Code.
+
+  The "source code" for a work means the preferred form of the work
+for making modifications to it.  "Object code" means any non-source
+form of a work.
+
+  A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+  The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form.  A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+  The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities.  However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work.  For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+  The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+  The Corresponding Source for a work in source code form is that
+same work.
+
+  2. Basic Permissions.
+
+  All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met.  This License explicitly affirms your unlimited
+permission to run the unmodified Program.  The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work.  This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+  You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force.  You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright.  Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+  Conveying under any other circumstances is permitted solely under
+the conditions stated below.  Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+  3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+  No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+  When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+  4. Conveying Verbatim Copies.
+
+  You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+  You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+  5. Conveying Modified Source Versions.
+
+  You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+    a) The work must carry prominent notices stating that you modified
+    it, and giving a relevant date.
+
+    b) The work must carry prominent notices stating that it is
+    released under this License and any conditions added under section
+    7.  This requirement modifies the requirement in section 4 to
+    "keep intact all notices".
+
+    c) You must license the entire work, as a whole, under this
+    License to anyone who comes into possession of a copy.  This
+    License will therefore apply, along with any applicable section 7
+    additional terms, to the whole of the work, and all its parts,
+    regardless of how they are packaged.  This License gives no
+    permission to license the work in any other way, but it does not
+    invalidate such permission if you have separately received it.
+
+    d) If the work has interactive user interfaces, each must display
+    Appropriate Legal Notices; however, if the Program has interactive
+    interfaces that do not display Appropriate Legal Notices, your
+    work need not make them do so.
+
+  A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit.  Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+  6. Conveying Non-Source Forms.
+
+  You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+    a) Convey the object code in, or embodied in, a physical product
+    (including a physical distribution medium), accompanied by the
+    Corresponding Source fixed on a durable physical medium
+    customarily used for software interchange.
+
+    b) Convey the object code in, or embodied in, a physical product
+    (including a physical distribution medium), accompanied by a
+    written offer, valid for at least three years and valid for as
+    long as you offer spare parts or customer support for that product
+    model, to give anyone who possesses the object code either (1) a
+    copy of the Corresponding Source for all the software in the
+    product that is covered by this License, on a durable physical
+    medium customarily used for software interchange, for a price no
+    more than your reasonable cost of physically performing this
+    conveying of source, or (2) access to copy the
+    Corresponding Source from a network server at no charge.
+
+    c) Convey individual copies of the object code with a copy of the
+    written offer to provide the Corresponding Source.  This
+    alternative is allowed only occasionally and noncommercially, and
+    only if you received the object code with such an offer, in accord
+    with subsection 6b.
+
+    d) Convey the object code by offering access from a designated
+    place (gratis or for a charge), and offer equivalent access to the
+    Corresponding Source in the same way through the same place at no
+    further charge.  You need not require recipients to copy the
+    Corresponding Source along with the object code.  If the place to
+    copy the object code is a network server, the Corresponding Source
+    may be on a different server (operated by you or a third party)
+    that supports equivalent copying facilities, provided you maintain
+    clear directions next to the object code saying where to find the
+    Corresponding Source.  Regardless of what server hosts the
+    Corresponding Source, you remain obligated to ensure that it is
+    available for as long as needed to satisfy these requirements.
+
+    e) Convey the object code using peer-to-peer transmission, provided
+    you inform other peers where the object code and Corresponding
+    Source of the work are being offered to the general public at no
+    charge under subsection 6d.
+
+  A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+  A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling.  In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage.  For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product.  A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+  "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source.  The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+  If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information.  But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+  The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed.  Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+  Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+  7. Additional Terms.
+
+  "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law.  If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+  When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it.  (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.)  You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+  Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+    a) Disclaiming warranty or limiting liability differently from the
+    terms of sections 15 and 16 of this License; or
+
+    b) Requiring preservation of specified reasonable legal notices or
+    author attributions in that material or in the Appropriate Legal
+    Notices displayed by works containing it; or
+
+    c) Prohibiting misrepresentation of the origin of that material, or
+    requiring that modified versions of such material be marked in
+    reasonable ways as different from the original version; or
+
+    d) Limiting the use for publicity purposes of names of licensors or
+    authors of the material; or
+
+    e) Declining to grant rights under trademark law for use of some
+    trade names, trademarks, or service marks; or
+
+    f) Requiring indemnification of licensors and authors of that
+    material by anyone who conveys the material (or modified versions of
+    it) with contractual assumptions of liability to the recipient, for
+    any liability that these contractual assumptions directly impose on
+    those licensors and authors.
+
+  All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10.  If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term.  If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+  If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+  Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+  8. Termination.
+
+  You may not propagate or modify a covered work except as expressly
+provided under this License.  Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+  However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+  Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+  Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License.  If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+  9. Acceptance Not Required for Having Copies.
+
+  You are not required to accept this License in order to receive or
+run a copy of the Program.  Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance.  However,
+nothing other than this License grants you permission to propagate or
+modify any covered work.  These actions infringe copyright if you do
+not accept this License.  Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+  10. Automatic Licensing of Downstream Recipients.
+
+  Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License.  You are not responsible
+for enforcing compliance by third parties with this License.
+
+  An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations.  If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+  You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License.  For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+  11. Patents.
+
+  A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based.  The
+work thus licensed is called the contributor's "contributor version".
+
+  A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version.  For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+  Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+  In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement).  To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+  If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients.  "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+  If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+  A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License.  You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+  Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+  12. No Surrender of Others' Freedom.
+
+  If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all.  For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+  13. Use with the GNU Affero General Public License.
+
+  Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work.  The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+  14. Revised Versions of this License.
+
+  The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+  Each version is given a distinguishing version number.  If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation.  If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+  If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+  Later license versions may give you additional or different
+permissions.  However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+  15. Disclaimer of Warranty.
+
+  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. Limitation of Liability.
+
+  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+  17. Interpretation of Sections 15 and 16.
+
+  If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+                     END OF TERMS AND CONDITIONS
+
+            How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+  If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+    <program>  Copyright (C) <year>  <name of author>
+    This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+  You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+<http://www.gnu.org/licenses/>.
+
+  The GNU General Public License does not permit incorporating your program
+into proprietary programs.  If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications with
+the library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.  But first, please read
+<http://www.gnu.org/philosophy/why-not-lgpl.html>.

+ 65 - 0
vendor/github.com/mikkeloscar/gopkgbuild/README.md

@@ -0,0 +1,65 @@
+[![GoDoc](https://godoc.org/github.com/mikkeloscar/gopkgbuild?status.svg)](https://godoc.org/github.com/mikkeloscar/gopkgbuild)
+
+# goPKGBUILD
+
+A golang package for parsing [Arch Linux][archlinux] `.SRCINFO` files
+([PKGBUILDs][pkgbuilds]).
+
+## TODO
+
+- [x] Handle split PKGBUILDs like [linux][linux-pkg]
+- [ ] Try to parse maintainer from top of PKGBUILD
+- [x] Handle multiple dependency versions
+- [x] Add support for reading a `.SRCINFO` file directly
+- [x] Update to pacman 4.2
+
+## Usage
+
+[Godoc][godoc]
+
+Example usage
+
+```go
+package main
+
+import (
+    "fmt"
+
+    "github.com/mikkeloscar/gopkgbuild"
+)
+
+func main() {
+    pkgb, err := ParseSRCINFO("/path/to/.SRCINFO")
+    if err != nil {
+        fmt.Println(err)
+    }
+
+    for _, subPkg := range pkgb.Pkgnames {
+       fmt.Printf("Package name: %s", subPkg)
+    }
+}
+```
+
+## LICENSE
+
+Copyright (C) 2016  Mikkel Oscar Lyderik Larsen
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+
+[archlinux]: http://archlinux.org
+[pkgbuilds]: https://wiki.archlinux.org/index.php/PKGBUILD
+[linux-pkg]: https://projects.archlinux.org/svntogit/packages.git/tree/trunk/PKGBUILD?h=packages/linux
+[pkg-introspec]: https://www.archlinux.org/packages/community/any/pkgbuild-introspection/
+[godoc]: https://godoc.org/github.com/mikkeloscar/gopkgbuild

+ 279 - 0
vendor/github.com/mikkeloscar/gopkgbuild/lex.go

@@ -0,0 +1,279 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// based on the lexer from: src/pkg/text/template/parse/lex.go (golang source)
+
+package pkgbuild
+
+import (
+	"fmt"
+	"strings"
+	"unicode"
+	"unicode/utf8"
+)
+
+// pos is a position in input being scanned
+type pos int
+
+type item struct {
+	typ itemType
+	pos pos
+	val string
+}
+
+func (i item) String() string {
+	switch {
+	case i.typ == itemEOF:
+		return "EOF"
+	case i.typ == itemError:
+		return i.val
+	case len(i.val) > 10:
+		return fmt.Sprintf("%.10q...", i.val)
+	}
+	return fmt.Sprintf("%q", i.val)
+}
+
+type itemType int
+
+const (
+	itemError itemType = iota
+	itemEOF
+	itemVariable
+	itemValue
+	itemEndSplit
+	// PKGBUILD variables
+	itemPkgname      // pkgname variable
+	itemPkgver       // pkgver variable
+	itemPkgrel       // pkgrel variable
+	itemPkgdir       // pkgdir variable
+	itemEpoch        // epoch variable
+	itemPkgbase      // pkgbase variable
+	itemPkgdesc      // pkgdesc variable
+	itemArch         // arch variable
+	itemURL          // url variable
+	itemLicense      // license variable
+	itemGroups       // groups variable
+	itemDepends      // depends variable
+	itemOptdepends   // optdepends variable
+	itemMakedepends  // makedepends variable
+	itemCheckdepends // checkdepends variable
+	itemProvides     // provides variable
+	itemConflicts    // conflicts variable
+	itemReplaces     // replaces variable
+	itemBackup       // backup variable
+	itemOptions      // options variable
+	itemInstall      // install variable
+	itemChangelog    // changelog variable
+	itemSource       // source variable
+	itemNoextract    // noextract variable
+	itemMd5sums      // md5sums variable
+	itemSha1sums     // sha1sums variable
+	itemSha224sums   // sha224sums variable
+	itemSha256sums   // sha256sums variable
+	itemSha384sums   // sha384sums variable
+	itemSha512sums   // sha512sums variable
+	itemValidpgpkeys // validpgpkeys variable
+)
+
+// PKGBUILD variables
+var variables = map[string]itemType{
+	"pkgname":      itemPkgname,
+	"pkgver":       itemPkgver,
+	"pkgrel":       itemPkgrel,
+	"pkgdir":       itemPkgdir,
+	"epoch":        itemEpoch,
+	"pkgbase":      itemPkgbase,
+	"pkgdesc":      itemPkgdesc,
+	"arch":         itemArch,
+	"url":          itemURL,
+	"license":      itemLicense,
+	"groups":       itemGroups,
+	"depends":      itemDepends,
+	"optdepends":   itemOptdepends,
+	"makedepends":  itemMakedepends,
+	"checkdepends": itemCheckdepends,
+	"provides":     itemProvides,
+	"conflicts":    itemConflicts,
+	"replaces":     itemReplaces,
+	"backup":       itemBackup,
+	"options":      itemOptions,
+	"install":      itemInstall,
+	"changelog":    itemChangelog,
+	"source":       itemSource,
+	"noextract":    itemNoextract,
+	"md5sums":      itemMd5sums,
+	"sha1sums":     itemSha1sums,
+	"sha224sums":   itemSha224sums,
+	"sha256sums":   itemSha256sums,
+	"sha384sums":   itemSha384sums,
+	"sha512sums":   itemSha512sums,
+	"validpgpkeys": itemValidpgpkeys,
+}
+
+const eof = -1
+
+// stateFn represents the state of the scanner as a function that returns the next state
+type stateFn func(*lexer) stateFn
+
+// lexer holds the state of the scanner
+type lexer struct {
+	input   string
+	state   stateFn
+	pos     pos
+	start   pos
+	width   pos
+	lastPos pos
+	items   chan item // channel of scanned items
+}
+
+// next returns the next rune in the input
+func (l *lexer) next() rune {
+	if int(l.pos) >= len(l.input) {
+		l.width = 0
+		return eof
+	}
+	r, w := utf8.DecodeRuneInString(l.input[l.pos:])
+	l.width = pos(w)
+	l.pos += l.width
+	return r
+}
+
+// peek returns but does not consume the next rune in the input
+func (l *lexer) peek() rune {
+	r := l.next()
+	l.backup()
+	return r
+}
+
+// backup steps back one rune. Can only be called once per call of next
+func (l *lexer) backup() {
+	l.pos -= l.width
+}
+
+// emit passes an item back to the client
+func (l *lexer) emit(t itemType) {
+	l.items <- item{t, l.start, l.input[l.start:l.pos]}
+	l.start = l.pos
+}
+
+// ignore skips over the pending input before this point
+func (l *lexer) ignore() {
+	l.start = l.pos
+}
+
+// errorf returns an error token and terminates the scan by passing
+// back a nil pointer that will be the next state, terminating l.nextItem.
+func (l *lexer) errorf(format string, args ...interface{}) stateFn {
+	l.items <- item{itemError, l.start, fmt.Sprintf(format, args...)}
+	return nil
+}
+
+// nextItem returns the next item from the input.
+func (l *lexer) nextItem() item {
+	item := <-l.items
+	l.lastPos = item.pos
+	return item
+}
+
+func lex(input string) *lexer {
+	l := &lexer{
+		input: input,
+		items: make(chan item),
+	}
+	go l.run()
+	return l
+}
+
+func (l *lexer) run() {
+	for l.state = lexEnv; l.state != nil; {
+		l.state = l.state(l)
+	}
+}
+
+func lexEnv(l *lexer) stateFn {
+	var r rune
+	for {
+		switch r = l.next(); {
+		case r == eof:
+			l.emit(itemEOF)
+			return nil
+		case isAlphaNumericUnderscore(r):
+			return lexVariable
+		case r == '\n':
+			if l.input[l.start:l.pos] == "\n\n" {
+				l.ignore()
+				l.emit(itemEndSplit)
+			}
+		case r == '\t':
+			l.ignore()
+		case r == '#':
+			return lexComment
+		default:
+			l.errorf("unable to parse character: %c", r)
+		}
+	}
+}
+
+func lexComment(l *lexer) stateFn {
+	for {
+		switch l.next() {
+		case '\n':
+			l.ignore()
+			return lexEnv
+		case eof:
+			l.emit(itemEOF)
+			return nil
+		}
+	}
+}
+
+func lexVariable(l *lexer) stateFn {
+	for {
+		switch r := l.next(); {
+		case isAlphaNumericUnderscore(r):
+			// absorb
+		case r == ' ' && l.peek() == '=':
+			l.backup()
+			variable := l.input[l.start:l.pos]
+
+			// strip arch from source_arch like constructs
+			witharch := strings.SplitN(variable, "_", 2)
+			if len(witharch) == 2 {
+				if _, ok := archs[witharch[1]]; ok {
+					variable = witharch[0]
+				}
+			}
+
+			if _, ok := variables[variable]; ok {
+				l.emit(variables[variable])
+				// TODO to cut off ' = '
+				l.next()
+				l.next()
+				l.next()
+				l.ignore()
+				return lexValue
+			}
+			return l.errorf("invalid variable: %s", variable)
+		default:
+			pattern := l.input[l.start:l.pos]
+			return l.errorf("invalid pattern: %s", pattern)
+		}
+	}
+}
+
+func lexValue(l *lexer) stateFn {
+	for {
+		switch l.next() {
+		case '\n':
+			l.backup()
+			l.emit(itemValue)
+			return lexEnv
+		}
+	}
+}
+
+// isAlphaNumericUnderscore reports whether r is an alphabetic, digit, or underscore.
+func isAlphaNumericUnderscore(r rune) bool {
+	return r == '_' || unicode.IsLetter(r) || unicode.IsDigit(r)
+}

+ 530 - 0
vendor/github.com/mikkeloscar/gopkgbuild/pkgbuild.go

@@ -0,0 +1,530 @@
+package pkgbuild
+
+import (
+	"bytes"
+	"fmt"
+	"io/ioutil"
+	"strconv"
+	"strings"
+)
+
+// Arch is a system architecture
+type Arch uint8
+
+const (
+	// Any architecture
+	Any Arch = iota
+	// I686 architecture
+	I686
+	// X8664 x86_64 (64bit) architecture
+	X8664
+	// ARMv5 architecture (archlinux-arm)
+	ARMv5
+	// ARMv6h architecture (archlinux-arm)
+	ARMv6h
+	// ARMv7h architecture (archlinux-arm)
+	ARMv7h
+	// ARMv8 architecture (64bit) (archlinux-arm)
+	ARMv8
+	// MIPS64 architecture
+	MIPS64
+)
+
+var archs = map[string]Arch{
+	"any":      Any,
+	"i686":     I686,
+	"x86":      I686,
+	"x86_64":   X8664,
+	"aarch64":  ARMv8,
+	"arm":      ARMv5,
+	"armv5":    ARMv5,
+	"armv6h":   ARMv6h,
+	"armv7h":   ARMv7h,
+	"mips64el": MIPS64,
+}
+
+// Dependency describes a dependency with min and max version, if any.
+type Dependency struct {
+	Name   string           // dependency name
+	MinVer *CompleteVersion // min version
+	sgt    bool             // defines if min version is strictly greater than
+	MaxVer *CompleteVersion // max version
+	slt    bool             // defines if max version is strictly less than
+}
+
+// PKGBUILD is a struct describing a parsed PKGBUILD file.
+// Required fields are:
+//	pkgname
+//	pkgver
+//	pkgrel
+//	arch
+//	(license) - not required but recommended
+//
+// parsing a PKGBUILD file without these fields will fail
+type PKGBUILD struct {
+	Pkgnames     []string
+	Pkgver       Version // required
+	Pkgrel       int     // required
+	Pkgdir       string
+	Epoch        int
+	Pkgbase      string
+	Pkgdesc      string
+	Arch         []Arch // required
+	URL          string
+	License      []string // recommended
+	Groups       []string
+	Depends      []*Dependency
+	Optdepends   []string
+	Makedepends  []*Dependency
+	Checkdepends []*Dependency
+	Provides     []string
+	Conflicts    []string
+	Replaces     []string
+	Backup       []string
+	Options      []string
+	Install      string
+	Changelog    string
+	Source       []string
+	Noextract    []string
+	Md5sums      []string
+	Sha1sums     []string
+	Sha224sums   []string
+	Sha256sums   []string
+	Sha384sums   []string
+	Sha512sums   []string
+	Validpgpkeys []string
+}
+
+// Newer is true if p has a higher version number than p2
+func (p *PKGBUILD) Newer(p2 *PKGBUILD) bool {
+	if p.Epoch < p2.Epoch {
+		return false
+	}
+
+	if p.Pkgver.bigger(p2.Pkgver) {
+		return true
+	}
+
+	if p2.Pkgver.bigger(p.Pkgver) {
+		return false
+	}
+
+	return p.Pkgrel > p2.Pkgrel
+}
+
+// Older is true if p has a smaller version number than p2
+func (p *PKGBUILD) Older(p2 *PKGBUILD) bool {
+	if p.Epoch < p2.Epoch {
+		return true
+	}
+
+	if p2.Pkgver.bigger(p.Pkgver) {
+		return true
+	}
+
+	if p.Pkgver.bigger(p2.Pkgver) {
+		return false
+	}
+
+	return p.Pkgrel < p2.Pkgrel
+}
+
+// Version returns the full version of the PKGBUILD (including epoch and rel)
+func (p *PKGBUILD) Version() string {
+	if p.Epoch > 0 {
+		return fmt.Sprintf("%d:%s-%d", p.Epoch, p.Pkgver, p.Pkgrel)
+	}
+
+	return fmt.Sprintf("%s-%d", p.Pkgver, p.Pkgrel)
+}
+
+// CompleteVersion returns a Complete version struct including version, rel and
+// epoch.
+func (p *PKGBUILD) CompleteVersion() CompleteVersion {
+	return CompleteVersion{
+		Version: p.Pkgver,
+		Epoch:   uint8(p.Epoch),
+		Pkgrel:  uint8(p.Pkgrel),
+	}
+}
+
+// BuildDepends is Depends, MakeDepends and CheckDepends combined.
+func (p *PKGBUILD) BuildDepends() []*Dependency {
+	// TODO real merge
+	deps := make([]*Dependency, len(p.Depends)+len(p.Makedepends)+len(p.Checkdepends))
+
+	deps = append(p.Depends, p.Makedepends...)
+	deps = append(deps, p.Checkdepends...)
+
+	return deps
+}
+
+// IsDevel returns true if package contains devel packages (-{bzr,git,svn,hg})
+// TODO: more robust check.
+func (p *PKGBUILD) IsDevel() bool {
+	for _, name := range p.Pkgnames {
+		if strings.HasSuffix(name, "-git") {
+			return true
+		}
+
+		if strings.HasSuffix(name, "-svn") {
+			return true
+		}
+
+		if strings.HasSuffix(name, "-hg") {
+			return true
+		}
+
+		if strings.HasSuffix(name, "-bzr") {
+			return true
+		}
+	}
+
+	return false
+}
+
+// MustParseSRCINFO must parse the .SRCINFO given by path or it will panic
+func MustParseSRCINFO(path string) *PKGBUILD {
+	pkgbuild, err := ParseSRCINFO(path)
+	if err != nil {
+		panic(err)
+	}
+	return pkgbuild
+}
+
+// ParseSRCINFO parses .SRCINFO file given by path.
+// This is a safe alternative to ParsePKGBUILD given that a .SRCINFO file is
+// available
+func ParseSRCINFO(path string) (*PKGBUILD, error) {
+	f, err := ioutil.ReadFile(path)
+	if err != nil {
+		return nil, fmt.Errorf("unable to read file: %s, %s", path, err.Error())
+	}
+
+	return parsePKGBUILD(string(f))
+}
+
+// parse a PKGBUILD and check that the required fields has a non-empty value
+func parsePKGBUILD(input string) (*PKGBUILD, error) {
+	pkgb, err := parse(input)
+	if err != nil {
+		return nil, err
+	}
+
+	if !validPkgver(string(pkgb.Pkgver)) {
+		return nil, fmt.Errorf("invalid pkgver: %s", pkgb.Pkgver)
+	}
+
+	if len(pkgb.Arch) == 0 {
+		return nil, fmt.Errorf("Arch missing")
+	}
+
+	if len(pkgb.Pkgnames) == 0 {
+		return nil, fmt.Errorf("missing pkgname")
+	}
+
+	for _, name := range pkgb.Pkgnames {
+		if !validPkgname(name) {
+			return nil, fmt.Errorf("invalid pkgname: %s", name)
+		}
+	}
+
+	return pkgb, nil
+}
+
+// parses a SRCINFO formatted PKGBUILD
+func parse(input string) (*PKGBUILD, error) {
+	var pkgbuild *PKGBUILD
+	var next item
+
+	lexer := lex(input)
+Loop:
+	for {
+		token := lexer.nextItem()
+		switch token.typ {
+		case itemPkgbase:
+			next = lexer.nextItem()
+			pkgbuild = &PKGBUILD{Epoch: 0, Pkgbase: next.val}
+		case itemPkgname:
+			next = lexer.nextItem()
+			pkgbuild.Pkgnames = append(pkgbuild.Pkgnames, next.val)
+		case itemPkgver:
+			next = lexer.nextItem()
+			version, err := parseVersion(next.val)
+			if err != nil {
+				return nil, err
+			}
+			pkgbuild.Pkgver = version
+		case itemPkgrel:
+			next = lexer.nextItem()
+			rel, err := strconv.ParseInt(next.val, 10, 0)
+			if err != nil {
+				return nil, err
+			}
+			pkgbuild.Pkgrel = int(rel)
+		case itemPkgdir:
+			next = lexer.nextItem()
+			pkgbuild.Pkgdir = next.val
+		case itemEpoch:
+			next = lexer.nextItem()
+			epoch, err := strconv.ParseInt(next.val, 10, 0)
+			if err != nil {
+				return nil, err
+			}
+
+			if epoch < 0 {
+				return nil, fmt.Errorf("invalid epoch: %d", epoch)
+			}
+			pkgbuild.Epoch = int(epoch)
+		case itemPkgdesc:
+			next = lexer.nextItem()
+			pkgbuild.Pkgdesc = next.val
+		case itemArch:
+			next = lexer.nextItem()
+			if arch, ok := archs[next.val]; ok {
+				pkgbuild.Arch = append(pkgbuild.Arch, arch)
+			} else {
+				return nil, fmt.Errorf("invalid Arch: %s", next.val)
+			}
+		case itemURL:
+			next = lexer.nextItem()
+			pkgbuild.URL = next.val
+		case itemLicense:
+			next = lexer.nextItem()
+			pkgbuild.License = append(pkgbuild.License, next.val)
+		case itemGroups:
+			next = lexer.nextItem()
+			pkgbuild.Groups = append(pkgbuild.Groups, next.val)
+		case itemDepends:
+			next = lexer.nextItem()
+			deps, err := parseDependency(next.val, pkgbuild.Depends)
+			if err != nil {
+				return nil, err
+			}
+			pkgbuild.Depends = deps
+		case itemOptdepends:
+			next = lexer.nextItem()
+			pkgbuild.Optdepends = append(pkgbuild.Optdepends, next.val)
+		case itemMakedepends:
+			next = lexer.nextItem()
+			deps, err := parseDependency(next.val, pkgbuild.Makedepends)
+			if err != nil {
+				return nil, err
+			}
+			pkgbuild.Makedepends = deps
+		case itemCheckdepends:
+			next = lexer.nextItem()
+			deps, err := parseDependency(next.val, pkgbuild.Checkdepends)
+			if err != nil {
+				return nil, err
+			}
+			pkgbuild.Checkdepends = deps
+		case itemProvides:
+			next = lexer.nextItem()
+			pkgbuild.Provides = append(pkgbuild.Provides, next.val)
+		case itemConflicts:
+			next = lexer.nextItem()
+			pkgbuild.Conflicts = append(pkgbuild.Conflicts, next.val)
+		case itemReplaces:
+			next = lexer.nextItem()
+			pkgbuild.Replaces = append(pkgbuild.Replaces, next.val)
+		case itemBackup:
+			next = lexer.nextItem()
+			pkgbuild.Backup = append(pkgbuild.Backup, next.val)
+		case itemOptions:
+			next = lexer.nextItem()
+			pkgbuild.Options = append(pkgbuild.Options, next.val)
+		case itemInstall:
+			next = lexer.nextItem()
+			pkgbuild.Install = next.val
+		case itemChangelog:
+			next = lexer.nextItem()
+			pkgbuild.Changelog = next.val
+		case itemSource:
+			next = lexer.nextItem()
+			pkgbuild.Source = append(pkgbuild.Source, next.val)
+		case itemNoextract:
+			next = lexer.nextItem()
+			pkgbuild.Noextract = append(pkgbuild.Noextract, next.val)
+		case itemMd5sums:
+			next = lexer.nextItem()
+			pkgbuild.Md5sums = append(pkgbuild.Md5sums, next.val)
+		case itemSha1sums:
+			next = lexer.nextItem()
+			pkgbuild.Sha1sums = append(pkgbuild.Sha1sums, next.val)
+		case itemSha224sums:
+			next = lexer.nextItem()
+			pkgbuild.Sha224sums = append(pkgbuild.Sha224sums, next.val)
+		case itemSha256sums:
+			next = lexer.nextItem()
+			pkgbuild.Sha256sums = append(pkgbuild.Sha256sums, next.val)
+		case itemSha384sums:
+			next = lexer.nextItem()
+			pkgbuild.Sha384sums = append(pkgbuild.Sha384sums, next.val)
+		case itemSha512sums:
+			next = lexer.nextItem()
+			pkgbuild.Sha512sums = append(pkgbuild.Sha512sums, next.val)
+		case itemValidpgpkeys:
+			next = lexer.nextItem()
+			pkgbuild.Validpgpkeys = append(pkgbuild.Validpgpkeys, next.val)
+		case itemEndSplit:
+		case itemError:
+			return nil, fmt.Errorf(token.val)
+		case itemEOF:
+			break Loop
+		default:
+			return nil, fmt.Errorf(token.val)
+		}
+	}
+	return pkgbuild, nil
+}
+
+// parse and validate a version string
+func parseVersion(s string) (Version, error) {
+	if validPkgver(s) {
+		return Version(s), nil
+	}
+
+	return "", fmt.Errorf("invalid version string: %s", s)
+}
+
+// check if name is a valid pkgname format
+func validPkgname(name string) bool {
+	if len(name) < 1 {
+		return false
+	}
+
+	if name[0] == '-' {
+		return false
+	}
+
+	for _, r := range name {
+		if !isValidPkgnameChar(uint8(r)) {
+			return false
+		}
+	}
+
+	return true
+}
+
+// check if version is a valid pkgver format
+func validPkgver(version string) bool {
+	if len(version) < 1 {
+		return false
+	}
+
+	if !isAlphaNumeric(version[0]) {
+		return false
+	}
+
+	for _, r := range version[1:] {
+		if !isValidPkgverChar(uint8(r)) {
+			return false
+		}
+	}
+
+	return true
+}
+
+// ParseDeps parses a string slice of dependencies into a slice of Dependency
+// objects.
+func ParseDeps(deps []string) ([]*Dependency, error) {
+	var err error
+	dependencies := make([]*Dependency, 0)
+
+	for _, dep := range deps {
+		dependencies, err = parseDependency(dep, dependencies)
+		if err != nil {
+			return nil, err
+		}
+	}
+
+	return dependencies, nil
+}
+
+// parse dependency with possible version restriction
+func parseDependency(dep string, deps []*Dependency) ([]*Dependency, error) {
+	var name string
+	var dependency *Dependency
+
+	if dep[0] == '-' {
+		return nil, fmt.Errorf("invalid dependency name")
+	}
+
+	i := 0
+	for _, c := range dep {
+		if !isValidPkgnameChar(uint8(c)) {
+			break
+		}
+		i++
+	}
+
+	// check if the dependency has been set before
+	name = dep[0:i]
+	for _, d := range deps {
+		if d.Name == name {
+			dependency = d
+		}
+	}
+
+	if dependency == nil {
+		dependency = &Dependency{
+			Name: name,
+			sgt:  false,
+			slt:  false,
+		}
+		deps = append(deps, dependency)
+	}
+
+	if len(dep) == len(name) {
+		return deps, nil
+	}
+
+	var eq bytes.Buffer
+	for _, c := range dep[i:] {
+		if c == '<' || c == '>' || c == '=' {
+			i++
+			eq.WriteRune(c)
+			continue
+		}
+		break
+	}
+
+	version, err := NewCompleteVersion(dep[i:])
+	if err != nil {
+		return nil, err
+	}
+
+	switch eq.String() {
+	case "==":
+		dependency.MinVer = version
+		dependency.MaxVer = version
+	case "<=":
+		dependency.MaxVer = version
+	case ">=":
+		dependency.MinVer = version
+	case "<":
+		dependency.MaxVer = version
+		dependency.slt = true
+	case ">":
+		dependency.MinVer = version
+		dependency.sgt = true
+	}
+
+	return deps, nil
+}
+
+// isLowerAlpha reports whether c is a lowercase alpha character
+func isLowerAlpha(c uint8) bool {
+	return 'a' <= c && c <= 'z'
+}
+
+// check if c is a valid pkgname char
+func isValidPkgnameChar(c uint8) bool {
+	return isLowerAlpha(c) || isDigit(c) || c == '@' || c == '.' || c == '_' || c == '+' || c == '-'
+}
+
+// check if c is a valid pkgver char
+func isValidPkgverChar(c uint8) bool {
+	return isAlphaNumeric(c) || c == '_' || c == '+' || c == '.'
+}

+ 211 - 0
vendor/github.com/mikkeloscar/gopkgbuild/pkgbuild_test.go

@@ -0,0 +1,211 @@
+package pkgbuild
+
+import "testing"
+
+// Test version parsing
+func TestVersionParsing(t *testing.T) {
+	versions := map[string]bool{
+		"1.0beta":   true,
+		"1.0.0.0.2": true,
+		"a.3_4":     true,
+		"A.2":       true,
+		"_1.2":      false,
+		".2":        false,
+		"a.2Ø":      false,
+		"1.?":       false,
+		"1.-":       false,
+	}
+
+	for version, valid := range versions {
+		_, err := parseVersion(version)
+		if err != nil && valid {
+			t.Errorf("Version string '%s' should parse", version)
+		}
+
+		if err == nil && !valid {
+			t.Errorf("Version string '%s' should not parse", version)
+		}
+	}
+}
+
+// Test complete-version parsing
+func TestCompleteVersionParsing(t *testing.T) {
+	versions := map[string]*CompleteVersion{
+		"1:1.0beta": &CompleteVersion{Version("1.0beta"), 1, 0},
+		"1.0":       &CompleteVersion{Version("1.0"), 0, 0},
+		"2.3-2":     &CompleteVersion{Version("2.3"), 0, 2},
+		"1::":       nil,
+		"4.3--1":    nil,
+		"4.1-a":     nil,
+		"f:2.3":     nil,
+		"1.?":       nil,
+	}
+
+	for version, expected := range versions {
+		ver, err := NewCompleteVersion(version)
+		if err != nil && expected != nil {
+			t.Errorf("CompleteVersion string '%s' should not parse", version)
+		}
+
+		if err == nil && expected != nil {
+			if ver.Version != expected.Version || ver.Epoch != expected.Epoch || ver.Pkgrel != expected.Pkgrel {
+				t.Errorf("CompleteVersion string '%s' should parse", version)
+			}
+		}
+	}
+}
+
+// Test Newer method
+func TestNewer(t *testing.T) {
+	a := &PKGBUILD{
+		Epoch:  0,
+		Pkgver: Version("1.0"),
+		Pkgrel: 1,
+	}
+	b := &PKGBUILD{
+		Epoch:  0,
+		Pkgver: Version("2.0"),
+		Pkgrel: 1,
+	}
+	c := &PKGBUILD{
+		Epoch:  1,
+		Pkgver: Version("1.0"),
+		Pkgrel: 1,
+	}
+	d := &PKGBUILD{
+		Epoch:  0,
+		Pkgver: Version("1.0"),
+		Pkgrel: 2,
+	}
+
+	if a.Newer(b) {
+		t.Errorf("a (%s) should not be newer than b (%s)", a.Version(), b.Version())
+	}
+
+	if b.Newer(c) {
+		t.Errorf("b (%s) should not be newer than c (%s)", b.Version(), c.Version())
+	}
+
+	if a.Newer(d) {
+		t.Errorf("a (%s) should not be newer than d (%s)", a.Version(), d.Version())
+	}
+
+	if a.Newer(a) {
+		t.Errorf("a (%s) should not be newer than itself", a.Version())
+	}
+}
+
+// Test Older method
+func TestOlder(t *testing.T) {
+	a := &PKGBUILD{
+		Epoch:  0,
+		Pkgver: Version("1.0"),
+		Pkgrel: 1,
+	}
+	b := &PKGBUILD{
+		Epoch:  0,
+		Pkgver: Version("2.0"),
+		Pkgrel: 1,
+	}
+	c := &PKGBUILD{
+		Epoch:  1,
+		Pkgver: Version("1.0"),
+		Pkgrel: 1,
+	}
+	d := &PKGBUILD{
+		Epoch:  0,
+		Pkgver: Version("1.0"),
+		Pkgrel: 2,
+	}
+
+	if !a.Older(b) {
+		t.Errorf("a (%s) should be older than b (%s)", a.Version(), b.Version())
+	}
+
+	if !b.Older(c) {
+		t.Errorf("b (%s) should be older than c (%s)", b.Version(), c.Version())
+	}
+
+	if !a.Older(d) {
+		t.Errorf("a (%s) should be older than d (%s)", a.Version(), d.Version())
+	}
+
+	if d.Older(d) {
+		t.Errorf("d (%s) should not be older than itself", d.Version())
+	}
+}
+
+// Test Version method
+func TestVersionMethod(t *testing.T) {
+	a := &PKGBUILD{
+		Epoch:  0,
+		Pkgver: Version("1.0"),
+		Pkgrel: 1,
+	}
+
+	version := "1.0-1"
+
+	if a.Version() != version {
+		t.Errorf("a (%s) should be %s", a.Version(), version)
+	}
+
+	b := &PKGBUILD{
+		Epoch:  4,
+		Pkgver: Version("1.0"),
+		Pkgrel: 1,
+	}
+
+	version = "4:1.0-1"
+
+	if b.Version() != version {
+		t.Errorf("a (%s) should be %s", b.Version(), version)
+	}
+}
+
+// Test random SRCINFO files based on pkgbuilds from Arch core
+func TestRandomCoreSRCINFOs(t *testing.T) {
+	srcinfos := []string{
+		"sudo",
+		"pacman",
+		"openssh",
+		"grub",
+		"glibc",
+		"systemd",
+		"linux",
+	}
+
+	for _, srcinfo := range srcinfos {
+		path := "./test_pkgbuilds/SRCINFO_" + srcinfo
+		pkg, err := ParseSRCINFO(path)
+		if err != nil {
+			t.Errorf("PKGBUILD for %s did not parse: %s", srcinfo, err.Error())
+		}
+
+		if pkg.Pkgbase != srcinfo {
+			t.Errorf("pkgbase for %s should be %s", srcinfo, pkg.Pkgbase)
+		}
+	}
+}
+
+func TestParseDependency(t *testing.T) {
+	deps := make([]*Dependency, 0)
+	_, err := parseDependency("linux-mainline-headers<4.6rc1", deps)
+	if err != nil {
+		t.Errorf("could not parse dependency %s: %s", "bla", err.Error())
+	}
+
+	_, err = parseDependency("linux-mainline-headers<=4.6rc1", deps)
+	if err != nil {
+		t.Errorf("could not parse dependency %s: %s", "bla", err.Error())
+	}
+
+	_, err = parseDependency("linux-mainline-headers>=4.6rc1", deps)
+	if err != nil {
+		t.Errorf("could not parse dependency %s: %s", "bla", err.Error())
+	}
+
+	_, err = parseDependency("linux-mainline-headers==4.6rc1", deps)
+	if err != nil {
+		t.Errorf("could not parse dependency %s: %s", "bla", err.Error())
+	}
+}

+ 150 - 0
vendor/github.com/mikkeloscar/gopkgbuild/test_pkgbuilds/PKGBUILD_glibc

@@ -0,0 +1,150 @@
+# $Id: PKGBUILD 227086 2014-11-25 12:39:13Z allan $
+# Maintainer: Allan McRae <allan@archlinux.org>
+
+# toolchain build order: linux-api-headers->glibc->binutils->gcc->binutils->glibc
+# NOTE: valgrind requires rebuilt with each major glibc version
+
+# NOTE: adjust version in install script when locale files are updated
+
+pkgname=glibc
+pkgver=2.20
+pkgrel=4
+pkgdesc="GNU C Library"
+arch=('i686' 'x86_64')
+url="http://www.gnu.org/software/libc"
+license=('GPL' 'LGPL')
+groups=('base')
+depends=('linux-api-headers>=3.16' 'tzdata' 'filesystem>=2013.01')
+makedepends=('gcc>=4.9')
+backup=(etc/gai.conf
+        etc/locale.gen
+        etc/nscd.conf)
+options=('!strip' 'staticlibs')
+install=glibc.install
+source=(http://ftp.gnu.org/gnu/libc/${pkgname}-${pkgver}.tar.xz{,.sig}
+        glibc-2.20-roundup.patch
+        locale.gen.txt
+        locale-gen)
+md5sums=('948a6e06419a01bd51e97206861595b0'
+         'SKIP'
+         '8cfa2a0fa2a9aad8b86a138587d6261f'
+         '07ac979b6ab5eeb778d55f041529d623'
+         '476e9113489f93b348b21e144b6a8fcf')
+
+validpgpkeys=('F37CDAB708E65EA183FD1AF625EF0A436C2A4AFF')  # Carlos O'Donell
+
+prepare() {
+  cd ${srcdir}/glibc-${pkgver}
+
+  # glibc-2.20..d73ac1bb
+  patch -p1 -i $srcdir/glibc-2.20-roundup.patch
+
+  mkdir ${srcdir}/glibc-build
+}
+
+build() {
+  cd ${srcdir}/glibc-build
+
+  if [[ ${CARCH} = "i686" ]]; then
+    # Hack to fix NPTL issues with Xen, only required on 32bit platforms
+    # TODO: make separate glibc-xen package for i686
+    export CFLAGS="${CFLAGS} -mno-tls-direct-seg-refs"
+  fi
+
+  echo "slibdir=/usr/lib" >> configparms
+  echo "rtlddir=/usr/lib" >> configparms
+  echo "sbindir=/usr/bin" >> configparms
+  echo "rootsbindir=/usr/bin" >> configparms
+
+  # remove hardening options for building libraries
+  CFLAGS=${CFLAGS/-fstack-protector-strong/}
+  CPPFLAGS=${CPPFLAGS/-D_FORTIFY_SOURCE=2/}
+
+  ${srcdir}/${pkgname}-${pkgver}/configure --prefix=/usr \
+      --libdir=/usr/lib --libexecdir=/usr/lib \
+      --with-headers=/usr/include \
+      --with-bugurl=https://bugs.archlinux.org/ \
+      --enable-add-ons \
+      --enable-obsolete-rpc \
+      --enable-kernel=2.6.32 \
+      --enable-bind-now --disable-profile \
+      --enable-stackguard-randomization \
+      --enable-lock-elision \
+      --enable-multi-arch
+
+  # build libraries with hardening disabled
+  echo "build-programs=no" >> configparms
+  make
+
+  # re-enable hardening for programs
+  sed -i "/build-programs=/s#no#yes#" configparms
+  echo "CC += -fstack-protector-strong -D_FORTIFY_SOURCE=2" >> configparms
+  echo "CXX += -fstack-protector-strong -D_FORTIFY_SOURCE=2" >> configparms
+  make
+
+  # remove harding in preparation to run test-suite
+  sed -i '5,7d' configparms
+}
+
+check() {
+  # the linker commands need to be reordered - fixed in 2.19
+  LDFLAGS=${LDFLAGS/--as-needed,/}
+
+  cd ${srcdir}/glibc-build
+
+  # tst-cleanupx4 failure on i686 is "expected"
+  make check || true
+}
+
+package() {
+  cd ${srcdir}/glibc-build
+
+  install -dm755 ${pkgdir}/etc
+  touch ${pkgdir}/etc/ld.so.conf
+
+  make install_root=${pkgdir} install
+
+  rm -f ${pkgdir}/etc/ld.so.{cache,conf}
+
+  install -dm755 ${pkgdir}/usr/lib/{locale,systemd/system,tmpfiles.d}
+
+  install -m644 ${srcdir}/${pkgname}-${pkgver}/nscd/nscd.conf ${pkgdir}/etc/nscd.conf
+  install -m644 ${srcdir}/${pkgname}-${pkgver}/nscd/nscd.service ${pkgdir}/usr/lib/systemd/system
+  install -m644 ${srcdir}/${pkgname}-${pkgver}/nscd/nscd.tmpfiles ${pkgdir}/usr/lib/tmpfiles.d/nscd.conf
+
+  install -m644 ${srcdir}/${pkgname}-${pkgver}/posix/gai.conf ${pkgdir}/etc/gai.conf
+
+  install -m755 ${srcdir}/locale-gen ${pkgdir}/usr/bin
+
+  # create /etc/locale.gen
+  install -m644 ${srcdir}/locale.gen.txt ${pkgdir}/etc/locale.gen
+  sed -e '1,3d' -e 's|/| |g' -e 's|\\| |g' -e 's|^|#|g' \
+    ${srcdir}/glibc-${pkgver}/localedata/SUPPORTED >> ${pkgdir}/etc/locale.gen
+
+  # remove the static libraries that have a shared counterpart
+  # libc, libdl, libm and libpthread are required for toolchain testsuites
+  # in addition libcrypt appears widely required
+  rm $pkgdir/usr/lib/lib{anl,BrokenLocale,nsl,resolv,rt,util}.a
+
+  # Do not strip the following files for improved debugging support
+  # ("improved" as in not breaking gdb and valgrind...):
+  #   ld-${pkgver}.so
+  #   libc-${pkgver}.so
+  #   libpthread-${pkgver}.so
+  #   libthread_db-1.0.so
+
+  cd $pkgdir
+  strip $STRIP_BINARIES usr/bin/{gencat,getconf,getent,iconv,iconvconfig} \
+                        usr/bin/{ldconfig,locale,localedef,nscd,makedb} \
+                        usr/bin/{pcprofiledump,pldd,rpcgen,sln,sprof} \
+                        usr/lib/getconf/*
+  [[ $CARCH = "i686" ]] && strip $STRIP_BINARIES usr/bin/lddlibc4
+
+  strip $STRIP_STATIC usr/lib/*.a
+
+  strip $STRIP_SHARED usr/lib/{libanl,libBrokenLocale,libcidn,libcrypt}-*.so \
+                      usr/lib/libnss_{compat,db,dns,files,hesiod,nis,nisplus}-*.so \
+                      usr/lib/{libdl,libm,libnsl,libresolv,librt,libutil}-*.so \
+                      usr/lib/{libmemusage,libpcprofile,libSegFault}.so \
+                      usr/lib/{audit,gconv}/*.so
+}

+ 389 - 0
vendor/github.com/mikkeloscar/gopkgbuild/test_pkgbuilds/PKGBUILD_grub

@@ -0,0 +1,389 @@
+# Maintainer : Tobias Powalowski <tpowa@archlinux.org>
+# Maintainer : Ronald van Haren <ronald.archlinux.org>
+# Contributor: Keshav Amburay <(the ddoott ridikulus ddoott rat) (aatt) (gemmaeiil) (ddoott) (ccoomm)>
+
+## "1" to enable IA32-EFI build in Arch x86_64, "0" to disable
+_IA32_EFI_IN_ARCH_X64="1"
+
+## "1" to enable EMU build, "0" to disable
+_GRUB_EMU_BUILD="0"
+
+_pkgver="2.02"
+_GRUB_GIT_TAG="grub-2.02-beta2"
+
+_UNIFONT_VER="6.3.20131217"
+
+[[ "${CARCH}" == "x86_64" ]] && _EFI_ARCH="x86_64"
+[[ "${CARCH}" == "i686" ]] && _EFI_ARCH="i386"
+
+[[ "${CARCH}" == "x86_64" ]] && _EMU_ARCH="x86_64"
+[[ "${CARCH}" == "i686" ]] && _EMU_ARCH="i386"
+
+pkgname="grub"
+pkgdesc="GNU GRand Unified Bootloader (2)"
+pkgver=2.02.beta2
+pkgrel=5
+epoch="1"
+url="https://www.gnu.org/software/grub/"
+arch=('x86_64' 'i686')
+license=('GPL3')
+backup=('boot/grub/grub.cfg' 'etc/default/grub' 'etc/grub.d/40_custom')
+install="${pkgname}.install"
+options=('!makeflags')
+
+conflicts=('grub-common' 'grub-bios' 'grub-emu' "grub-efi-${_EFI_ARCH}" 'grub-legacy')
+replaces=('grub-common' 'grub-bios' 'grub-emu' "grub-efi-${_EFI_ARCH}")
+provides=('grub-common' 'grub-bios' 'grub-emu' "grub-efi-${_EFI_ARCH}")
+
+makedepends=('git' 'rsync' 'xz' 'freetype2' 'ttf-dejavu' 'python' 'autogen'
+             'texinfo' 'help2man' 'gettext' 'device-mapper' 'fuse')
+depends=('sh' 'xz' 'gettext' 'device-mapper')
+optdepends=('freetype2: For grub-mkfont usage'
+            'fuse: For grub-mount usage'
+            'dosfstools: For grub-mkrescue FAT FS and EFI support' 
+            'efibootmgr: For grub-install EFI support'
+            'libisoburn: Provides xorriso for generating grub rescue iso using grub-mkrescue'
+            'os-prober: To detect other OSes when generating grub.cfg in BIOS systems'
+            'mtools: For grub-mkrescue FAT FS support')
+
+if [[ "${_GRUB_EMU_BUILD}" == "1" ]]; then
+    makedepends+=('libusbx' 'sdl')
+    optdepends+=('libusbx: For grub-emu USB support'
+                 'sdl: For grub-emu SDL support')
+fi
+
+source=("grub-${_pkgver}::git+git://git.sv.gnu.org/grub.git#tag=${_GRUB_GIT_TAG}"
+        "grub-extras::git+git://git.sv.gnu.org/grub-extras.git#branch=master"
+        "http://ftp.gnu.org/gnu/unifont/unifont-${_UNIFONT_VER}/unifont-${_UNIFONT_VER}.bdf.gz"
+        "http://ftp.gnu.org/gnu/unifont/unifont-${_UNIFONT_VER}/unifont-${_UNIFONT_VER}.bdf.gz.sig"
+        'grub-10_linux-detect-archlinux-initramfs.patch'
+	'grub-intel-ucode.patch'
+        'grub-add-GRUB_COLOR_variables.patch'
+        '60_memtest86+'
+        'grub.default'
+        'grub.cfg')
+
+md5sums=('SKIP'
+         'SKIP'
+         '728b7439ac733a7c0d56049adec364c7'
+         'SKIP'
+         '945527e0de8d384166a4cf23439ae9ee'
+	 'a678629bc82c4e70c48d28242036d1d7'
+         'e506ae4a9f9f7d1b765febfa84e10d48'
+         'be55eabc102f2c60b38ed35c203686d6'
+         'a03ffd56324520393bf574cefccb893d'
+         'c8b9511586d57d6f2524ae7898397a46')
+
+_pkgver() {
+	cd "${srcdir}/grub-${_pkgver}/"
+	echo "$(git describe --tags)" | sed -e 's|grub.||g' -e 's|-|\.|g'
+}
+
+prepare() {
+	
+	cd "${srcdir}/grub-${_pkgver}/"
+	
+	msg "Patch to load Intel microcode"
+	patch -Np1 -i "${srcdir}/grub-intel-ucode.patch"
+	echo
+
+	msg "Patch to detect of Arch Linux initramfs images by grub-mkconfig"
+	patch -Np1 -i "${srcdir}/grub-10_linux-detect-archlinux-initramfs.patch"
+	echo
+	
+	msg "Patch to enable GRUB_COLOR_* variables in grub-mkconfig"
+	## Based on http://lists.gnu.org/archive/html/grub-devel/2012-02/msg00021.html
+	patch -Np1 -i "${srcdir}/grub-add-GRUB_COLOR_variables.patch"
+	echo
+	
+	msg "Fix DejaVuSans.ttf location so that grub-mkfont can create *.pf2 files for starfield theme"
+	sed 's|/usr/share/fonts/dejavu|/usr/share/fonts/dejavu /usr/share/fonts/TTF|g' -i "${srcdir}/grub-${_pkgver}/configure.ac"
+	
+	msg "Fix mkinitcpio 'rw' FS#36275"
+	sed 's| ro | rw |g' -i "${srcdir}/grub-${_pkgver}/util/grub.d/10_linux.in"
+	
+	msg "Fix OS naming FS#33393"
+	sed 's|GNU/Linux|Linux|' -i "${srcdir}/grub-${_pkgver}/util/grub.d/10_linux.in"
+	
+	# msg "autogen.sh requires python (2/3). since bzr is in makedepends, use python2 and no need to pull python3"
+	# sed 's|python |python2 |g' -i "${srcdir}/grub-${_pkgver}/autogen.sh"
+	
+	msg "Pull in latest language files"
+	./linguas.sh
+	echo
+	
+	msg "Remove not working langs which need LC_ALL=C.UTF-8"
+	sed -e 's#en@cyrillic en@greek##g' -i "${srcdir}/grub-${_pkgver}/po/LINGUAS"
+	
+	msg "Avoid problem with unifont during compile of grub, http://savannah.gnu.org/bugs/?40330 and https://bugs.archlinux.org/task/37847"
+	cp "${srcdir}/unifont-${_UNIFONT_VER}.bdf" "${srcdir}/grub-${_pkgver}/unifont.bdf"
+	
+}
+
+_build_grub-common_and_bios() {
+	
+	msg "Set ARCH dependent variables for bios build"
+	if [[ "${CARCH}" == 'x86_64' ]]; then
+		_EFIEMU="--enable-efiemu"
+	else
+		_EFIEMU="--disable-efiemu"
+	fi
+	
+	msg "Copy the source for building the bios part"
+	cp -r "${srcdir}/grub-${_pkgver}" "${srcdir}/grub-${_pkgver}-bios"
+	cd "${srcdir}/grub-${_pkgver}-bios/"
+	
+	msg "Add the grub-extra sources for bios build"
+	install -d "${srcdir}/grub-${_pkgver}-bios/grub-extras"
+	cp -r "${srcdir}/grub-extras/915resolution" "${srcdir}/grub-${_pkgver}-bios/grub-extras/915resolution"
+	export GRUB_CONTRIB="${srcdir}/grub-${_pkgver}-bios/grub-extras/"
+	
+	msg "Unset all compiler FLAGS for bios build"
+	unset CFLAGS
+	unset CPPFLAGS
+	unset CXXFLAGS
+	unset LDFLAGS
+	unset MAKEFLAGS
+	
+	cd "${srcdir}/grub-${_pkgver}-bios/"
+	
+	msg "Run autogen.sh for bios build"
+	./autogen.sh
+	echo
+	
+	msg "Run ./configure for bios build"
+	./configure \
+		--with-platform="pc" \
+		--target="i386" \
+		"${_EFIEMU}" \
+		--enable-mm-debug \
+		--enable-nls \
+		--enable-device-mapper \
+		--enable-cache-stats \
+		--enable-boot-time \
+		--enable-grub-mkfont \
+		--enable-grub-mount \
+		--prefix="/usr" \
+		--bindir="/usr/bin" \
+		--sbindir="/usr/bin" \
+		--mandir="/usr/share/man" \
+		--infodir="/usr/share/info" \
+		--datarootdir="/usr/share" \
+		--sysconfdir="/etc" \
+	 	--program-prefix="" \
+		--with-bootdir="/boot" \
+		--with-grubdir="grub" \
+		--disable-silent-rules \
+		--disable-werror
+	echo
+	
+	msg "Run make for bios build"
+	make
+	echo
+}
+
+_build_grub-efi() {
+	
+	msg "Copy the source for building the ${_EFI_ARCH} efi part"
+	cp -r "${srcdir}/grub-${_pkgver}" "${srcdir}/grub-${_pkgver}-efi-${_EFI_ARCH}"
+	cd "${srcdir}/grub-${_pkgver}-efi-${_EFI_ARCH}/"
+	
+	msg "Unset all compiler FLAGS for ${_EFI_ARCH} efi build"
+	unset CFLAGS
+	unset CPPFLAGS
+	unset CXXFLAGS
+	unset LDFLAGS
+	unset MAKEFLAGS
+	
+	cd "${srcdir}/grub-${_pkgver}-efi-${_EFI_ARCH}/"
+	
+	msg "Run autogen.sh for ${_EFI_ARCH} efi build"
+	./autogen.sh
+	echo
+	
+	msg "Run ./configure for ${_EFI_ARCH} efi build"
+	./configure \
+		--with-platform="efi" \
+		--target="${_EFI_ARCH}" \
+		--disable-efiemu \
+		--enable-mm-debug \
+		--enable-nls \
+		--enable-device-mapper \
+		--enable-cache-stats \
+		--enable-boot-time \
+		--enable-grub-mkfont \
+		--enable-grub-mount \
+		--prefix="/usr" \
+		--bindir="/usr/bin" \
+		--sbindir="/usr/bin" \
+		--mandir="/usr/share/man" \
+		--infodir="/usr/share/info" \
+		--datarootdir="/usr/share" \
+		--sysconfdir="/etc" \
+		--program-prefix="" \
+		--with-bootdir="/boot" \
+		--with-grubdir="grub" \
+		--disable-silent-rules \
+		--disable-werror
+	echo
+	
+	msg "Run make for ${_EFI_ARCH} efi build"
+	make
+	echo
+	
+}
+
+_build_grub-emu() {
+	
+	msg "Copy the source for building the emu part"
+	cp -r "${srcdir}/grub-${_pkgver}/" "${srcdir}/grub-${_pkgver}-emu/"
+	
+	msg "Unset all compiler FLAGS for emu build"
+	unset CFLAGS
+	unset CPPFLAGS
+	unset CXXFLAGS
+	unset LDFLAGS
+	unset MAKEFLAGS
+	
+	cd "${srcdir}/grub-${_pkgver}-emu/"
+	
+	msg "Run autogen.sh for emu build"
+	./autogen.sh
+	echo
+	
+	msg "Run ./configure for emu build"
+	./configure \
+		--with-platform="emu" \
+		--target="${_EMU_ARCH}" \
+		--enable-mm-debug \
+		--enable-nls \
+		--enable-device-mapper \
+		--enable-cache-stats \
+		--enable-grub-mkfont \
+		--enable-grub-mount \
+		--enable-grub-emu-usb=no \
+		--enable-grub-emu-sdl=no \
+		--disable-grub-emu-pci \
+		--prefix="/usr" \
+		--bindir="/usr/bin" \
+		--sbindir="/usr/bin" \
+		--mandir="/usr/share/man" \
+		--infodir="/usr/share/info" \
+		--datarootdir="/usr/share" \
+		--sysconfdir="/etc" \
+		--program-prefix="" \
+		--with-bootdir="/boot" \
+		--with-grubdir="grub" \
+		--disable-silent-rules \
+		--disable-werror
+	echo
+	
+	msg "Run make for emu build"
+	make
+	echo
+	
+}
+
+build() {
+	
+	cd "${srcdir}/grub-${_pkgver}/"
+	
+	msg "Build grub bios stuff"
+	_build_grub-common_and_bios
+	echo
+	
+	msg "Build grub ${_EFI_ARCH} efi stuff"
+	_build_grub-efi
+	echo
+	
+	if [[ "${CARCH}" == "x86_64" ]] && [[ "${_IA32_EFI_IN_ARCH_X64}" == "1" ]]; then
+		msg "Build grub i386 efi stuff"
+		_EFI_ARCH="i386" _build_grub-efi
+		echo
+	fi
+	
+	if [[ "${_GRUB_EMU_BUILD}" == "1" ]]; then
+		msg "Build grub emu stuff"
+		_build_grub-emu
+		echo
+	fi
+    
+}
+
+_package_grub-common_and_bios() {
+	
+	cd "${srcdir}/grub-${_pkgver}-bios/"
+	
+	msg "Run make install for bios build"
+	make DESTDIR="${pkgdir}/" bashcompletiondir="/usr/share/bash-completion/completions" install
+	echo
+	
+	msg "Remove gdb debugging related files for bios build"
+	rm -f "${pkgdir}/usr/lib/grub/i386-pc"/*.module || true
+	rm -f "${pkgdir}/usr/lib/grub/i386-pc"/*.image || true
+	rm -f "${pkgdir}/usr/lib/grub/i386-pc"/{kernel.exec,gdb_grub,gmodule.pl} || true
+	
+	msg "Install extra /etc/grub.d/ files"
+	install -D -m0755 "${srcdir}/60_memtest86+" "${pkgdir}/etc/grub.d/60_memtest86+"
+	
+	msg "Install /etc/default/grub (used by grub-mkconfig)"
+	install -D -m0644 "${srcdir}/grub.default" "${pkgdir}/etc/default/grub"
+	
+	msg "Install grub.cfg for backup array"
+	install -D -m0644 "${srcdir}/grub.cfg" "${pkgdir}/boot/grub/grub.cfg"
+	
+}
+
+_package_grub-efi() {
+	
+	cd "${srcdir}/grub-${_pkgver}-efi-${_EFI_ARCH}/"
+	
+	msg "Run make install for ${_EFI_ARCH} efi build"
+	make DESTDIR="${pkgdir}/" bashcompletiondir="/usr/share/bash-completion/completions" install
+	echo
+	
+	msg "Remove gdb debugging related files for ${_EFI_ARCH} efi build"
+	rm -f "${pkgdir}/usr/lib/grub/${_EFI_ARCH}-efi"/*.module || true
+	rm -f "${pkgdir}/usr/lib/grub/${_EFI_ARCH}-efi"/*.image || true
+	rm -f "${pkgdir}/usr/lib/grub/${_EFI_ARCH}-efi"/{kernel.exec,gdb_grub,gmodule.pl} || true
+	
+}
+
+_package_grub-emu() {
+	
+	cd "${srcdir}/grub-${_pkgver}-emu/"
+	
+	msg "Run make install for emu build"
+	make DESTDIR="${pkgdir}/" bashcompletiondir="/usr/share/bash-completion/completions" install
+	echo
+	
+	msg "Remove gdb debugging related files for emu build"
+	rm -f "${pkgdir}/usr/lib/grub/${_EMU_ARCH}-emu"/*.module || true
+	rm -f "${pkgdir}/usr/lib/grub/${_EMU_ARCH}-emu"/*.image || true
+	rm -f "${pkgdir}/usr/lib/grub/${_EMU_ARCH}-emu"/{kernel.exec,gdb_grub,gmodule.pl} || true
+	
+}
+
+package() {
+	
+	cd "${srcdir}/grub-${_pkgver}/"
+	
+	msg "Package grub ${_EFI_ARCH} efi stuff"
+	_package_grub-efi
+	
+	if [[ "${CARCH}" == "x86_64" ]] && [[ "${_IA32_EFI_IN_ARCH_X64}" == "1" ]]; then
+		msg "Package grub i386 efi stuff"
+		_EFI_ARCH="i386" _package_grub-efi
+		echo
+	fi
+	
+	if [[ "${_GRUB_EMU_BUILD}" == "1" ]]; then
+		msg "Package grub emu stuff"
+		_package_grub-emu
+		echo
+	fi
+	
+	msg "Package grub bios stuff"
+	_package_grub-common_and_bios
+	
+}

+ 301 - 0
vendor/github.com/mikkeloscar/gopkgbuild/test_pkgbuilds/PKGBUILD_linux

@@ -0,0 +1,301 @@
+# $Id: PKGBUILD 230158 2015-01-28 07:08:45Z tpowa $
+# Maintainer: Tobias Powalowski <tpowa@archlinux.org>
+# Maintainer: Thomas Baechler <thomas@archlinux.org>
+
+pkgbase=linux               # Build stock -ARCH kernel
+#pkgbase=linux-custom       # Build kernel with a different name
+_srcname=linux-3.18
+pkgver=3.18.4
+pkgrel=1
+arch=('i686' 'x86_64')
+url="http://www.kernel.org/"
+license=('GPL2')
+makedepends=('xmlto' 'docbook-xsl' 'kmod' 'inetutils' 'bc')
+options=('!strip')
+source=("https://www.kernel.org/pub/linux/kernel/v3.x/${_srcname}.tar.xz"
+        "https://www.kernel.org/pub/linux/kernel/v3.x/${_srcname}.tar.sign"
+        "https://www.kernel.org/pub/linux/kernel/v3.x/patch-${pkgver}.xz"
+        "https://www.kernel.org/pub/linux/kernel/v3.x/patch-${pkgver}.sign"
+        # the main kernel config files
+        'config' 'config.x86_64'
+        # standard config files for mkinitcpio ramdisk
+        'linux.preset'
+        'change-default-console-loglevel.patch'
+        )
+sha256sums=('becc413cc9e6d7f5cc52a3ce66d65c3725bc1d1cc1001f4ce6c32b69eb188cbd'
+            'SKIP'
+            '57c74ba5266bb10be335a89d30480739b3de67b5a72b3e0b0d37a27775b1862a'
+            'SKIP'
+            'd3794c8b2cd11b71914b41f7a4e861369d4fa3c29fdd9e1d677ff0c2167eeb52'
+            'df7886f5d57f8f85e89987066dfa5c316e922dc0b22e6e6ad01331333db52377'
+            'f0d90e756f14533ee67afda280500511a62465b4f76adcc5effa95a40045179c'
+            '1256b241cd477b265a3c2d64bdc19ffe3c9bbcee82ea3994c590c2c76e767d99')
+validpgpkeys=(
+              'ABAF11C65A2970B130ABE3C479BE3E4300411886' # Linus Torvalds
+              '647F28654894E3BD457199BE38DBBDC86092693E' # Greg Kroah-Hartman
+             )
+
+_kernelname=${pkgbase#linux}
+
+prepare() {
+  cd "${srcdir}/${_srcname}"
+
+  # add upstream patch
+  patch -p1 -i "${srcdir}/patch-${pkgver}"
+
+  # add latest fixes from stable queue, if needed
+  # http://git.kernel.org/?p=linux/kernel/git/stable/stable-queue.git
+  
+  # set DEFAULT_CONSOLE_LOGLEVEL to 4 (same value as the 'quiet' kernel param)
+  # remove this when a Kconfig knob is made available by upstream
+  # (relevant patch sent upstream: https://lkml.org/lkml/2011/7/26/227)
+  patch -p1 -i "${srcdir}/change-default-console-loglevel.patch"
+
+  if [ "${CARCH}" = "x86_64" ]; then
+    cat "${srcdir}/config.x86_64" > ./.config
+  else
+    cat "${srcdir}/config" > ./.config
+  fi
+
+  if [ "${_kernelname}" != "" ]; then
+    sed -i "s|CONFIG_LOCALVERSION=.*|CONFIG_LOCALVERSION=\"${_kernelname}\"|g" ./.config
+    sed -i "s|CONFIG_LOCALVERSION_AUTO=.*|CONFIG_LOCALVERSION_AUTO=n|" ./.config
+  fi
+
+  # set extraversion to pkgrel
+  sed -ri "s|^(EXTRAVERSION =).*|\1 -${pkgrel}|" Makefile
+
+  # don't run depmod on 'make install'. We'll do this ourselves in packaging
+  sed -i '2iexit 0' scripts/depmod.sh
+
+  # get kernel version
+  make prepare
+
+  # load configuration
+  # Configure the kernel. Replace the line below with one of your choice.
+  #make menuconfig # CLI menu for configuration
+  #make nconfig # new CLI menu for configuration
+  #make xconfig # X-based configuration
+  #make oldconfig # using old config from previous kernel version
+  # ... or manually edit .config
+
+  # rewrite configuration
+  yes "" | make config >/dev/null
+}
+
+build() {
+  cd "${srcdir}/${_srcname}"
+
+  make ${MAKEFLAGS} LOCALVERSION= bzImage modules
+}
+
+_package() {
+  pkgdesc="The ${pkgbase/linux/Linux} kernel and modules"
+  [ "${pkgbase}" = "linux" ] && groups=('base')
+  depends=('coreutils' 'linux-firmware' 'kmod' 'mkinitcpio>=0.7')
+  optdepends=('crda: to set the correct wireless channels of your country')
+  provides=("kernel26${_kernelname}=${pkgver}")
+  conflicts=("kernel26${_kernelname}")
+  replaces=("kernel26${_kernelname}")
+  backup=("etc/mkinitcpio.d/${pkgbase}.preset")
+  install=linux.install
+
+  cd "${srcdir}/${_srcname}"
+
+  KARCH=x86
+
+  # get kernel version
+  _kernver="$(make LOCALVERSION= kernelrelease)"
+  _basekernel=${_kernver%%-*}
+  _basekernel=${_basekernel%.*}
+
+  mkdir -p "${pkgdir}"/{lib/modules,lib/firmware,boot}
+  make LOCALVERSION= INSTALL_MOD_PATH="${pkgdir}" modules_install
+  cp arch/$KARCH/boot/bzImage "${pkgdir}/boot/vmlinuz-${pkgbase}"
+
+  # set correct depmod command for install
+  cp -f "${startdir}/${install}" "${startdir}/${install}.pkg"
+  true && install=${install}.pkg
+  sed \
+    -e  "s/KERNEL_NAME=.*/KERNEL_NAME=${_kernelname}/" \
+    -e  "s/KERNEL_VERSION=.*/KERNEL_VERSION=${_kernver}/" \
+    -i "${startdir}/${install}"
+
+  # install mkinitcpio preset file for kernel
+  install -D -m644 "${srcdir}/linux.preset" "${pkgdir}/etc/mkinitcpio.d/${pkgbase}.preset"
+  sed \
+    -e "1s|'linux.*'|'${pkgbase}'|" \
+    -e "s|ALL_kver=.*|ALL_kver=\"/boot/vmlinuz-${pkgbase}\"|" \
+    -e "s|default_image=.*|default_image=\"/boot/initramfs-${pkgbase}.img\"|" \
+    -e "s|fallback_image=.*|fallback_image=\"/boot/initramfs-${pkgbase}-fallback.img\"|" \
+    -i "${pkgdir}/etc/mkinitcpio.d/${pkgbase}.preset"
+
+  # remove build and source links
+  rm -f "${pkgdir}"/lib/modules/${_kernver}/{source,build}
+  # remove the firmware
+  rm -rf "${pkgdir}/lib/firmware"
+  # gzip -9 all modules to save 100MB of space
+  find "${pkgdir}" -name '*.ko' -exec gzip -9 {} \;
+  # make room for external modules
+  ln -s "../extramodules-${_basekernel}${_kernelname:--ARCH}" "${pkgdir}/lib/modules/${_kernver}/extramodules"
+  # add real version for building modules and running depmod from post_install/upgrade
+  mkdir -p "${pkgdir}/lib/modules/extramodules-${_basekernel}${_kernelname:--ARCH}"
+  echo "${_kernver}" > "${pkgdir}/lib/modules/extramodules-${_basekernel}${_kernelname:--ARCH}/version"
+
+  # Now we call depmod...
+  depmod -b "${pkgdir}" -F System.map "${_kernver}"
+
+  # move module tree /lib -> /usr/lib
+  mkdir -p "${pkgdir}/usr"
+  mv "${pkgdir}/lib" "${pkgdir}/usr/"
+
+  # add vmlinux
+  install -D -m644 vmlinux "${pkgdir}/usr/lib/modules/${_kernver}/build/vmlinux" 
+}
+
+_package-headers() {
+  pkgdesc="Header files and scripts for building modules for ${pkgbase/linux/Linux} kernel"
+  provides=("kernel26${_kernelname}-headers=${pkgver}")
+  conflicts=("kernel26${_kernelname}-headers")
+  replaces=("kernel26${_kernelname}-headers")
+
+  install -dm755 "${pkgdir}/usr/lib/modules/${_kernver}"
+
+  cd "${srcdir}/${_srcname}"
+  install -D -m644 Makefile \
+    "${pkgdir}/usr/lib/modules/${_kernver}/build/Makefile"
+  install -D -m644 kernel/Makefile \
+    "${pkgdir}/usr/lib/modules/${_kernver}/build/kernel/Makefile"
+  install -D -m644 .config \
+    "${pkgdir}/usr/lib/modules/${_kernver}/build/.config"
+
+  mkdir -p "${pkgdir}/usr/lib/modules/${_kernver}/build/include"
+
+  for i in acpi asm-generic config crypto drm generated keys linux math-emu \
+    media net pcmcia scsi sound trace uapi video xen; do
+    cp -a include/${i} "${pkgdir}/usr/lib/modules/${_kernver}/build/include/"
+  done
+
+  # copy arch includes for external modules
+  mkdir -p "${pkgdir}/usr/lib/modules/${_kernver}/build/arch/x86"
+  cp -a arch/x86/include "${pkgdir}/usr/lib/modules/${_kernver}/build/arch/x86/"
+
+  # copy files necessary for later builds, like nvidia and vmware
+  cp Module.symvers "${pkgdir}/usr/lib/modules/${_kernver}/build"
+  cp -a scripts "${pkgdir}/usr/lib/modules/${_kernver}/build"
+
+  # fix permissions on scripts dir
+  chmod og-w -R "${pkgdir}/usr/lib/modules/${_kernver}/build/scripts"
+  mkdir -p "${pkgdir}/usr/lib/modules/${_kernver}/build/.tmp_versions"
+
+  mkdir -p "${pkgdir}/usr/lib/modules/${_kernver}/build/arch/${KARCH}/kernel"
+
+  cp arch/${KARCH}/Makefile "${pkgdir}/usr/lib/modules/${_kernver}/build/arch/${KARCH}/"
+
+  if [ "${CARCH}" = "i686" ]; then
+    cp arch/${KARCH}/Makefile_32.cpu "${pkgdir}/usr/lib/modules/${_kernver}/build/arch/${KARCH}/"
+  fi
+
+  cp arch/${KARCH}/kernel/asm-offsets.s "${pkgdir}/usr/lib/modules/${_kernver}/build/arch/${KARCH}/kernel/"
+
+  # add docbook makefile
+  install -D -m644 Documentation/DocBook/Makefile \
+    "${pkgdir}/usr/lib/modules/${_kernver}/build/Documentation/DocBook/Makefile"
+
+  # add dm headers
+  mkdir -p "${pkgdir}/usr/lib/modules/${_kernver}/build/drivers/md"
+  cp drivers/md/*.h "${pkgdir}/usr/lib/modules/${_kernver}/build/drivers/md"
+
+  # add inotify.h
+  mkdir -p "${pkgdir}/usr/lib/modules/${_kernver}/build/include/linux"
+  cp include/linux/inotify.h "${pkgdir}/usr/lib/modules/${_kernver}/build/include/linux/"
+
+  # add wireless headers
+  mkdir -p "${pkgdir}/usr/lib/modules/${_kernver}/build/net/mac80211/"
+  cp net/mac80211/*.h "${pkgdir}/usr/lib/modules/${_kernver}/build/net/mac80211/"
+
+  # add dvb headers for external modules
+  # in reference to:
+  # http://bugs.archlinux.org/task/9912
+  mkdir -p "${pkgdir}/usr/lib/modules/${_kernver}/build/drivers/media/dvb-core"
+  cp drivers/media/dvb-core/*.h "${pkgdir}/usr/lib/modules/${_kernver}/build/drivers/media/dvb-core/"
+  # and...
+  # http://bugs.archlinux.org/task/11194
+  mkdir -p "${pkgdir}/usr/lib/modules/${_kernver}/build/include/config/dvb/"
+  cp include/config/dvb/*.h "${pkgdir}/usr/lib/modules/${_kernver}/build/include/config/dvb/"
+
+  # add dvb headers for http://mcentral.de/hg/~mrec/em28xx-new
+  # in reference to:
+  # http://bugs.archlinux.org/task/13146
+  mkdir -p "${pkgdir}/usr/lib/modules/${_kernver}/build/drivers/media/dvb-frontends/"
+  cp drivers/media/dvb-frontends/lgdt330x.h "${pkgdir}/usr/lib/modules/${_kernver}/build/drivers/media/dvb-frontends/"
+  mkdir -p "${pkgdir}/usr/lib/modules/${_kernver}/build/drivers/media/i2c/"
+  cp drivers/media/i2c/msp3400-driver.h "${pkgdir}/usr/lib/modules/${_kernver}/build/drivers/media/i2c/"
+
+  # add dvb headers
+  # in reference to:
+  # http://bugs.archlinux.org/task/20402
+  mkdir -p "${pkgdir}/usr/lib/modules/${_kernver}/build/drivers/media/usb/dvb-usb"
+  cp drivers/media/usb/dvb-usb/*.h "${pkgdir}/usr/lib/modules/${_kernver}/build/drivers/media/usb/dvb-usb/"
+  mkdir -p "${pkgdir}/usr/lib/modules/${_kernver}/build/drivers/media/dvb-frontends"
+  cp drivers/media/dvb-frontends/*.h "${pkgdir}/usr/lib/modules/${_kernver}/build/drivers/media/dvb-frontends/"
+  mkdir -p "${pkgdir}/usr/lib/modules/${_kernver}/build/drivers/media/tuners"
+  cp drivers/media/tuners/*.h "${pkgdir}/usr/lib/modules/${_kernver}/build/drivers/media/tuners/"
+
+  # add xfs and shmem for aufs building
+  mkdir -p "${pkgdir}/usr/lib/modules/${_kernver}/build/fs/xfs"
+  mkdir -p "${pkgdir}/usr/lib/modules/${_kernver}/build/mm"
+  # removed in 3.17 series
+  # cp fs/xfs/xfs_sb.h "${pkgdir}/usr/lib/modules/${_kernver}/build/fs/xfs/xfs_sb.h"
+
+  # copy in Kconfig files
+  for i in $(find . -name "Kconfig*"); do
+    mkdir -p "${pkgdir}"/usr/lib/modules/${_kernver}/build/`echo ${i} | sed 's|/Kconfig.*||'`
+    cp ${i} "${pkgdir}/usr/lib/modules/${_kernver}/build/${i}"
+  done
+
+  chown -R root.root "${pkgdir}/usr/lib/modules/${_kernver}/build"
+  find "${pkgdir}/usr/lib/modules/${_kernver}/build" -type d -exec chmod 755 {} \;
+
+  # strip scripts directory
+  find "${pkgdir}/usr/lib/modules/${_kernver}/build/scripts" -type f -perm -u+w 2>/dev/null | while read binary ; do
+    case "$(file -bi "${binary}")" in
+      *application/x-sharedlib*) # Libraries (.so)
+        /usr/bin/strip ${STRIP_SHARED} "${binary}";;
+      *application/x-archive*) # Libraries (.a)
+        /usr/bin/strip ${STRIP_STATIC} "${binary}";;
+      *application/x-executable*) # Binaries
+        /usr/bin/strip ${STRIP_BINARIES} "${binary}";;
+    esac
+  done
+
+  # remove unneeded architectures
+  rm -rf "${pkgdir}"/usr/lib/modules/${_kernver}/build/arch/{alpha,arc,arm,arm26,arm64,avr32,blackfin,c6x,cris,frv,h8300,hexagon,ia64,m32r,m68k,m68knommu,metag,mips,microblaze,mn10300,openrisc,parisc,powerpc,ppc,s390,score,sh,sh64,sparc,sparc64,tile,unicore32,um,v850,xtensa}
+}
+
+_package-docs() {
+  pkgdesc="Kernel hackers manual - HTML documentation that comes with the ${pkgbase/linux/Linux} kernel"
+  provides=("kernel26${_kernelname}-docs=${pkgver}")
+  conflicts=("kernel26${_kernelname}-docs")
+  replaces=("kernel26${_kernelname}-docs")
+
+  cd "${srcdir}/${_srcname}"
+
+  mkdir -p "${pkgdir}/usr/lib/modules/${_kernver}/build"
+  cp -al Documentation "${pkgdir}/usr/lib/modules/${_kernver}/build"
+  find "${pkgdir}" -type f -exec chmod 444 {} \;
+  find "${pkgdir}" -type d -exec chmod 755 {} \;
+
+  # remove a file already in linux package
+  rm -f "${pkgdir}/usr/lib/modules/${_kernver}/build/Documentation/DocBook/Makefile"
+}
+
+pkgname=("${pkgbase}" "${pkgbase}-headers" "${pkgbase}-docs")
+for _p in ${pkgname[@]}; do
+  eval "package_${_p}() {
+    $(declare -f "_package${_p#${pkgbase}}")
+    _package${_p#${pkgbase}}
+  }"
+done
+
+# vim:set ts=8 sts=2 sw=2 et:

+ 88 - 0
vendor/github.com/mikkeloscar/gopkgbuild/test_pkgbuilds/PKGBUILD_openssh

@@ -0,0 +1,88 @@
+# $Id: PKGBUILD 224811 2014-10-18 18:33:28Z bisson $
+# Maintainer: Gaetan Bisson <bisson@archlinux.org>
+# Contributor: Aaron Griffin <aaron@archlinux.org>
+# Contributor: judd <jvinet@zeroflux.org>
+
+pkgname=openssh
+pkgver=6.7p1
+pkgrel=1
+pkgdesc='Free version of the SSH connectivity tools'
+url='http://www.openssh.org/portable.html'
+license=('custom:BSD')
+arch=('i686' 'x86_64')
+makedepends=('linux-headers')
+depends=('krb5' 'openssl' 'libedit' 'ldns')
+optdepends=('xorg-xauth: X11 forwarding'
+            'x11-ssh-askpass: input passphrase in X')
+source=("ftp://ftp.openbsd.org/pub/OpenBSD/OpenSSH/portable/${pkgname}-${pkgver}.tar.gz"{,.asc}
+        'sshdgenkeys.service'
+        'sshd@.service'
+        'sshd.service'
+        'sshd.socket'
+        'sshd.pam')
+sha1sums=('14e5fbed710ade334d65925e080d1aaeb9c85bf6' 'SKIP'
+          'cc1ceec606c98c7407e7ac21ade23aed81e31405'
+          '6a0ff3305692cf83aca96e10f3bb51e1c26fccda'
+          'ec49c6beba923e201505f5669cea48cad29014db'
+          'e12fa910b26a5634e5a6ac39ce1399a132cf6796'
+          'd93dca5ebda4610ff7647187f8928a3de28703f3')
+
+backup=('etc/ssh/ssh_config' 'etc/ssh/sshd_config' 'etc/pam.d/sshd')
+
+install=install
+
+build() {
+	cd "${srcdir}/${pkgname}-${pkgver}"
+
+	./configure \
+		--prefix=/usr \
+		--sbindir=/usr/bin \
+		--libexecdir=/usr/lib/ssh \
+		--sysconfdir=/etc/ssh \
+		--with-ldns \
+		--with-libedit \
+		--with-ssl-engine \
+		--with-pam \
+		--with-privsep-user=nobody \
+		--with-kerberos5=/usr \
+		--with-xauth=/usr/bin/xauth \
+		--with-mantype=man \
+		--with-md5-passwords \
+		--with-pid-dir=/run \
+
+	make
+}
+
+check() {
+	cd "${srcdir}/${pkgname}-${pkgver}"
+
+	make tests || true
+	# hard to suitably test connectivity:
+	# - fails with /bin/false as login shell
+	# - fails with firewall activated, etc.
+}
+
+package() {
+	cd "${srcdir}/${pkgname}-${pkgver}"
+
+	make DESTDIR="${pkgdir}" install
+
+	ln -sf ssh.1.gz "${pkgdir}"/usr/share/man/man1/slogin.1.gz
+	install -Dm644 LICENCE "${pkgdir}/usr/share/licenses/${pkgname}/LICENCE"
+
+	install -Dm644 ../sshdgenkeys.service "${pkgdir}"/usr/lib/systemd/system/sshdgenkeys.service
+	install -Dm644 ../sshd@.service "${pkgdir}"/usr/lib/systemd/system/sshd@.service
+	install -Dm644 ../sshd.service "${pkgdir}"/usr/lib/systemd/system/sshd.service
+	install -Dm644 ../sshd.socket "${pkgdir}"/usr/lib/systemd/system/sshd.socket
+	install -Dm644 ../sshd.pam "${pkgdir}"/etc/pam.d/sshd
+
+	install -Dm755 contrib/findssl.sh "${pkgdir}"/usr/bin/findssl.sh
+	install -Dm755 contrib/ssh-copy-id "${pkgdir}"/usr/bin/ssh-copy-id
+	install -Dm644 contrib/ssh-copy-id.1 "${pkgdir}"/usr/share/man/man1/ssh-copy-id.1
+
+	sed \
+		-e '/^#ChallengeResponseAuthentication yes$/c ChallengeResponseAuthentication no' \
+		-e '/^#PrintMotd yes$/c PrintMotd no # pam does that' \
+		-e '/^#UsePAM no$/c UsePAM yes' \
+		-i "${pkgdir}"/etc/ssh/sshd_config
+}

+ 96 - 0
vendor/github.com/mikkeloscar/gopkgbuild/test_pkgbuilds/PKGBUILD_pacman

@@ -0,0 +1,96 @@
+# vim: set ts=2 sw=2 et:
+# $Id: PKGBUILD 227073 2014-11-25 01:56:16Z bisson $
+# Maintainer: Dan McGee <dan@archlinux.org>
+# Maintainer: Dave Reisner <dreisner@archlinux.org>
+
+pkgname=pacman
+pkgver=4.1.2
+pkgrel=7
+pkgdesc="A library-based package manager with dependency support"
+arch=('i686' 'x86_64')
+url="http://www.archlinux.org/pacman/"
+license=('GPL')
+groups=('base' 'base-devel')
+depends=('bash>=4.2.042-2' 'glibc>=2.17-2' 'libarchive>=3.1.2' 'curl>=7.19.4'
+         'gpgme' 'pacman-mirrorlist' 'archlinux-keyring')
+checkdepends=('python2' 'fakechroot')
+optdepends=('fakeroot: for makepkg usage as normal user')
+provides=('pacman-contrib')
+conflicts=('pacman-contrib')
+replaces=('pacman-contrib')
+backup=(etc/pacman.conf etc/makepkg.conf)
+options=('strip' 'debug')
+source=(ftp://ftp.archlinux.org/other/pacman/$pkgname-$pkgver.tar.gz{,.sig}
+	0001-pacman-key-compatibility-with-gnupg-2.1.patch
+        pacman.conf.i686
+        pacman.conf.x86_64
+        makepkg.conf)
+md5sums=('063c8b0ff6bdf903dc235445525627cd'
+         'SKIP'
+         'd0e015b1bf78cbf9762d9c44ea5f77a9'
+         '2db6c94709bb30cc614a176ecf8badb1'
+         'de74a13618347f08ae4a9637f74471c4'
+         '2da6544e387f940588a90cb4b9b914e2')
+validpgpkeys=('6645B0A8C7005E78DB1D7864F99FFE0FEAE999BD')  # Allan McRae <allan@archlinux.org>
+
+prepare() {
+  cd "$pkgname-$pkgver"
+  patch -p1 -i $srcdir/0001-pacman-key-compatibility-with-gnupg-2.1.patch
+}
+
+build() {
+  cd "$pkgname-$pkgver"
+
+  ./configure --prefix=/usr --sysconfdir=/etc \
+    --localstatedir=/var --enable-doc \
+    --with-scriptlet-shell=/usr/bin/bash \
+    --with-ldconfig=/usr/bin/ldconfig
+  make
+  make -C contrib
+}
+
+check() {
+  make -C "$pkgname-$pkgver" check
+}
+
+package() {
+  cd "$pkgname-$pkgver"
+
+  make DESTDIR="$pkgdir" install
+  make DESTDIR="$pkgdir" -C contrib install
+
+  # install Arch specific stuff
+  install -dm755 "$pkgdir/etc"
+  install -m644 "$srcdir/pacman.conf.$CARCH" "$pkgdir/etc/pacman.conf"
+
+  case $CARCH in
+    i686)
+      mycarch="i686"
+      mychost="i686-pc-linux-gnu"
+      myflags="-march=i686"
+      ;;
+    x86_64)
+      mycarch="x86_64"
+      mychost="x86_64-unknown-linux-gnu"
+      myflags="-march=x86-64"
+      ;;
+  esac
+
+  # set things correctly in the default conf file
+  install -m644 "$srcdir/makepkg.conf" "$pkgdir/etc"
+  sed -i "$pkgdir/etc/makepkg.conf" \
+    -e "s|@CARCH[@]|$mycarch|g" \
+    -e "s|@CHOST[@]|$mychost|g" \
+    -e "s|@CARCHFLAGS[@]|$myflags|g"
+
+  # put bash_completion in the right location
+  install -dm755 "$pkgdir/usr/share/bash-completion/completions"
+  mv "$pkgdir/etc/bash_completion.d/pacman" "$pkgdir/usr/share/bash-completion/completions"
+  rmdir "$pkgdir/etc/bash_completion.d"
+
+  for f in makepkg pacman-key; do
+    ln -s pacman "$pkgdir/usr/share/bash-completion/completions/$f"
+  done
+
+  install -Dm644 contrib/PKGBUILD.vim "$pkgdir/usr/share/vim/vimfiles/syntax/PKGBUILD.vim"
+}

+ 66 - 0
vendor/github.com/mikkeloscar/gopkgbuild/test_pkgbuilds/PKGBUILD_sudo

@@ -0,0 +1,66 @@
+# $Id: PKGBUILD 225542 2014-11-02 04:43:40Z foutrelis $
+# Maintainer: Evangelos Foutras <evangelos@foutrelis.com>
+# Contributor: Allan McRae <allan@archlinux.org>
+# Contributor: Tom Newsom <Jeepster@gmx.co.uk>
+
+pkgname=sudo
+_sudover=1.8.11p2
+pkgver=${_sudover/p/.p}
+pkgrel=1
+pkgdesc="Give certain users the ability to run some commands as root"
+arch=('i686' 'x86_64')
+url="http://www.sudo.ws/sudo/"
+license=('custom')
+groups=('base-devel')
+depends=('glibc' 'pam' 'libldap')
+backup=('etc/sudoers' 'etc/pam.d/sudo')
+install=$pkgname.install
+source=(http://www.sudo.ws/sudo/dist/$pkgname-$_sudover.tar.gz{,.sig}
+        sudo.tmpfiles.conf
+        sudo.pam)
+sha256sums=('8133849418fa18cf6b6bb6893d1855ff7afe21db8923234a00bf045c90fba1ad'
+            'SKIP'
+            '080dd97111b3149f8d140ffac68c88acd63da9eacc81fbcc7c43591be13b42fe'
+            'd1738818070684a5d2c9b26224906aad69a4fea77aabd960fc2675aee2df1fa2')
+
+build() {
+  cd "$srcdir/$pkgname-$_sudover"
+
+  ./configure \
+    --prefix=/usr \
+    --sbindir=/usr/bin \
+    --libexecdir=/usr/lib \
+    --with-rundir=/run/sudo \
+    --with-vardir=/var/db/sudo \
+    --with-logfac=auth \
+    --with-pam \
+    --with-ldap \
+    --with-ldap-conf-file=/etc/openldap/ldap.conf \
+    --with-env-editor \
+    --with-passprompt="[sudo] password for %p: " \
+    --with-all-insults
+  make
+}
+
+check() {
+  cd "$srcdir/$pkgname-$_sudover"
+  make check
+}
+
+package() {
+  cd "$srcdir/$pkgname-$_sudover"
+  make DESTDIR="$pkgdir" install
+
+  # Remove /run/sudo directory from the package; we create it using tmpfiles.d
+  rmdir "$pkgdir/run/sudo"
+  rmdir "$pkgdir/run"
+
+  install -Dm644 "$srcdir/sudo.tmpfiles.conf" \
+    "$pkgdir/usr/lib/tmpfiles.d/sudo.conf"
+
+  install -Dm644 "$srcdir/sudo.pam" "$pkgdir/etc/pam.d/sudo"
+
+  install -Dm644 doc/LICENSE "$pkgdir/usr/share/licenses/sudo/LICENSE"
+}
+
+# vim:set ts=2 sw=2 et:

+ 197 - 0
vendor/github.com/mikkeloscar/gopkgbuild/test_pkgbuilds/PKGBUILD_systemd

@@ -0,0 +1,197 @@
+# Maintainer: Dave Reisner <dreisner@archlinux.org>
+# Maintainer: Tom Gundersen <teg@jklm.no>
+
+pkgbase=systemd
+pkgname=('systemd' 'libsystemd' 'systemd-sysvcompat')
+pkgver=217
+pkgrel=8
+arch=('i686' 'x86_64')
+url="http://www.freedesktop.org/wiki/Software/systemd"
+makedepends=('acl' 'cryptsetup' 'docbook-xsl' 'gobject-introspection' 'gperf'
+             'gtk-doc' 'intltool' 'kmod' 'libcap' 'libidn' 'libgcrypt' 'libmicrohttpd'
+             'libxslt' 'util-linux' 'linux-api-headers' 'lz4' 'pam' 'python'
+             'python-lxml' 'quota-tools' 'shadow' 'xz')
+options=('strip' 'debug')
+source=("http://www.freedesktop.org/software/$pkgname/$pkgname-$pkgver.tar.xz"
+        '0001-nspawn-ignore-EEXIST-when-creating-mount-point.patch'
+        '0001-sd-dhcp-client-clean-up-raw-socket-sd_event_source-w.patch'
+        '0001-shared-install-avoid-prematurely-rejecting-missing-u.patch'
+        '0001-sd-bus-properly-handle-removals-of-non-existing-matc.patch'
+        '0001-units-don-t-order-journal-flushing-afte-remote-fs.ta.patch'
+        '0001-units-order-sd-journal-flush-after-sd-remount-fs.patch'
+        '0001-units-make-systemd-journald.service-Type-notify.patch'
+        '0001-shutdown-fix-arguments-to-run-initramfs-shutdown.patch'
+        '0001-udev-hwdb-Change-error-message-regarding-missing-hwd.patch'
+        'initcpio-hook-udev'
+        'initcpio-install-systemd'
+        'initcpio-install-udev')
+md5sums=('e68dbff3cc19f66e341572d9fb2ffa89'
+         'ca9e33118fd8d456563854d95512a577'
+         'ade8c1b5b2c85d0a83b7bcf5aa6d131a'
+         '7aaf44ce842deb449fca0f2595bbc1e4'
+         '4adc3ddce027693bafa53089322e859b'
+         '42ff9d59bb057637355b202157d59991'
+         '92497d06e0af615be4b368fe615109c0'
+         'a321d62d6ffada9e6976bdd339fa3219'
+         'f72e8d086172177c224f0ce48ef54222'
+         '6326988822e9d18217525b2cb25cec1d'
+         '90ea67a7bb237502094914622a39e281'
+         '107c489f27c667be4101aecd3369b355'
+         'bde43090d4ac0ef048e3eaee8202a407')
+
+
+prepare() {
+  cd "$pkgname-$pkgver"
+
+  patch -Np1 <../0001-nspawn-ignore-EEXIST-when-creating-mount-point.patch
+  patch -Np1 <../0001-sd-dhcp-client-clean-up-raw-socket-sd_event_source-w.patch
+  patch -Np1 <../0001-shared-install-avoid-prematurely-rejecting-missing-u.patch
+  patch -Np1 <../0001-sd-bus-properly-handle-removals-of-non-existing-matc.patch
+  patch -Np1 <../0001-units-don-t-order-journal-flushing-afte-remote-fs.ta.patch
+  patch -Np1 <../0001-units-order-sd-journal-flush-after-sd-remount-fs.patch
+  patch -Np1 <../0001-units-make-systemd-journald.service-Type-notify.patch
+  patch -Np1 <../0001-shutdown-fix-arguments-to-run-initramfs-shutdown.patch
+  patch -Np1 <../0001-udev-hwdb-Change-error-message-regarding-missing-hwd.patch
+}
+
+build() {
+  cd "$pkgname-$pkgver"
+
+  local timeservers=({0..3}.arch.pool.ntp.org)
+
+  ./configure \
+      --libexecdir=/usr/lib \
+      --localstatedir=/var \
+      --sysconfdir=/etc \
+      --enable-introspection \
+      --enable-gtk-doc \
+      --enable-lz4 \
+      --enable-compat-libs \
+      --disable-audit \
+      --disable-ima \
+      --disable-kdbus \
+      --with-sysvinit-path= \
+      --with-sysvrcnd-path= \
+      --with-ntp-servers="${timeservers[*]}"
+
+  make
+}
+
+package_systemd() {
+  pkgdesc="system and service manager"
+  license=('GPL2' 'LGPL2.1' 'MIT')
+  depends=('acl' 'bash' 'dbus' 'glib2' 'kbd' 'kmod' 'hwids' 'libcap' 'libgcrypt'
+           'libsystemd' 'libidn' 'lz4' 'pam' 'libseccomp' 'util-linux' 'xz')
+  provides=('nss-myhostname' "systemd-tools=$pkgver" "udev=$pkgver")
+  replaces=('nss-myhostname' 'systemd-tools' 'udev')
+  conflicts=('nss-myhostname' 'systemd-tools' 'udev')
+  optdepends=('python: systemd library bindings'
+              'cryptsetup: required for encrypted block devices'
+              'libmicrohttpd: remote journald capabilities'
+              'quota-tools: kernel-level quota management'
+              'systemd-sysvcompat: symlink package to provide sysvinit binaries'
+              'polkit: allow administration as unprivileged user')
+  backup=(etc/dbus-1/system.d/org.freedesktop.systemd1.conf
+          etc/dbus-1/system.d/org.freedesktop.hostname1.conf
+          etc/dbus-1/system.d/org.freedesktop.login1.conf
+          etc/dbus-1/system.d/org.freedesktop.locale1.conf
+          etc/dbus-1/system.d/org.freedesktop.machine1.conf
+          etc/dbus-1/system.d/org.freedesktop.timedate1.conf
+          etc/pam.d/systemd-user
+          etc/systemd/bootchart.conf
+          etc/systemd/coredump.conf
+          etc/systemd/journald.conf
+          etc/systemd/logind.conf
+          etc/systemd/system.conf
+          etc/systemd/timesyncd.conf
+          etc/systemd/resolved.conf
+          etc/systemd/user.conf
+          etc/udev/udev.conf)
+  install="systemd.install"
+
+  make -C "$pkgname-$pkgver" DESTDIR="$pkgdir" install
+
+  # don't write units to /etc by default. some of these will be re-enabled on
+  # post_install.
+  rm "$pkgdir/etc/systemd/system/getty.target.wants/getty@tty1.service" \
+      "$pkgdir/etc/systemd/system/multi-user.target.wants/systemd-networkd.service" \
+      "$pkgdir/etc/systemd/system/multi-user.target.wants/systemd-resolved.service" \
+      "$pkgdir/etc/systemd/system/sysinit.target.wants/systemd-timesyncd.service" \
+      "$pkgdir/etc/systemd/system/network-online.target.wants/systemd-networkd-wait-online.service"
+  rmdir "$pkgdir/etc/systemd/system/getty.target.wants" \
+      "$pkgdir/etc/systemd/system/network-online.target.wants"
+
+  # get rid of RPM macros
+  rm -r "$pkgdir/usr/lib/rpm"
+
+  # add back tmpfiles.d/legacy.conf
+  install -m644 "systemd-$pkgver/tmpfiles.d/legacy.conf" "$pkgdir/usr/lib/tmpfiles.d"
+
+  # Replace dialout/tape/cdrom group in rules with uucp/storage/optical group
+  sed -i 's#GROUP="dialout"#GROUP="uucp"#g;
+          s#GROUP="tape"#GROUP="storage"#g;
+          s#GROUP="cdrom"#GROUP="optical"#g' "$pkgdir"/usr/lib/udev/rules.d/*.rules
+  sed -i 's/dialout/uucp/g;
+          s/tape/storage/g;
+          s/cdrom/optical/g' "$pkgdir"/usr/lib/sysusers.d/basic.conf
+
+  # add mkinitcpio hooks
+  install -Dm644 "$srcdir/initcpio-install-systemd" "$pkgdir/usr/lib/initcpio/install/systemd"
+  install -Dm644 "$srcdir/initcpio-install-udev" "$pkgdir/usr/lib/initcpio/install/udev"
+  install -Dm644 "$srcdir/initcpio-hook-udev" "$pkgdir/usr/lib/initcpio/hooks/udev"
+
+  # ensure proper permissions for /var/log/journal. This is only to placate
+  chown root:systemd-journal "$pkgdir/var/log/journal"
+  chmod 2755 "$pkgdir/var/log/journal"{,/remote}
+
+  # fix pam file
+  sed 's|system-auth|system-login|g' -i "$pkgdir/etc/pam.d/systemd-user"
+
+  # ship default policy to leave services disabled
+  echo 'disable *' >"$pkgdir"/usr/lib/systemd/system-preset/99-default.preset
+
+  ### split out manpages for sysvcompat
+  rm -rf "$srcdir/_sysvcompat"
+  install -dm755 "$srcdir"/_sysvcompat/usr/share/man/man8/
+  mv "$pkgdir"/usr/share/man/man8/{telinit,halt,reboot,poweroff,runlevel,shutdown}.8 \
+     "$srcdir"/_sysvcompat/usr/share/man/man8
+
+  ### split off runtime libraries
+  rm -rf "$srcdir/_libsystemd"
+  install -dm755 "$srcdir"/_libsystemd/usr/lib
+  cd "$srcdir"/_libsystemd
+  mv "$pkgdir"/usr/lib/lib{systemd,{g,}udev}*.so* usr/lib
+
+  # include MIT license, since it's technically custom
+  install -Dm644 "$srcdir/$pkgname-$pkgver/LICENSE.MIT" \
+      "$pkgdir/usr/share/licenses/systemd/LICENSE.MIT"
+}
+
+package_libsystemd() {
+  pkgdesc="systemd client libraries"
+  depends=('glib2' 'glibc' 'libgcrypt' 'lz4' 'xz')
+  license=('GPL2')
+  provides=('libgudev-1.0.so' 'libsystemd.so' 'libsystemd-daemon.so' 'libsystemd-id128.so'
+            'libsystemd-journal.so' 'libsystemd-login.so' 'libudev.so')
+
+  mv "$srcdir/_libsystemd"/* "$pkgdir"
+}
+
+package_systemd-sysvcompat() {
+  pkgdesc="sysvinit compat for systemd"
+  license=('GPL2')
+  groups=('base')
+  conflicts=('sysvinit')
+  depends=('systemd')
+
+  mv "$srcdir/_sysvcompat"/* "$pkgdir"
+
+  install -dm755 "$pkgdir/usr/bin"
+  for tool in runlevel reboot shutdown poweroff halt telinit; do
+    ln -s 'systemctl' "$pkgdir/usr/bin/$tool"
+  done
+
+  ln -s '../lib/systemd/systemd' "$pkgdir/usr/bin/init"
+}
+
+# vim: ft=sh syn=sh et

+ 36 - 0
vendor/github.com/mikkeloscar/gopkgbuild/test_pkgbuilds/SRCINFO_glibc

@@ -0,0 +1,36 @@
+# Generated by makepkg 4.2.0
+# Mon Feb  2 23:44:57 UTC 2015
+pkgbase = glibc
+	pkgdesc = GNU C Library
+	pkgver = 2.20
+	pkgrel = 6
+	url = http://www.gnu.org/software/libc
+	install = glibc.install
+	arch = i686
+	arch = x86_64
+	arch = armv6h
+	groups = base
+	license = GPL
+	license = LGPL
+	makedepends = gcc>=4.9
+	depends = linux-api-headers>=3.16
+	depends = tzdata
+	depends = filesystem>=2013.01
+	options = !strip
+	options = staticlibs
+	backup = etc/gai.conf
+	backup = etc/locale.gen
+	backup = etc/nscd.conf
+	source = http://ftp.gnu.org/gnu/libc/glibc-2.20.tar.xz
+	source = http://ftp.gnu.org/gnu/libc/glibc-2.20.tar.xz.sig
+	source = glibc-2.20-roundup.patch
+	source = locale.gen.txt
+	source = locale-gen
+	md5sums = 948a6e06419a01bd51e97206861595b0
+	md5sums = SKIP
+	md5sums = f7a5faf2911ae7c13f584bd60c802873
+	md5sums = 07ac979b6ab5eeb778d55f041529d623
+	md5sums = 476e9113489f93b348b21e144b6a8fcf
+
+pkgname = glibc
+

+ 75 - 0
vendor/github.com/mikkeloscar/gopkgbuild/test_pkgbuilds/SRCINFO_grub

@@ -0,0 +1,75 @@
+# Generated by makepkg 4.2.0
+# Mon Feb  2 23:43:33 UTC 2015
+pkgbase = grub
+	pkgdesc = GNU GRand Unified Bootloader (2)
+	pkgver = 2.02.beta2
+	pkgrel = 5
+	epoch = 1
+	url = https://www.gnu.org/software/grub/
+	install = grub.install
+	arch = x86_64
+	arch = i686
+	license = GPL3
+	makedepends = git
+	makedepends = rsync
+	makedepends = xz
+	makedepends = freetype2
+	makedepends = ttf-dejavu
+	makedepends = python
+	makedepends = autogen
+	makedepends = texinfo
+	makedepends = help2man
+	makedepends = gettext
+	makedepends = device-mapper
+	makedepends = fuse
+	depends = sh
+	depends = xz
+	depends = gettext
+	depends = device-mapper
+	optdepends = freetype2: For grub-mkfont usage
+	optdepends = fuse: For grub-mount usage
+	optdepends = dosfstools: For grub-mkrescue FAT FS and EFI support
+	optdepends = efibootmgr: For grub-install EFI support
+	optdepends = libisoburn: Provides xorriso for generating grub rescue iso using grub-mkrescue
+	optdepends = os-prober: To detect other OSes when generating grub.cfg in BIOS systems
+	optdepends = mtools: For grub-mkrescue FAT FS support
+	provides = grub-common
+	provides = grub-bios
+	provides = grub-emu
+	provides = grub-efi-x86_64
+	conflicts = grub-common
+	conflicts = grub-bios
+	conflicts = grub-emu
+	conflicts = grub-efi-x86_64
+	conflicts = grub-legacy
+	replaces = grub-common
+	replaces = grub-bios
+	replaces = grub-emu
+	replaces = grub-efi-x86_64
+	options = !makeflags
+	backup = boot/grub/grub.cfg
+	backup = etc/default/grub
+	backup = etc/grub.d/40_custom
+	source = grub-2.02::git+git://git.sv.gnu.org/grub.git#tag=grub-2.02-beta2
+	source = grub-extras::git+git://git.sv.gnu.org/grub-extras.git#branch=master
+	source = http://ftp.gnu.org/gnu/unifont/unifont-6.3.20131217/unifont-6.3.20131217.bdf.gz
+	source = http://ftp.gnu.org/gnu/unifont/unifont-6.3.20131217/unifont-6.3.20131217.bdf.gz.sig
+	source = grub-10_linux-detect-archlinux-initramfs.patch
+	source = grub-intel-ucode.patch
+	source = grub-add-GRUB_COLOR_variables.patch
+	source = 60_memtest86+
+	source = grub.default
+	source = grub.cfg
+	md5sums = SKIP
+	md5sums = SKIP
+	md5sums = 728b7439ac733a7c0d56049adec364c7
+	md5sums = SKIP
+	md5sums = 945527e0de8d384166a4cf23439ae9ee
+	md5sums = a678629bc82c4e70c48d28242036d1d7
+	md5sums = e506ae4a9f9f7d1b765febfa84e10d48
+	md5sums = be55eabc102f2c60b38ed35c203686d6
+	md5sums = a03ffd56324520393bf574cefccb893d
+	md5sums = c8b9511586d57d6f2524ae7898397a46
+
+pkgname = grub
+

+ 57 - 0
vendor/github.com/mikkeloscar/gopkgbuild/test_pkgbuilds/SRCINFO_linux

@@ -0,0 +1,57 @@
+# Generated by makepkg 4.2.0
+# Mon Feb  2 23:47:51 UTC 2015
+pkgbase = linux
+	pkgver = 3.18.5
+	pkgrel = 1
+	url = http://www.kernel.org/
+	arch = i686
+	arch = x86_64
+	license = GPL2
+	makedepends = xmlto
+	makedepends = docbook-xsl
+	makedepends = kmod
+	makedepends = inetutils
+	makedepends = bc
+	options = !strip
+	source = https://www.kernel.org/pub/linux/kernel/v3.x/linux-3.18.tar.xz
+	source = https://www.kernel.org/pub/linux/kernel/v3.x/linux-3.18.tar.sign
+	source = https://www.kernel.org/pub/linux/kernel/v3.x/patch-3.18.5.xz
+	source = https://www.kernel.org/pub/linux/kernel/v3.x/patch-3.18.5.sign
+	source = config
+	source = config.x86_64
+	source = linux.preset
+	source = change-default-console-loglevel.patch
+	sha256sums = becc413cc9e6d7f5cc52a3ce66d65c3725bc1d1cc1001f4ce6c32b69eb188cbd
+	sha256sums = SKIP
+	sha256sums = 9e261632e11f629705c3f1b2f07c611284e5f9972c42f6740131e8e2471c349a
+	sha256sums = SKIP
+	sha256sums = d3794c8b2cd11b71914b41f7a4e861369d4fa3c29fdd9e1d677ff0c2167eeb52
+	sha256sums = df7886f5d57f8f85e89987066dfa5c316e922dc0b22e6e6ad01331333db52377
+	sha256sums = f0d90e756f14533ee67afda280500511a62465b4f76adcc5effa95a40045179c
+	sha256sums = 1256b241cd477b265a3c2d64bdc19ffe3c9bbcee82ea3994c590c2c76e767d99
+
+pkgname = linux
+	pkgdesc = The Linux kernel and modules
+	install = linux.install
+	depends = coreutils
+	depends = linux-firmware
+	depends = kmod
+	depends = mkinitcpio>=0.7
+	optdepends = crda: to set the correct wireless channels of your country
+	provides = kernel26=3.18.5
+	conflicts = kernel26
+	replaces = kernel26
+	backup = etc/mkinitcpio.d/linux.preset
+
+pkgname = linux-headers
+	pkgdesc = Header files and scripts for building modules for Linux kernel
+	provides = kernel26-headers=3.18.5
+	conflicts = kernel26-headers
+	replaces = kernel26-headers
+
+pkgname = linux-docs
+	pkgdesc = Kernel hackers manual - HTML documentation that comes with the Linux kernel
+	provides = kernel26-docs=3.18.5
+	conflicts = kernel26-docs
+	replaces = kernel26-docs
+

+ 38 - 0
vendor/github.com/mikkeloscar/gopkgbuild/test_pkgbuilds/SRCINFO_openssh

@@ -0,0 +1,38 @@
+# Generated by makepkg 4.2.0
+# Mon Feb  2 23:36:37 UTC 2015
+pkgbase = openssh
+	pkgdesc = Free version of the SSH connectivity tools
+	pkgver = 6.7p1
+	pkgrel = 1
+	url = http://www.openssh.org/portable.html
+	install = install
+	arch = i686
+	arch = x86_64
+	license = custom:BSD
+	makedepends = linux-headers
+	depends = krb5
+	depends = openssl
+	depends = libedit
+	depends = ldns
+	optdepends = xorg-xauth: X11 forwarding
+	optdepends = x11-ssh-askpass: input passphrase in X
+	backup = etc/ssh/ssh_config
+	backup = etc/ssh/sshd_config
+	backup = etc/pam.d/sshd
+	source = ftp://ftp.openbsd.org/pub/OpenBSD/OpenSSH/portable/openssh-6.7p1.tar.gz
+	source = ftp://ftp.openbsd.org/pub/OpenBSD/OpenSSH/portable/openssh-6.7p1.tar.gz.asc
+	source = sshdgenkeys.service
+	source = sshd@.service
+	source = sshd.service
+	source = sshd.socket
+	source = sshd.pam
+	sha1sums = 14e5fbed710ade334d65925e080d1aaeb9c85bf6
+	sha1sums = SKIP
+	sha1sums = cc1ceec606c98c7407e7ac21ade23aed81e31405
+	sha1sums = 6a0ff3305692cf83aca96e10f3bb51e1c26fccda
+	sha1sums = ec49c6beba923e201505f5669cea48cad29014db
+	sha1sums = e12fa910b26a5634e5a6ac39ce1399a132cf6796
+	sha1sums = d93dca5ebda4610ff7647187f8928a3de28703f3
+
+pkgname = openssh
+

+ 44 - 0
vendor/github.com/mikkeloscar/gopkgbuild/test_pkgbuilds/SRCINFO_pacman

@@ -0,0 +1,44 @@
+# Generated by makepkg 4.2.0
+# Mon Feb  2 23:35:22 UTC 2015
+pkgbase = pacman
+	pkgdesc = A library-based package manager with dependency support
+	pkgver = 4.2.0
+	pkgrel = 6
+	url = http://www.archlinux.org/pacman/
+	arch = i686
+	arch = x86_64
+	groups = base
+	groups = base-devel
+	license = GPL
+	checkdepends = python2
+	checkdepends = fakechroot
+	makedepends = asciidoc
+	depends = bash
+	depends = glibc
+	depends = libarchive>=3.1.2
+	depends = curl>=7.39.0
+	depends = gpgme
+	depends = pacman-mirrorlist
+	depends = archlinux-keyring
+	provides = pacman-contrib
+	conflicts = pacman-contrib
+	replaces = pacman-contrib
+	options = strip
+	options = debug
+	backup = etc/pacman.conf
+	backup = etc/makepkg.conf
+	source = ftp://ftp.archlinux.org/other/pacman/pacman-4.2.0.tar.gz
+	source = ftp://ftp.archlinux.org/other/pacman/pacman-4.2.0.tar.gz.sig
+	source = pacman.conf.i686
+	source = pacman.conf.x86_64
+	source = makepkg.conf
+	source = pacman-4.2.0-roundup.patch
+	md5sums = 184ce14f1f326fede72012cca51bba51
+	md5sums = SKIP
+	md5sums = 2db6c94709bb30cc614a176ecf8badb1
+	md5sums = de74a13618347f08ae4a9637f74471c4
+	md5sums = 03d578816b56852d803cbafac85b9f09
+	md5sums = abe3baaf610d9cc42b4e3748c936bbce
+
+pkgname = pacman
+

+ 28 - 0
vendor/github.com/mikkeloscar/gopkgbuild/test_pkgbuilds/SRCINFO_sudo

@@ -0,0 +1,28 @@
+# Generated by makepkg 4.2.0
+# Mon Feb  2 23:32:24 UTC 2015
+pkgbase = sudo
+	pkgdesc = Give certain users the ability to run some commands as root
+	pkgver = 1.8.11.p2
+	pkgrel = 1
+	url = http://www.sudo.ws/sudo/
+	install = sudo.install
+	arch = i686
+	arch = x86_64
+	groups = base-devel
+	license = custom
+	depends = glibc
+	depends = pam
+	depends = libldap
+	backup = etc/sudoers
+	backup = etc/pam.d/sudo
+	source = http://www.sudo.ws/sudo/dist/sudo-1.8.11p2.tar.gz
+	source = http://www.sudo.ws/sudo/dist/sudo-1.8.11p2.tar.gz.sig
+	source = sudo.tmpfiles.conf
+	source = sudo.pam
+	sha256sums = 8133849418fa18cf6b6bb6893d1855ff7afe21db8923234a00bf045c90fba1ad
+	sha256sums = SKIP
+	sha256sums = 080dd97111b3149f8d140ffac68c88acd63da9eacc81fbcc7c43591be13b42fe
+	sha256sums = d1738818070684a5d2c9b26224906aad69a4fea77aabd960fc2675aee2df1fa2
+
+pkgname = sudo
+

+ 118 - 0
vendor/github.com/mikkeloscar/gopkgbuild/test_pkgbuilds/SRCINFO_systemd

@@ -0,0 +1,118 @@
+# Generated by makepkg 4.2.0
+# Mon Feb  2 23:46:32 UTC 2015
+pkgbase = systemd
+	pkgver = 218
+	pkgrel = 1
+	url = http://www.freedesktop.org/wiki/Software/systemd
+	arch = i686
+	arch = x86_64
+	makedepends = acl
+	makedepends = cryptsetup
+	makedepends = docbook-xsl
+	makedepends = gobject-introspection
+	makedepends = gperf
+	makedepends = gtk-doc
+	makedepends = intltool
+	makedepends = kmod
+	makedepends = libcap
+	makedepends = libidn
+	makedepends = libgcrypt
+	makedepends = libmicrohttpd
+	makedepends = libxslt
+	makedepends = util-linux
+	makedepends = linux-api-headers
+	makedepends = lz4
+	makedepends = pam
+	makedepends = python
+	makedepends = python-lxml
+	makedepends = quota-tools
+	makedepends = shadow
+	makedepends = xz
+	options = strip
+	options = debug
+	source = http://www.freedesktop.org/software/systemd/systemd-218.tar.xz
+	source = initcpio-hook-udev
+	source = initcpio-install-systemd
+	source = initcpio-install-udev
+	md5sums = 4e2c511b0a7932d7fc9d79822273aac6
+	md5sums = 90ea67a7bb237502094914622a39e281
+	md5sums = c9db3010602913559295de3481019681
+	md5sums = bde43090d4ac0ef048e3eaee8202a407
+
+pkgname = systemd
+	pkgdesc = system and service manager
+	install = systemd.install
+	license = GPL2
+	license = LGPL2.1
+	license = MIT
+	depends = acl
+	depends = bash
+	depends = dbus
+	depends = glib2
+	depends = kbd
+	depends = kmod
+	depends = hwids
+	depends = libcap
+	depends = libgcrypt
+	depends = libsystemd
+	depends = libidn
+	depends = lz4
+	depends = pam
+	depends = libseccomp
+	depends = util-linux
+	depends = xz
+	optdepends = python: systemd library bindings
+	optdepends = cryptsetup: required for encrypted block devices
+	optdepends = libmicrohttpd: remote journald capabilities
+	optdepends = quota-tools: kernel-level quota management
+	optdepends = systemd-sysvcompat: symlink package to provide sysvinit binaries
+	optdepends = polkit: allow administration as unprivileged user
+	provides = nss-myhostname
+	provides = systemd-tools=218
+	provides = udev=218
+	conflicts = nss-myhostname
+	conflicts = systemd-tools
+	conflicts = udev
+	replaces = nss-myhostname
+	replaces = systemd-tools
+	replaces = udev
+	backup = etc/dbus-1/system.d/org.freedesktop.systemd1.conf
+	backup = etc/dbus-1/system.d/org.freedesktop.hostname1.conf
+	backup = etc/dbus-1/system.d/org.freedesktop.login1.conf
+	backup = etc/dbus-1/system.d/org.freedesktop.locale1.conf
+	backup = etc/dbus-1/system.d/org.freedesktop.machine1.conf
+	backup = etc/dbus-1/system.d/org.freedesktop.timedate1.conf
+	backup = etc/pam.d/systemd-user
+	backup = etc/systemd/bootchart.conf
+	backup = etc/systemd/coredump.conf
+	backup = etc/systemd/journald.conf
+	backup = etc/systemd/logind.conf
+	backup = etc/systemd/system.conf
+	backup = etc/systemd/timesyncd.conf
+	backup = etc/systemd/resolved.conf
+	backup = etc/systemd/user.conf
+	backup = etc/udev/udev.conf
+
+pkgname = libsystemd
+	pkgdesc = systemd client libraries
+	license = GPL2
+	depends = glib2
+	depends = glibc
+	depends = libgcrypt
+	depends = lz4
+	depends = xz
+	provides = libgudev-1.0.so
+	provides = libsystemd.so
+	provides = libsystemd-daemon.so
+	provides = libsystemd-id128.so
+	provides = libsystemd-journal.so
+	provides = libsystemd-login.so
+	provides = libudev.so
+
+pkgname = systemd-sysvcompat
+	pkgdesc = sysvinit compat for systemd
+	groups = base
+	license = GPL2
+	depends = systemd
+	conflicts = sysvinit
+

+ 289 - 0
vendor/github.com/mikkeloscar/gopkgbuild/version.go

@@ -0,0 +1,289 @@
+package pkgbuild
+
+import (
+	"fmt"
+	"strconv"
+	"strings"
+)
+
+// Version string
+type Version string
+
+type CompleteVersion struct {
+	Version Version
+	Epoch   uint8
+	Pkgrel  uint8
+}
+
+func (c *CompleteVersion) String() string {
+	return fmt.Sprintf("%d-%s-%d", c.Epoch, c.Version, c.Pkgrel)
+}
+
+// NewCompleteVersion creates a CompleteVersion including basic version, epoch
+// and rel from string
+func NewCompleteVersion(s string) (*CompleteVersion, error) {
+	var err error
+	epoch := 0
+	rel := 0
+
+	// handle possible epoch
+	versions := strings.Split(s, ":")
+	if len(versions) > 2 {
+		return nil, fmt.Errorf("invalid version format: %s", s)
+	}
+
+	if len(versions) > 1 {
+		epoch, err = strconv.Atoi(versions[0])
+		if err != nil {
+			return nil, err
+		}
+	}
+
+	// handle possible rel
+	versions = strings.Split(versions[len(versions)-1], "-")
+	if len(versions) > 2 {
+		return nil, fmt.Errorf("invalid version format: %s", s)
+	}
+
+	if len(versions) > 1 {
+		rel, err = strconv.Atoi(versions[1])
+		if err != nil {
+			return nil, err
+		}
+	}
+
+	// finally check that the actual version is valid
+	if validPkgver(versions[0]) {
+		return &CompleteVersion{
+			Version: Version(versions[0]),
+			Epoch:   uint8(epoch),
+			Pkgrel:  uint8(rel),
+		}, nil
+	}
+
+	return nil, fmt.Errorf("invalid version format: %s", s)
+}
+
+// Older returns true if a is older than the argument version string
+func (a *CompleteVersion) Older(v string) bool {
+	b, err := NewCompleteVersion(v)
+	if err != nil {
+		return false
+	}
+
+	return a.cmp(b) == -1
+}
+
+// Newer returns true if a is newer than the argument version string
+func (a *CompleteVersion) Newer(v string) bool {
+	b, err := NewCompleteVersion(v)
+	if err != nil {
+		return false
+	}
+
+	return a.cmp(b) == 1
+}
+
+// Equal returns true if a is equal to the argument version string
+func (a *CompleteVersion) Equal(v string) bool {
+	b, err := NewCompleteVersion(v)
+	if err != nil {
+		return false
+	}
+
+	return a.cmp(b) == 0
+}
+
+// Compare a to b:
+// return 1: a is newer than b
+//        0: a and b are the same version
+//       -1: b is newer than a
+func (a *CompleteVersion) cmp(b *CompleteVersion) int8 {
+	if a.Epoch > b.Epoch {
+		return 1
+	}
+
+	if a.Epoch < b.Epoch {
+		return -1
+	}
+
+	if a.Version.bigger(b.Version) {
+		return 1
+	}
+
+	if b.Version.bigger(a.Version) {
+		return -1
+	}
+
+	if a.Pkgrel > b.Pkgrel {
+		return 1
+	}
+
+	if a.Pkgrel < b.Pkgrel {
+		return -1
+	}
+
+	return 0
+}
+
+// Compare alpha and numeric segments of two versions.
+// return 1: a is newer than b
+//        0: a and b are the same version
+//       -1: b is newer than a
+//
+// This is based on the rpmvercmp function used in libalpm
+// https://projects.archlinux.org/pacman.git/tree/lib/libalpm/version.c
+func rpmvercmp(a, b Version) int {
+	if a == b {
+		return 0
+	}
+
+	var one, two, ptr1, ptr2 int
+	var isNum bool
+	one, two, ptr1, ptr2 = 0, 0, 0, 0
+
+	// loop through each version segment of a and b and compare them
+	for len(a) > one && len(b) > two {
+		for len(a) > one && !isAlphaNumeric(a[one]) {
+			one++
+		}
+		for len(b) > two && !isAlphaNumeric(b[two]) {
+			two++
+		}
+
+		// if we ran to the end of either, we are finished with the loop
+		if !(len(a) > one && len(b) > two) {
+			break
+		}
+
+		// if the seperator lengths were different, we are also finished
+		if one-ptr1 != two-ptr2 {
+			if one-ptr1 < two-ptr2 {
+				return -1
+			}
+			return 1
+		}
+
+		ptr1 = one
+		ptr2 = two
+
+		// grab first completely alpha or completely numeric segment
+		// leave one and two pointing to the start of the alpha or numeric
+		// segment and walk ptr1 and ptr2 to end of segment
+		if isDigit(a[ptr1]) {
+			for len(a) > ptr1 && isDigit(a[ptr1]) {
+				ptr1++
+			}
+			for len(b) > ptr2 && isDigit(b[ptr2]) {
+				ptr2++
+			}
+			isNum = true
+		} else {
+			for len(a) > ptr1 && isAlpha(a[ptr1]) {
+				ptr1++
+			}
+			for len(b) > ptr2 && isAlpha(b[ptr2]) {
+				ptr2++
+			}
+			isNum = false
+		}
+
+		// take care of the case where the two version segments are
+		// different types: one numeric, the other alpha (i.e. empty)
+		// numeric segments are always newer than alpha segments
+		if two == ptr2 {
+			if isNum {
+				return 1
+			}
+			return -1
+		}
+
+		if isNum {
+			// we know this part of the strings only contains digits
+			// so we can ignore the error value since it should
+			// always be nil
+			as, _ := strconv.ParseInt(string(a[one:ptr1]), 10, 0)
+			bs, _ := strconv.ParseInt(string(b[two:ptr2]), 10, 0)
+
+			// whichever number has more digits wins
+			if as > bs {
+				return 1
+			}
+			if as < bs {
+				return -1
+			}
+		} else {
+			cmp := alphaCompare(a[one:ptr1], b[two:ptr2])
+			if cmp < 0 {
+				return -1
+			}
+			if cmp > 0 {
+				return 1
+			}
+		}
+
+		// advance one and two to next segment
+		one = ptr1
+		two = ptr2
+	}
+
+	// this catches the case where all numeric and alpha segments have
+	// compared identically but the segment separating characters were
+	// different
+	if len(a) <= one && len(b) <= two {
+		return 0
+	}
+
+	// the final showdown. we never want a remaining alpha string to
+	// beat an empty string. the logic is a bit weird, but:
+	// - if one is empty and two is not an alpha, two is newer.
+	// - if one is an alpha, two is newer.
+	// - otherwise one is newer.
+	if (len(a) <= one && !isAlpha(b[two])) || len(a) > one && isAlpha(a[one]) {
+		return -1
+	}
+	return 1
+}
+
+// alphaCompare compares two alpha version segments and will return a positive
+// value if a is bigger than b and a negative if b is bigger than a else 0
+func alphaCompare(a, b Version) int8 {
+	if a == b {
+		return 0
+	}
+
+	i := 0
+	for len(a) > i && len(b) > i && a[i] == b[i] {
+		i++
+	}
+
+	if len(a) == i && len(b) > i {
+		return -1
+	}
+
+	if len(b) == i {
+		return 1
+	}
+
+	return int8(a[i]) - int8(b[i])
+}
+
+// check if version number v is bigger than v2
+func (v Version) bigger(v2 Version) bool {
+	return rpmvercmp(v, v2) == 1
+}
+
+// isAlphaNumeric reports whether c is an alpha character or digit
+func isAlphaNumeric(c uint8) bool {
+	return isDigit(c) || isAlpha(c)
+}
+
+// isAlpha reports whether c is an alpha character
+func isAlpha(c uint8) bool {
+	return 'a' <= c && c <= 'z' || 'A' <= c && c <= 'Z'
+}
+
+// isDigit reports whether d is an ASCII digit
+func isDigit(d uint8) bool {
+	return '0' <= d && d <= '9'
+}

+ 122 - 0
vendor/github.com/mikkeloscar/gopkgbuild/version_test.go

@@ -0,0 +1,122 @@
+package pkgbuild
+
+import "testing"
+
+// Test version comparison
+func TestVersionComparison(t *testing.T) {
+	alphaNumeric := []Version{
+		"1.0.1",
+		"1.0.a",
+		"1.0",
+		"1.0rc",
+		"1.0pre",
+		"1.0p",
+		"1.0beta",
+		"1.0b",
+		"1.0a",
+	}
+	numeric := []Version{
+		"20141130",
+		"012",
+		"11",
+		"3.0.0",
+		"2.011",
+		"2.03",
+		"2.0",
+		"1.2",
+		"1.1.1",
+		"1.1",
+		"1.0.1",
+		"1.0.0.0.0.0",
+		"1.0",
+		"1",
+	}
+	git := []Version{
+		"r1000.b481c3c",
+		"r37.e481c3c",
+		"r36.f481c3c",
+	}
+
+	bigger := func(list []Version) {
+		for i, v := range list {
+			for _, v2 := range list[i:] {
+				if v != v2 && !v.bigger(v2) {
+					t.Errorf("%s should be bigger than %s", v, v2)
+				}
+			}
+		}
+	}
+
+	smaller := func(list []Version) {
+		for i := len(list) - 1; i >= 0; i-- {
+			v := list[i]
+			for _, v2 := range list[:i] {
+				if v != v2 && v.bigger(v2) {
+					t.Errorf("%s should be smaller than %s", v, v2)
+				}
+			}
+		}
+	}
+
+	bigger(alphaNumeric)
+	smaller(alphaNumeric)
+	bigger(numeric)
+	smaller(numeric)
+	bigger(git)
+	smaller(git)
+}
+
+// Test alphaCompare function
+func TestAlphaCompare(t *testing.T) {
+	if alphaCompare("test", "test") != 0 {
+		t.Error("should be 0")
+	}
+
+	if alphaCompare("test", "test123") > 0 {
+		t.Error("should be less than 0")
+	}
+
+	if alphaCompare("test123", "test") < 0 {
+		t.Error("should be greater than 0")
+	}
+}
+
+// Test CompleteVersion comparisons
+func TestCompleteVersionComparison(t *testing.T) {
+	a := &CompleteVersion{
+		Version: "2",
+		Epoch:   1,
+		Pkgrel:  2,
+	}
+
+	older := []string{
+		"0-3-4",
+		"1-2-1",
+		"1-1-1",
+	}
+
+	for _, o := range older {
+		if a.Older(o) {
+			t.Errorf("%s should be older than %s", o, a.String())
+		}
+	}
+
+	newer := []string{
+		"2-1-1",
+		"1-3-1",
+		"1-2-3",
+	}
+
+	for _, n := range newer {
+		if a.Newer(n) {
+			t.Errorf("%s should be newer than %s", n, a.String())
+		}
+	}
+}
+
+// Benchmark rpmvercmp
+func BenchmarkVersionCompare(b *testing.B) {
+	for i := 0; i < b.N; i++ {
+		rpmvercmp("1.0", "1.0.0")
+	}
+}