git, routes: commit diff view

This commit is contained in:
Anirudh Oppiliappan 2022-12-12 17:17:49 +05:30
parent ce71721c6d
commit c165c44768
No known key found for this signature in database
GPG key ID: 8A93F96F78C5D4C4
6 changed files with 198 additions and 0 deletions

99
git/diff.go Normal file
View file

@ -0,0 +1,99 @@
package git
import (
"fmt"
"log"
"strings"
"github.com/bluekeyes/go-gitdiff/gitdiff"
"github.com/go-git/go-git/v5/plumbing/object"
)
type TextFragment struct {
Header string
Lines []gitdiff.Line
}
type Diff struct {
Name struct {
Old string
New string
}
TextFragments []TextFragment
}
// A nicer git diff representation.
type NiceDiff struct {
Commit struct {
Message string
Author object.Signature
This string
Parent string
}
Stat struct {
FilesChanged int
Insertions int
Deletions int
}
Diff []Diff
}
func (g *GitRepo) Diff() (*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 len(c.ParentHashes) > 0 {
parent, err = c.Parent(0)
if err != nil {
return nil, fmt.Errorf("getting parent: %w", err)
}
} else {
parent = c
}
patch, err := parent.Patch(c)
if err != nil {
return nil, fmt.Errorf("patch: %w", err)
}
diffs, _, err := gitdiff.Parse(strings.NewReader(patch.String()))
if err != nil {
log.Println(err)
}
nd := NiceDiff{}
nd.Commit.This = c.Hash.String()
nd.Commit.Parent = parent.Hash.String()
nd.Commit.Author = c.Author
nd.Commit.Message = c.Message
ndiff := Diff{}
for _, d := range diffs {
ndiff.Name.New = d.NewName
ndiff.Name.Old = d.OldName
for _, tf := range d.TextFragments {
ndiff.TextFragments = append(ndiff.TextFragments, TextFragment{
Header: tf.Header(),
Lines: tf.Lines,
})
for _, l := range tf.Lines {
switch l.Op {
case gitdiff.OpAdd:
nd.Stat.Insertions += 1
case gitdiff.OpDelete:
nd.Stat.Deletions += 1
}
}
}
nd.Diff = append(nd.Diff, ndiff)
}
nd.Stat.FilesChanged = len(diffs)
return &nd, nil
}

2
go.mod
View file

