Implement diffs for pkgbuild viewing.

diff viewing can be toggled via --[no]showdiffs. When enabled diffs will
be shown for packages between the current HEAD and upstream's HEAD.
Packages downloaded via tarballs will be shown in full using the editor

git diff is used to show diffs. Therefore the pager for diffs can be
set via the PAGER and GIT_PAGER enviroment variables.
This commit is contained in:
morganamilo 2018-05-31 20:31:45 +01:00
parent af91c2f1b8
commit f20fbd25c1
No known key found for this signature in database
GPG key ID: 6FE9E7996B0B082E
5 changed files with 137 additions and 20 deletions

24
cmd.go
View file

@ -304,6 +304,10 @@ func handleConfig(option, value string) bool {
config.PGPFetch = true
case "nopgpfetch":
config.PGPFetch = false
case "showdiffs":
config.ShowDiffs = true
case "noshowdiffs":
config.ShowDiffs = false
case "a", "aur":
mode = ModeAUR
case "repo":
@ -603,7 +607,6 @@ func passToMakepkgCapture(dir string, args ...string) (string, string, error) {
args = append(args, mflags...)
cmd := exec.Command(config.MakepkgBin, args...)
cmd.Stdin, cmd.Stdout, cmd.Stderr = os.Stdin, os.Stdout, os.Stderr
cmd.Dir = dir
cmd.Stdout = &outbuf
cmd.Stderr = &errbuf
@ -630,3 +633,22 @@ func passToGit(dir string, _args ...string) (err error) {
err = cmd.Run()
return
}
func passToGitCapture(dir string, _args ...string) (string, string, error) {
var outbuf, errbuf bytes.Buffer
gitflags := strings.Fields(config.GitFlags)
args := []string{"-C", dir}
args = append(args, gitflags...)
args = append(args, _args...)
cmd := exec.Command(config.GitBin, args...)
cmd.Dir = dir
cmd.Stdout = &outbuf
cmd.Stderr = &errbuf
err := cmd.Run()
stdout := outbuf.String()
stderr := errbuf.String()
return stdout, stderr, err
}

View file

@ -64,6 +64,7 @@ type Configuration struct {
GitClone bool `json:"gitclone"`
Provides bool `json:"provides"`
PGPFetch bool `json:"pgpfetch"`
ShowDiffs bool `json:"showdifs"`
}
var version = "5.688"
@ -167,6 +168,7 @@ func defaultSettings(config *Configuration) {
config.AnswerUpgrade = ""
config.GitClone = true
config.Provides = true
config.ShowDiffs = true
}
// Editor returns the preferred system editor.

View file

@ -7,6 +7,7 @@ import (
"os"
"os/exec"
"path/filepath"
"strings"
)
// Decide what download method to use:
@ -20,7 +21,7 @@ func shouldUseGit(path string) bool {
}
_, err = os.Stat(filepath.Join(path, ".git"))
return os.IsExist(err)
return err == nil || os.IsExist(err)
}
func downloadFile(path string, url string) (err error) {
@ -43,6 +44,15 @@ func downloadFile(path string, url string) (err error) {
return err
}
func gitGetHash(path string, name string) (string, error) {
stdout, stderr, err := passToGitCapture(filepath.Join(path, name), "rev-parse", "HEAD")
if err != nil {
return "", fmt.Errorf("%s%s", stderr, err)
}
return strings.TrimSpace(stdout), nil
}
func gitDownload(url string, path string, name string) error {
_, err := os.Stat(filepath.Join(path, name, ".git"))
if os.IsNotExist(err) {
@ -74,6 +84,12 @@ func gitDownload(url string, path string, name string) error {
return nil
}
func gitDiff(path string, name string) error {
err := passToGit(filepath.Join(path, name), "diff", "HEAD..HEAD@{upstream}")
return err
}
// DownloadAndUnpack downloads url tgz and extracts to path.
func downloadAndUnpack(url string, path string) (err error) {
err = os.MkdirAll(path, 0755)

View file

@ -153,13 +153,17 @@ func install(parser *arguments) error {
cleanBuilds(toClean)
err = downloadPkgBuilds(do.Aur, parser.targets, do.Bases)
oldHashes, err := downloadPkgBuilds(do.Aur, parser.targets, do.Bases)
if err != nil {
return err
}
if len(toEdit) > 0 {
err = editPkgBuilds(toEdit)
if config.ShowDiffs {
err = showPkgBuildDiffs(toEdit, do.Bases, oldHashes)
} else {
err = editPkgBuilds(toEdit, do.Bases, oldHashes)
}
if err != nil {
return err
}
@ -422,7 +426,11 @@ func cleanEditNumberMenu(pkgs []*rpc.Pkg, bases map[string][]*rpc.Pkg, installed
}
}
fmt.Println(bold(green(arrow + " PKGBUILDs to edit?")))
if config.ShowDiffs {
fmt.Println(bold(green(arrow + " Diffs to show?")))
} else {
fmt.Println(bold(green(arrow + " PKGBUILDs to edit?")))
}
fmt.Println(bold(green(arrow) + cyan(" [N]one ") + "[A]ll [Ab]ort [I]nstalled [No]tInstalled or (1 2 3, 1-3, ^4)"))
fmt.Print(bold(green(arrow + " ")))
@ -481,20 +489,66 @@ func cleanBuilds(pkgs []*rpc.Pkg) {
}
}
func editPkgBuilds(pkgs []*rpc.Pkg) error {
func showPkgBuildDiffs(pkgs []*rpc.Pkg, bases map[string][]*rpc.Pkg, hashes map[string]string) error {
for _, pkg := range pkgs {
dir := filepath.Join(config.BuildDir, pkg.PackageBase)
if shouldUseGit(dir) {
hash, _ := hashes[pkg.PackageBase]
if hash == "" {
hash = gitEmptyTree
}
head, err := gitGetHash(config.BuildDir, pkg.PackageBase)
if err != nil {
return err
}
if head == hash {
fmt.Printf("%s %s: %s\n", bold(yellow(arrow)), cyan(formatPkgbase(pkg, bases)), bold("No changes -- skipping"))
continue
}
args := []string{"diff", hash + "..HEAD", "--src-prefix", dir + "/", "--dst-prefix", dir + "/"}
if useColor {
args = append(args, "--color=always")
} else {
args = append(args, "--color=never")
}
err = passToGit(dir, args...)
if err != nil {
return err
}
} else {
editor, editorArgs := editor()
editorArgs = append(editorArgs, filepath.Join(dir, "PKGBUILD"))
editcmd := exec.Command(editor, editorArgs...)
editcmd.Stdin, editcmd.Stdout, editcmd.Stderr = os.Stdin, os.Stdout, os.Stderr
err := editcmd.Run()
if err != nil {
return fmt.Errorf("Editor did not exit successfully, Aborting: %s", err)
}
}
}
return nil
}
func editPkgBuilds(pkgs []*rpc.Pkg, bases map[string][]*rpc.Pkg, hashes map[string]string) error {
pkgbuilds := make([]string, 0, len(pkgs))
for _, pkg := range pkgs {
dir := filepath.Join(config.BuildDir, pkg.PackageBase)
pkgbuilds = append(pkgbuilds, filepath.Join(dir, "PKGBUILD"))
}
editor, editorArgs := editor()
editorArgs = append(editorArgs, pkgbuilds...)
editcmd := exec.Command(editor, editorArgs...)
editcmd.Stdin, editcmd.Stdout, editcmd.Stderr = os.Stdin, os.Stdout, os.Stderr
err := editcmd.Run()
if err != nil {
return fmt.Errorf("Editor did not exit successfully, Aborting: %s", err)
if len(pkgbuilds) > 0 {
editor, editorArgs := editor()
editorArgs = append(editorArgs, pkgbuilds...)
editcmd := exec.Command(editor, editorArgs...)
editcmd.Stdin, editcmd.Stdout, editcmd.Stderr = os.Stdin, os.Stdout, os.Stderr
err := editcmd.Run()
if err != nil {
return fmt.Errorf("Editor did not exit successfully, Aborting: %s", err)
}
}
return nil
@ -535,8 +589,11 @@ func tryParsesrcinfosFile(pkgs []*rpc.Pkg, srcinfos map[string]*gopkg.PKGBUILD,
}
}
func downloadPkgBuilds(pkgs []*rpc.Pkg, targets stringSet, bases map[string][]*rpc.Pkg) error {
for k, pkg := range pkgs {
func downloadPkgBuilds(pkgs []*rpc.Pkg, targets stringSet, bases map[string][]*rpc.Pkg) (map[string]string, error) {
toSkip := make(stringSet)
hashes := make(map[string]string)
for _, pkg := range pkgs {
if config.ReDownload == "no" || (config.ReDownload == "yes" && !targets.get(pkg.Name)) {
dir := filepath.Join(config.BuildDir, pkg.PackageBase, ".SRCINFO")
pkgbuild, err := gopkg.ParseSRCINFO(dir)
@ -546,13 +603,28 @@ func downloadPkgBuilds(pkgs []*rpc.Pkg, targets stringSet, bases map[string][]*r
versionPKG, errP := gopkg.NewCompleteVersion(pkgbuild.Version())
if errP == nil && errR == nil {
if !versionRPC.Newer(versionPKG) {
str := bold(cyan("::") + " PKGBUILD up to date, Skipping (%d/%d): %s\n")
fmt.Printf(str, k+1, len(pkgs), cyan(formatPkgbase(pkg, bases)))
continue
toSkip.set(pkg.PackageBase)
}
}
}
}
}
for k, pkg := range pkgs {
if shouldUseGit(filepath.Join(config.BuildDir, pkg.PackageBase)) {
hash, err := gitGetHash(config.BuildDir, pkg.PackageBase)
if err == nil {
hashes[pkg.PackageBase] = hash
} else {
hashes[pkg.PackageBase] = ""
}
}
if toSkip.get(pkg.PackageBase) {
str := bold(cyan("::") + " PKGBUILD up to date, Skipping (%d/%d): %s\n")
fmt.Printf(str, k+1, len(pkgs), cyan(formatPkgbase(pkg, bases)))
continue
}
str := bold(cyan("::") + " Downloading PKGBUILD (%d/%d): %s\n")
@ -561,15 +633,18 @@ func downloadPkgBuilds(pkgs []*rpc.Pkg, targets stringSet, bases map[string][]*r
var err error
if shouldUseGit(filepath.Join(config.BuildDir, pkg.PackageBase)) {
err = gitDownload(baseURL+"/"+pkg.PackageBase+".git", config.BuildDir, pkg.PackageBase)
if err != nil {
return hashes, err
}
} else {
err = downloadAndUnpack(baseURL+pkg.URLPath, config.BuildDir)
}
if err != nil {
return err
return hashes, err
}
}
return nil
return hashes, nil
}
func downloadPkgBuildsSources(pkgs []*rpc.Pkg, bases map[string][]*rpc.Pkg, incompatible stringSet) (err error) {

View file

@ -4,6 +4,8 @@ import (
"unicode"
)
const gitEmptyTree = "4b825dc642cb6eb9a060e54bf8d69288fbee4904"
type mapStringSet map[string]stringSet
type intRange struct {