Goit

Simple and lightweight Git web server
git clone http://git.omkov.net/Goit
Log | Tree | Refs | README | Download

AuthorJakob Wakeling <[email protected]>
Date2023-08-14 08:57:25
Commit4a22b95d4b1a44bde5c239387430575ee063f9bb
Parentff9ec25a03d343b2b4ea7c538faa27264dd0233c

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