Parcourir la source

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.
morganamilo il y a 7 ans
Parent
commit
f20fbd25c1
5 fichiers modifiés avec 137 ajouts et 20 suppressions
  1. 23 1
      cmd.go
  2. 2 0
      config.go
  3. 17 1
      download.go
  4. 93 18
      install.go
  5. 2 0
      utils.go

+ 23 - 1
cmd.go

@@ -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
+}

+ 2 - 0
config.go

@@ -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.

+ 17 - 1
download.go

@@ -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)

+ 93 - 18
install.go

@@ -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) {

+ 2 - 0
utils.go

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