Changes
6 changed files (+151/-2)
-
-
@@ -21,6 +21,20 @@ repo:- master - main # How to generate commit diffs? Valid values are "system" and "go" (default). # # "system" uses system git to generate diff. It's faster and its output is # familiar. # # "go" uses pure-Go diff implementation. Slower, but absolutely stable output # as it does not use system git installation. Its output has unfamiliar hunk # (chunk header's context line.) Unfortunately, its performance is significantly # worse than system git. For large diffs such as auto-generated files, it can # take 10x~ times compared to system git. # # Default value is "go" for backwards compatibility. diff: go # Runtime directories. dirs: # [optional]
-
-
-
@@ -19,6 +19,10 @@ type Config struct {MainBranch []string `yaml:"mainBranch"` Ignore []string `yaml:"ignore,omitempty"` Unlisted []string `yaml:"unlisted,omitempty"` // Diff method. "system" uses system git and "go" uses go-git and go-diff. // Default is "go". Diff string `yaml:"diff"` } `yaml:"repo"` Dirs struct { Templates string `yaml:"templates"`
-
@@ -67,6 +71,7 @@ func NewWithDefaults() *Config {"README", "README.txt", "README.md", "README.adoc", "readme", "readme.txt", "readme.md", "readme.adoc", } c.Repo.Diff = "go" c.Meta.Title = "Repositories" c.StaticDirRevision = staticDirRevision
-
@@ -103,6 +108,13 @@ func (c *Config) Resolve(cwd string) error {return err } switch c.Repo.Diff { case "go": case "system": default: return fmt.Errorf("\"%s\" is not a valid repo.diff value", c.Repo.Diff) } // Override templates dir if c.Dirs.Templates != "" { if c.Dirs.Templates, err = resolvePath(c.Dirs.Templates, basePath); err != nil {
-
-
-
@@ -19,6 +19,9 @@ import (type GitRepo struct { r *git.Repository h plumbing.Hash // Repository path path string } type TagList struct {
-
@@ -84,7 +87,9 @@ func (self *TagList) Less(i, j int) bool {func Open(path string, ref string) (*GitRepo, error) { var err error g := GitRepo{} g := GitRepo{ path: path, } g.r, err = git.PlainOpen(path) if err != nil { return nil, fmt.Errorf("opening %s: %w", path, err)
-
-
git/systemdiff.go (new)
-
@@ -0,0 +1,105 @@package git import ( "bytes" "fmt" "log" "os/exec" "strings" "github.com/bluekeyes/go-gitdiff/gitdiff" "github.com/go-git/go-git/v5/plumbing/object" "github.com/pocka/legit/git/exe" ) // SystemDiff generates diff lines using system git. func (g *GitRepo) SystemDiff() (*NiceDiff, error) { c, err := g.r.CommitObject(g.h) if err != nil { return nil, fmt.Errorf("commit object: %w", err) } var parent *object.Commit if parent, err = c.Parent(0); err != nil { if err != object.ErrParentNotFound { return nil, fmt.Errorf("unable to read parent of %s: %w", c.Hash, err) } } nd := NiceDiff{} nd.Commit = c nd.Parent = parent if parent == nil { nd.Parent = &object.Commit{} } diffs, err := g.getSystemGitDiff(c) if err == nil { nd.Files = diffs for _, d := range diffs { for _, tf := range d.TextFragments { for _, l := range tf.Lines { switch l.Op { case gitdiff.OpAdd: nd.Stat.Insertions += 1 case gitdiff.OpDelete: nd.Stat.Deletions += 1 } } } } nd.Stat.FilesChanged = len(diffs) } else { log.Printf("diff generation failed: %s", err) } return &nd, nil } func (g *GitRepo) getSystemGitDiff(commit *object.Commit) ([]*gitdiff.File, error) { cmd := exec.Command(exe.GitBin(), []string{ // repo.scanPath is trusted directory, thus g.path (inside repo.scanPath) is // trusted too. // https://git-scm.com/docs/git-config#Documentation/git-config.txt-safedirectory "-c", fmt.Sprintf("safe.directory=%s", g.path), "-C", g.path, "show", commit.Hash.String(), "--no-ext-diff", }...) cmd.Env = []string{ // By default, system git tries to read from various places. // We want deterministic, configuration independent behavior here. "GIT_CONFIG_GLOBAL=/dev/null", "GIT_CONFIG_SYSTEM=/dev/null", "GIT_CONFIG_NOSYSTEM=1", fmt.Sprintf("GIT_CEILING_DIRECTORIES=%s", g.path), } stdout, err := cmd.StdoutPipe() if err != nil { return nil, fmt.Errorf("stdout pipe init failure: %w", err) } defer stdout.Close() stderr := strings.Builder{} cmd.Stderr = &stderr cmd.Stdin = &bytes.Reader{} if err := cmd.Start(); err != nil { return nil, fmt.Errorf("unable to start system git-diff: %w", err) } diffs, _, err := gitdiff.Parse(stdout) if err != nil { return nil, fmt.Errorf("unable to parse git diff: %w", err) } if err := cmd.Wait(); err != nil { log.Print(stderr.String()) return nil, fmt.Errorf("unable to run system git-diff: %w", err) } return diffs, nil }
-
-
-
@@ -25,12 +25,14 @@ func main() {var port uint var scanPath string var compileTemplatesOnRequest bool var repoDiff string var staticDirOverride string var templatesDirOverride string flag.StringVar(&cfg, "config", "", "path to config file") flag.StringVar(&host, "server.host", "", "override server.host config") flag.UintVar(&port, "server.port", 0, "override server.port config") flag.StringVar(&scanPath, "repo.scanPath", "", "override repo.scanPath config") flag.StringVar(&repoDiff, "repo.diff", "", "override repo.diff config") flag.BoolVar(&compileTemplatesOnRequest, "compileTemplatesOnRequest", false, "override compileTemplatesOnRequest config") flag.StringVar(&staticDirOverride, "dirs.static", "", "override dirs.static config") flag.StringVar(&templatesDirOverride, "dirs.templates", "", "override dirs.templates config")
-
@@ -61,6 +63,10 @@ func main() {c.Repo.ScanPath = scanPath } if repoDiff != "" { c.Repo.Diff = repoDiff } if compileTemplatesOnRequest { c.CompileTemplatesOnRequest = true }
-
-
-
@@ -7,6 +7,8 @@ import ("net/http" "path/filepath" "strings" "github.com/pocka/legit/git" ) func (d *deps) serveRepoTree(w http.ResponseWriter, r *http.Request) {
-
@@ -101,7 +103,12 @@ func (d *deps) serveDiff(w http.ResponseWriter, r *http.Request) {return } diff, err := gr.Diff() var diff *git.NiceDiff if d.c.Repo.Diff == "system" { diff, err = gr.SystemDiff() } else { diff, err = gr.Diff() } if err != nil { d.write500(w, r) log.Println(err)
-