Author | Jakob Wakeling <[email protected]> |
Date | 2023-08-14 08:57:25 |
Commit | 4a22b95d4b1a44bde5c239387430575ee063f9bb |
Parent | ff9ec25a03d343b2b4ea7c538faa27264dd0233c |
Improve commit diff statistics
Diffstat
M | res/repo/commit.html | | | 20 | +++++++++++++------- |
M | src/git.go | | | 88 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
M | src/repo/commit.go | | | 21 | ++++++++++++++++----- |
A | src/repo/edit.go | | | 29 | +++++++++++++++++++++++++++++ |
M | src/repo/log.go | | | 7 | ++++--- |
5 files changed, 150 insertions, 15 deletions
diff --git a/res/repo/commit.html b/res/repo/commit.html index fd18c70..c3bcbde 100644 --- a/res/repo/commit.html +++ b/res/repo/commit.html @@ -15,14 +15,20 @@ <p>{{.MessageBody}}</p> <h2>Diffstat</h2> <table> - {{range .DiffStat}} + {{range .Stats}} <tr> - <td><a href="/{{$.Name}}/file/{{.Name}}">{{.Name}}</a></td> - <td>|</td><td>{{.Num}}</td> - <td> - <span style="color: #008800;">{{.Plusses}}</span><!-- - --><span style="color: #AA0000;">{{.Minuses}}</span> - </td> + <td>{{.Status}}</td> + <td><a href="/{{$.Name}}/file/{{.Path}}">{{.Name}}</a></td> + <td>|</td> + {{if .IsBinary}} + <td colspan="2">binary</td> + {{else}} + <td>{{.Num}}</td> + <td> + <span style="color: #008800;">{{.Plusses}}</span><!-- + --><span style="color: #AA0000;">{{.Minuses}}</span> + </td> + {{end}} </tr> {{end}} </table> diff --git a/src/git.go b/src/git.go index 0dbd706..0d729d2 100644 --- a/src/git.go +++ b/src/git.go @@ -15,6 +15,8 @@ import ( "strconv" "strings" + "github.com/go-git/go-git/v5/plumbing/format/diff" + "github.com/go-git/go-git/v5/plumbing/object" "github.com/gorilla/mux" ) @@ -216,3 +218,89 @@ func (C *gitCommand) Run(in io.Reader, out io.Writer) ([]byte, []byte, error) { return stdout.Bytes(), stderr.Bytes(), nil } + +type DiffStat struct { + Name, Prev string + Status string + Addition int + Deletion int + IsBinary bool +} + +func DiffStats(c *object.Commit) ([]DiffStat, error) { + from, err := c.Tree() + if err != nil { + return nil, err + } + + to := &object.Tree{} + if c.NumParents() != 0 { + parent, err := c.Parents().Next() + if err != nil { + return nil, err + } + + to, err = parent.Tree() + if err != nil { + return nil, err + } + } + + patch, err := to.Patch(from) + if err != nil { + return nil, err + } + + var stats []DiffStat + for _, fp := range patch.FilePatches() { + var stat DiffStat + + if len(fp.Chunks()) == 0 { + if !fp.IsBinary() { + continue + } + + stat.IsBinary = true + } + + from, to := fp.Files() + if from == nil /* Added */ { + stat.Name = to.Path() + stat.Status = "A" + } else if to == nil /* Deleted */ { + stat.Name = from.Path() + stat.Status = "D" + } else if from.Path() != to.Path() /* Renamed */ { + stat.Name = to.Path() + stat.Prev = from.Path() + stat.Status = "R" + } else { + stat.Name = from.Path() + stat.Status = "M" + } + + for _, chunk := range fp.Chunks() { + s := chunk.Content() + if len(s) == 0 { + continue + } + + switch chunk.Type() { + case diff.Add: + stat.Addition += strings.Count(s, "\n") + if s[len(s)-1] != '\n' { + stat.Addition++ + } + case diff.Delete: + stat.Deletion += strings.Count(s, "\n") + if s[len(s)-1] != '\n' { + stat.Deletion++ + } + } + } + + stats = append(stats, stat) + } + + return stats, nil +} diff --git a/src/repo/commit.go b/src/repo/commit.go index adaa868..1058d3b 100644 --- a/src/repo/commit.go +++ b/src/repo/commit.go @@ -31,13 +31,18 @@ func HandleCommit(w http.ResponseWriter, r *http.Request) { return } + type stat struct { + Name, Path, Status, Num, Plusses, Minuses string + IsBinary bool + } + data := struct { Title, Name, Description, Url string Readme, Licence string Author, Date, Commit string Parents []string MessageSubject, MessageBody string - DiffStat []struct{ Name, Num, Plusses, Minuses string } + Stats []stat Summary string Diff template.HTML }{ @@ -90,7 +95,7 @@ func HandleCommit(w http.ResponseWriter, r *http.Request) { data.MessageSubject = message[0] data.MessageBody = message[1] - st, err := commit.Stats() + st, err := goit.DiffStats(commit) if err != nil { log.Println("[/repo/commit]", err.Error()) goit.HttpError(w, http.StatusInternalServerError) @@ -99,8 +104,7 @@ func HandleCommit(w http.ResponseWriter, r *http.Request) { var files, additions, deletions int = len(st), 0, 0 for _, s := range st { - /* TODO handle renames */ - f := struct{ Name, Num, Plusses, Minuses string }{Name: s.Name} + f := stat{Name: s.Name, Path: s.Name, Status: s.Status} f.Num = strconv.FormatInt(int64(s.Addition+s.Deletion), 10) if s.Addition+s.Deletion > 80 { @@ -111,7 +115,14 @@ func HandleCommit(w http.ResponseWriter, r *http.Request) { f.Minuses = strings.Repeat("-", s.Deletion) } - data.DiffStat = append(data.DiffStat, f) + if s.Status == "R" { + f.Name = s.Prev + " -> " + s.Name + } + if s.IsBinary { + f.IsBinary = true + } + + data.Stats = append(data.Stats, f) additions += s.Addition deletions += s.Deletion diff --git a/src/repo/edit.go b/src/repo/edit.go new file mode 100644 index 0000000..b259065 --- /dev/null +++ b/src/repo/edit.go @@ -0,0 +1,29 @@ +package repo + +import ( + "log" + "net/http" + + goit "github.com/Jamozed/Goit/src" + "github.com/gorilla/mux" +) + +func HandleEdit(w http.ResponseWriter, r *http.Request) { + auth, uid := goit.AuthCookie(w, r, true) + + repo, err := goit.GetRepoByName(mux.Vars(r)["repo"]) + if err != nil { + log.Println("[/repo/edit]", err.Error()) + goit.HttpError(w, http.StatusInternalServerError) + return + } else if repo == nil || (!auth || repo.OwnerId != uid) { + goit.HttpError(w, http.StatusNotFound) + return + } + + // data := struct { + // Title string + // }{ + // Title: "Repository - Edit", + // } +} diff --git a/src/repo/log.go b/src/repo/log.go index 7c0f08a..03e46d0 100644 --- a/src/repo/log.go +++ b/src/repo/log.go @@ -79,7 +79,7 @@ func HandleLog(w http.ResponseWriter, r *http.Request) { } else if err := iter.ForEach(func(c *object.Commit) error { var files, additions, deletions int - if stats, err := c.Stats(); err != nil { + if stats, err := goit.DiffStats(c); err != nil { log.Println("[/repo/log]", err.Error()) } else { files = len(stats) @@ -90,8 +90,9 @@ func HandleLog(w http.ResponseWriter, r *http.Request) { } data.Commits = append(data.Commits, row{ - c.Hash.String(), c.Author.When.UTC().Format(time.DateTime), strings.SplitN(c.Message, "\n", 2)[0], - c.Author.Name, fmt.Sprint(files), "+" + fmt.Sprint(additions), "-" + fmt.Sprint(deletions), + Hash: c.Hash.String(), Date: c.Author.When.UTC().Format(time.DateTime), + Message: strings.SplitN(c.Message, "\n", 2)[0], Author: c.Author.Name, Files: fmt.Sprint(files), + Additions: "+" + fmt.Sprint(additions), Deletions: "-" + fmt.Sprint(deletions), }) return nil