Goit

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

AuthorJakob Wakeling <[email protected]>
Date2023-07-25 12:53:25
Commit8e4646b2a71f4f8a862be7b31ff7ff9e0e294bc4
Parent64718e1cdc44c70854777e66c08401558ff0999c

Implement repository tree page

Diffstat

M main.go | 5 +++--
M res/repo/tree.html | 20 ++++++++++++++------
M src/repo.go | 8 ++------
M src/repo/log.go | 25 +++++++++++--------------
A src/repo/tree.go | 86 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
M src/util/util.go | 14 ++++++++++++++

6 files changed, 130 insertions, 28 deletions

diff --git a/main.go b/main.go
index 9e714e5..2beaf53 100644
--- a/main.go
+++ b/main.go
@@ -25,7 +25,6 @@ func main() {
 	h.StrictSlash(true)
 
 	h.Path("/").HandlerFunc(goit.HandleIndex)
-	// h.Path("/user").Methods("GET").HandlerFunc(goit.HandleUserIndex)
 	h.Path("/user/login").Methods("GET", "POST").HandlerFunc(goit.HandleUserLogin)
 	h.Path("/user/logout").Methods("GET", "POST").HandlerFunc(goit.HandleUserLogout)
 	h.Path("/user/sessions").Methods("GET", "POST").HandlerFunc(goit.HandleUserSessions)
@@ -41,7 +40,9 @@ func main() {
 	h.Path("/{repo:.+(?:\\.git)$}").Methods("GET").HandlerFunc(redirectDotGit)
 	h.Path("/{repo}").Methods("GET").HandlerFunc(repo.HandleLog)
 	h.Path("/{repo}/log").Methods("GET").HandlerFunc(repo.HandleLog)
-	h.Path("/{repo}/tree").Methods("GET").HandlerFunc(goit.HandleRepoTree)
+	h.Path("/{repo}/log/{path:.*}").Methods("GET").HandlerFunc(repo.HandleLog)
+	h.Path("/{repo}/tree").Methods("GET").HandlerFunc(repo.HandleTree)
+	h.Path("/{repo}/tree/{path:.*}").Methods("GET").HandlerFunc(repo.HandleTree)
 	h.Path("/{repo}/refs").Methods("GET").HandlerFunc(goit.HandleRepoRefs)
 	h.Path("/{repo}/info/refs").Methods("GET").HandlerFunc(goit.HandleInfoRefs)
 	h.Path("/{repo}/git-upload-pack").Methods("POST").HandlerFunc(goit.HandleUploadPack)
diff --git a/res/repo/tree.html b/res/repo/tree.html
index 6dc6935..714fd31 100644
--- a/res/repo/tree.html
+++ b/res/repo/tree.html
@@ -6,17 +6,25 @@
 		<table>
 			<thead>
 				<tr>
+					<td><b>Mode</b></td>
 					<td><b>Name</b></td>
 					<td><b>Size</b></td>
+					<td></td>
 				</tr>
 			</thead>
 			<tbody>
-			{{range .Files}}
-				<tr>
-					<td>{{.Name}}</a></td>
-					<td>{{.Size}}</td>
-				</tr>
-			{{end}}
+				{{if .Files}}
+					{{range .Files}}
+						<tr>
+							<td>{{.Mode}}</td>
+							<td><a href="/{{$.Name}}/tree/{{.Name}}">{{.Name}}</a></td>
+							<td align="right" {{if .B}}style="padding-right: calc(2ch + 0.4em);"{{end}}>{{.Size}}</td>
+							<td>log blame raw download</td>
+						</tr>
+					{{end}}
+				{{else}}
+					<tr><td colspan="4">No files</td></tr>
+				{{end}}
 			</tbody>
 		</table>
 	</main>
diff --git a/src/repo.go b/src/repo.go
index 28c6169..3deed7c 100644
--- a/src/repo.go
+++ b/src/repo.go
@@ -126,10 +126,6 @@ func HandleRepoCreate(w http.ResponseWriter, r *http.Request) {
 	}
 }
 
-func HandleRepoTree(w http.ResponseWriter, r *http.Request) {
-	HttpError(w, http.StatusNoContent)
-}
-
 func HandleRepoRefs(w http.ResponseWriter, r *http.Request) {
 	reponame := mux.Vars(r)["repo"]
 
@@ -181,8 +177,8 @@ func HandleRepoRefs(w http.ResponseWriter, r *http.Request) {
 		Branches                      []bra
 		Tags                          []tag
 	}{
-		"Refs", reponame, repo.Description, util.If(Conf.UsesHttps, "https://", "http://") + r.Host + r.URL.Path, "",
-		"", bras, tags,
+		"Refs", reponame, repo.Description, util.If(Conf.UsesHttps, "https://", "http://") + r.Host + "/" + repo.Name,
+		"", "", bras, tags,
 	}); err != nil {
 		log.Println("[Repo:Refs]", err.Error())
 	}
diff --git a/src/repo/log.go b/src/repo/log.go
index d2a98a1..a971568 100644
--- a/src/repo/log.go
+++ b/src/repo/log.go
@@ -4,7 +4,6 @@ import (
 	"fmt"
 	"log"
 	"net/http"
-	"strconv"
 	"strings"
 	"time"
 
@@ -27,17 +26,15 @@ func HandleLog(w http.ResponseWriter, r *http.Request) {
 		return
 	}
 
-	var offset uint64 = 0
-	if o := r.URL.Query().Get("o"); o != "" {
-		if i, err := strconv.ParseUint(o, 10, 64); err != nil {
-			goit.HttpError(w, http.StatusBadRequest)
-			return
-		} else {
-			offset = i
-		}
-	}
-
-	offset += 1
+	// var offset uint64 = 0
+	// if o := r.URL.Query().Get("o"); o != "" {
+	// 	if i, err := strconv.ParseUint(o, 10, 64); err != nil {
+	// 		goit.HttpError(w, http.StatusBadRequest)
+	// 		return
+	// 	} else {
+	// 		offset = i
+	// 	}
+	// }
 
 	type row struct{ Hash, Date, Message, Author, Files, Additions, Deletions string }
 	data := struct {
@@ -45,8 +42,8 @@ func HandleLog(w http.ResponseWriter, r *http.Request) {
 		Readme, Licence               string
 		Commits                       []row
 	}{
-		Title: repo.Name + " - Log", Name: repo.Name,
-		Description: repo.Description, Url: util.If(goit.Conf.UsesHttps, "https://", "http://") + r.Host + r.URL.Path,
+		Title: repo.Name + " - Log", Name: repo.Name, Description: repo.Description,
+		Url: util.If(goit.Conf.UsesHttps, "https://", "http://") + r.Host + "/" + repo.Name,
 	}
 
 	gr, err := git.PlainOpen(goit.RepoPath(repo.Name))
diff --git a/src/repo/tree.go b/src/repo/tree.go
new file mode 100644
index 0000000..e3f22e1
--- /dev/null
+++ b/src/repo/tree.go
@@ -0,0 +1,86 @@
+package repo
+
+import (
+	"log"
+	"net/http"
+	"strings"
+
+	goit "github.com/Jamozed/Goit/src"
+	"github.com/Jamozed/Goit/src/util"
+	"github.com/dustin/go-humanize"
+	"github.com/go-git/go-git/v5"
+	"github.com/go-git/go-git/v5/plumbing/object"
+	"github.com/gorilla/mux"
+)
+
+func HandleTree(w http.ResponseWriter, r *http.Request) {
+	_, uid := goit.AuthCookie(w, r, true)
+
+	repo, err := goit.GetRepoByName(mux.Vars(r)["repo"])
+	if err != nil {
+		goit.HttpError(w, http.StatusInternalServerError)
+		return
+	} else if repo == nil || (repo.IsPrivate && repo.OwnerId != uid) {
+		goit.HttpError(w, http.StatusNotFound)
+		return
+	}
+
+	type row struct {
+		Mode, Name, Size string
+		B                bool
+	}
+	data := struct {
+		Title, Name, Description, Url string
+		Readme, Licence               string
+		Files                         []row
+	}{
+		Title: repo.Name + " - Tree", Name: repo.Name, Description: repo.Description,
+		Url: util.If(goit.Conf.UsesHttps, "https://", "http://") + r.Host + "/" + repo.Name,
+	}
+
+	gr, err := git.PlainOpen(goit.RepoPath(repo.Name))
+	if err != nil {
+		log.Println("[/repo/tree]", err.Error())
+		goit.HttpError(w, http.StatusInternalServerError)
+		return
+	}
+
+	ref, err := gr.Head()
+	if err != nil {
+		log.Println("[/repo/tree]", err.Error())
+		goit.HttpError(w, http.StatusInternalServerError)
+		return
+	}
+
+	commit, err := gr.CommitObject(ref.Hash())
+	if err != nil {
+		log.Println("[/repo/tree]", err.Error())
+		goit.HttpError(w, http.StatusInternalServerError)
+		return
+	}
+
+	iter, err := commit.Tree()
+	if err != nil {
+		log.Println("[/repo/tree]", err.Error())
+		goit.HttpError(w, http.StatusInternalServerError)
+		return
+	}
+
+	if err := iter.Files().ForEach(func(f *object.File) error {
+		size := humanize.IBytes(uint64(f.Size))
+		data.Files = append(data.Files, row{
+			Mode: util.ModeString(uint32(f.Mode)), Name: f.Name, Size: size,
+			B: util.If(strings.HasSuffix(size, " B"), true, false),
+		})
+
+		return nil
+	}); err != nil {
+		log.Println("[/repo/tree]", err.Error())
+		goit.HttpError(w, http.StatusInternalServerError)
+		return
+	}
+
+	if err := goit.Tmpl.ExecuteTemplate(w, "repo/tree", data); err != nil {
+		log.Println("[/repo/tree]", err.Error())
+	}
+}
diff --git a/src/util/util.go b/src/util/util.go
index bc3e587..0a75dd8 100644
--- a/src/util/util.go
+++ b/src/util/util.go
@@ -35,3 +35,17 @@ func Cookie(r *http.Request, name string) *http.Cookie {
 
 	return nil
 }
+
+func ModeString(mode uint32) string {
+	s := "-"
+	s += If((mode&0b100000000) != 0, "r", "-")
+	s += If((mode&0b010000000) != 0, "w", "-")
+	s += If((mode&0b001000000) != 0, "x", "-")
+	s += If((mode&0b000100000) != 0, "r", "-")
+	s += If((mode&0b000010000) != 0, "w", "-")
+	s += If((mode&0b000001000) != 0, "x", "-")
+	s += If((mode&0b000000100) != 0, "r", "-")
+	s += If((mode&0b000000010) != 0, "w", "-")
+	s += If((mode&0b000000001) != 0, "x", "-")
+	return s
+}