@ -12,6 +12,7 @@ require (
github.com/Microsoft/go-winio v0.5.2 // indirect
github.com/ProtonMail/go-crypto v0.0.0-20221026131551-cf6655e29de4 // indirect
github.com/acomagu/bufpipe v1.0.3 // indirect
github.com/bluekeyes/go-gitdiff v0.7.0 // indirect
github.com/cloudflare/circl v1.1.0 // indirect
github.com/emirpasic/gods v1.18.1 // indirect
github.com/go-git/gcfg v1.5.0 // indirect
@ -22,6 +23,7 @@ require (
github.com/pjbgf/sha1cd v0.2.0 // indirect
github.com/sergi/go-diff v1.1.0 // indirect
github.com/skeema/knownhosts v1.1.0 // indirect
github.com/sourcegraph/go-diff v0.6.1 // indirect
github.com/xanzy/ssh-agent v0.3.2 // indirect
golang.org/x/crypto v0.3.0 // indirect
golang.org/x/net v0.2.0 // indirect

8
go.sum
View file

@ -10,6 +10,8 @@ github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFI
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4=
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
github.com/bluekeyes/go-gitdiff v0.7.0 h1:w4SrRFcufU0/tEpWx3VurDBAnWfpxsmwS7yWr14meQk=
github.com/bluekeyes/go-gitdiff v0.7.0/go.mod h1:QpfYYO1E0fTVHVZAZKiRjtSGY9823iCdvGXBcEzHGbM=
github.com/bwesterb/go-ristretto v1.2.0/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0=
github.com/cloudflare/circl v1.1.0 h1:bZgT/A+cikZnKIwn7xL2OBj012Bmvho/o6RpRvv3GKY=
github.com/cloudflare/circl v1.1.0/go.mod h1:prBCrKB9DV4poKZY1l9zBXg2QJY7mvgRvtMxxK7fi4I=
@ -29,6 +31,7 @@ github.com/go-git/go-git-fixtures/v4 v4.3.1 h1:y5z6dd3qi8Hl+stezc8p3JxDkoTRqMAlK
github.com/go-git/go-git-fixtures/v4 v4.3.1/go.mod h1:8LHG1a3SRW71ettAD/jW13h8c6AqjVSeL11RAdgaqpo=
github.com/go-git/go-git/v5 v5.5.0 h1:StO/ASRvk1Pp74tr7XQ0pQwKlCFignzzTF/NLKdQzUE=
github.com/go-git/go-git/v5 v5.5.0/go.mod h1:g456XI30HAdt7GQtIf8JR6GDAdULGaR4KtfFtQa0uTg=
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/imdario/mergo v0.3.13 h1:lFzP57bqS/wsqKssCGmtLAb8A0wKjLGrve2q3PPVcBk=
@ -56,9 +59,13 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0=
github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
github.com/shurcooL/go v0.0.0-20180423040247-9e1955d9fb6e/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk=
github.com/shurcooL/go-goon v0.0.0-20170922171312-37c2f522c041/go.mod h1:N5mDOmsrJOB+vfqUK+7DmDyjhSLIIBnXo9lvZJj3MWQ=
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
github.com/skeema/knownhosts v1.1.0 h1:Wvr9V0MxhjRbl3f9nMnKnFfiWTJmtECJ9Njkea3ysW0=
github.com/skeema/knownhosts v1.1.0/go.mod h1:sKFq3RD6/TKZkSWn8boUbDC7Qkgcv+8XXijpFO6roag=
github.com/sourcegraph/go-diff v0.6.1 h1:hmA1LzxW0n1c3Q4YbrFgg4P99GSnebYa3x8gr0HZqLQ=
github.com/sourcegraph/go-diff v0.6.1/go.mod h1:iBszgVvyxdc8SFZ7gm69go2KDdt3ag071iBaWPF6cjs=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
@ -115,6 +122,7 @@ golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGm
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=

View file

@ -12,5 +12,6 @@ func Handlers(c *config.Config) *flow.Mux {
mux.HandleFunc("/:name/tree/:ref/...", d.RepoTree, "GET")
mux.HandleFunc("/:name/blob/:ref/...", d.FileContent, "GET")
mux.HandleFunc("/:name/log/:ref", d.Log, "GET")
mux.HandleFunc("/:name/commit/:ref", d.Diff, "GET")
return mux
}

View file

@ -127,3 +127,39 @@ func (d *deps) Log(w http.ResponseWriter, r *http.Request) {
return
}
}
func (d *deps) Diff(w http.ResponseWriter, r *http.Request) {
name := flow.Param(r.Context(), "name")
ref := flow.Param(r.Context(), "ref")
path := filepath.Join(d.c.Git.ScanPath, name+".git")
gr, err := git.Open(path, ref)
if err != nil {
Write404(w, *d.c)
return
}
diff, err := gr.Diff()
if err != nil {
Write500(w, *d.c)
log.Println(err)
return
}
tpath := filepath.Join(d.c.Template.Dir, "*")
t := template.Must(template.ParseGlob(tpath))
data := make(map[string]interface{})
data["commit"] = diff.Commit
data["stat"] = diff.Stat
data["diff"] = diff.Diff
data["meta"] = d.c.Meta
data["name"] = name
data["ref"] = ref
if err := t.ExecuteTemplate(w, "commit", data); err != nil {
log.Println(err)
return
}
}

52
templates/commit.html Normal file
View file

@ -0,0 +1,52 @@
{{ define "commit" }}
<html>
{{ template "head" . }}
<header>
<h1>{{ .meta.Title }}</h1>
<h2>{{ .meta.Description }}</h2>
</header>
<body>
{{ template "nav" . }}
<main>
<section>
<p>author: {{ .commit.Author.Name }} <{{ .commit.Author.Email}}> on {{ .commit.Author.When }}</p>
<p>commit: <a href="/{{ .name }}/commit/{{ .commit.This }}">
{{ .commit.This }}
</a>
</p>
<p>parent: <a href="/{{ .name }}/commit/{{ .commit.Parent }}">
{{ .commit.Parent }}
</a>
</p>
<p>{{ .stat.FilesChanged }} files changed,
{{ .stat.Insertions }} insertions(+),
{{ .stat.Deletions }} deletions(-)
</p>
</section>
<section>
{{ range .diff }}
{{ if .Name.Old }}
<p>{{ .Name.Old }} → {{ .Name.New }}</p>
{{ else }}
<p>{{.Name.New }}</p>
{{- end -}}
<pre>
{{- range .TextFragments -}}
<p>{{- .Header -}}</p>
{{- range .Lines -}}
{{- if eq .Op.String "+" -}}
<span style="color: green">{{ .String }}</span>
{{- end -}}
{{- if eq .Op.String "-" -}}
<span style="color: red">{{ .String }}</span>
{{- end -}}
{{- end -}}
{{- end -}}
</pre>
{{ end }}
</section>
</main>
</body>
</html>
{{ end }}