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-02 09:44:07
Commit7ba1b21b11fb9266c475104434c93714b2b67af9
Parent5aa454cedeed0b7d4c4e48142cdac4d3793fdd7b

Add README and LICENCE links in repo header

Diffstat

M README.md | 2 +-
M res/repo/header.html | 4 ++--
M src/repo/file.go | 8 ++++++++
M src/repo/log.go | 26 +++++++++++++++++++-------
M src/repo/repo.go | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
M src/repo/tree.go | 7 +++++++

6 files changed, 97 insertions, 10 deletions

diff --git a/README.md b/README.md
index 6f5616e..cbcde10 100644
--- a/README.md
+++ b/README.md
@@ -7,7 +7,7 @@ A simple and lightweight Git web server.
 - Git Smart HTTP protocol (v2 only)
 - Git SSH protocol (planned)
 - Repository log, tree, refs, and commit viewers
-- File viewer with syntax highlighting and markdown support (planned)
+- File viewer with syntax highlighting (planned)
 - File raw, blame, and history views (planned)
 - Public and private repositories
 - Read and write permissions for non owners (planned)
diff --git a/res/repo/header.html b/res/repo/header.html
index 3d249a1..c59fbae 100644
--- a/res/repo/header.html
+++ b/res/repo/header.html
@@ -19,10 +19,10 @@
 			| <a href="/{{.Name}}/tree">Tree</a>
 			| <a href="/{{.Name}}/refs">Refs</a>
 			{{if .Readme}}
-				| <a href="">README</a>
+				| <a href="{{.Readme}}">README</a>
 			{{end}}
 			{{if .Licence}}
-				| <a href="">LICENCE</a>
+				| <a href="{{.Licence}}">LICENCE</a>
 			{{end}}
 		</td>
 	</tr>
diff --git a/src/repo/file.go b/src/repo/file.go
index e19dadd..09e3979 100644
--- a/src/repo/file.go
+++ b/src/repo/file.go
@@ -5,6 +5,7 @@ import (
 	"io"
 	"log"
 	"net/http"
+	"path"
 	"strings"
 
 	goit "github.com/Jamozed/Goit/src"
@@ -61,6 +62,13 @@ func HandleFile(w http.ResponseWriter, r *http.Request) {
 		return
 	}
 
+	if readme, _ := findReadme(gr, ref); readme != "" {
+		data.Readme = path.Join("/", repo.Name, "file", readme)
+	}
+	if licence, _ := findLicence(gr, ref); licence != "" {
+		data.Licence = path.Join("/", repo.Name, "file", licence)
+	}
+
 	commit, err := gr.CommitObject(ref.Hash())
 	if err != nil {
 		log.Println("[/repo/file]", err.Error())
diff --git a/src/repo/log.go b/src/repo/log.go
index 01f63ef..ab408d6 100644
--- a/src/repo/log.go
+++ b/src/repo/log.go
@@ -5,6 +5,7 @@ import (
 	"fmt"
 	"log"
 	"net/http"
+	"path"
 	"strings"
 	"time"
 
@@ -55,13 +56,23 @@ func HandleLog(w http.ResponseWriter, r *http.Request) {
 		return
 	}
 
-	if ref, err := gr.Head(); err != nil {
-		if !errors.Is(err, plumbing.ErrReferenceNotFound) {
-			log.Println("[/repo/log]", err.Error())
-			goit.HttpError(w, http.StatusInternalServerError)
-			return
-		}
-	} else if iter, err := gr.Log(&git.LogOptions{From: ref.Hash()}); err != nil {
+	ref, err := gr.Head()
+	if errors.Is(err, plumbing.ErrReferenceNotFound) {
+		goto execute
+	} else if err != nil {
+		log.Println("[/repo/log]", err.Error())
+		goit.HttpError(w, http.StatusInternalServerError)
+		return
+	}
+
+	if readme, _ := findReadme(gr, ref); readme != "" {
+		data.Readme = path.Join("/", repo.Name, "file", readme)
+	}
+	if licence, _ := findLicence(gr, ref); licence != "" {
+		data.Licence = path.Join("/", repo.Name, "file", licence)
+	}
+
+	if iter, err := gr.Log(&git.LogOptions{From: ref.Hash()}); err != nil {
 		log.Println("[/repo/log]", err.Error())
 		goit.HttpError(w, http.StatusInternalServerError)
 		return
@@ -90,6 +101,7 @@ func HandleLog(w http.ResponseWriter, r *http.Request) {
 		return
 	}
 
+execute:
 	if err := goit.Tmpl.ExecuteTemplate(w, "repo/log", data); err != nil {
 		log.Println("[/repo/log]", err.Error())
 	}
diff --git a/src/repo/repo.go b/src/repo/repo.go
index 3299296..f118a21 100644
--- a/src/repo/repo.go
+++ b/src/repo/repo.go
@@ -3,11 +3,19 @@ package repo
 import (
 	"log"
 	"net/http"
+	"regexp"
 	"strconv"
 
 	goit "github.com/Jamozed/Goit/src"
+	"github.com/go-git/go-git/v5"
+	"github.com/go-git/go-git/v5/plumbing"
+	"github.com/go-git/go-git/v5/plumbing/object"
+	"github.com/go-git/go-git/v5/plumbing/storer"
 )
 
+var readmePattern = regexp.MustCompile(`(?i)^readme(?:\.?(?:md|txt))?$`)
+var licencePattern = regexp.MustCompile(`(?i)^licence(?:\.?(?:md|txt))?$`)
+
 func HandleDelete(w http.ResponseWriter, r *http.Request) {
 	auth, admin, uid := goit.AuthCookieAdmin(w, r, true)
 
@@ -37,3 +45,55 @@ func HandleDelete(w http.ResponseWriter, r *http.Request) {
 
 	http.Redirect(w, r, "/", http.StatusFound)
 }
+
+func findReadme(gr *git.Repository, ref *plumbing.Reference) (string, error) {
+	commit, err := gr.CommitObject(ref.Hash())
+	if err != nil {
+		return "", err
+	}
+
+	iter, err := commit.Files()
+	if err != nil {
+		return "", err
+	}
+
+	var filename string
+	if err := iter.ForEach(func(f *object.File) error {
+		if readmePattern.MatchString(f.Name) {
+			filename = f.Name
+			return storer.ErrStop
+		}
+
+		return nil
+	}); err != nil {
+		return "", err
+	}
+
+	return filename, nil
+}
+
+func findLicence(gr *git.Repository, ref *plumbing.Reference) (string, error) {
+	commit, err := gr.CommitObject(ref.Hash())
+	if err != nil {
+		return "", err
+	}
+
+	iter, err := commit.Files()
+	if err != nil {
+		return "", err
+	}
+
+	var filename string
+	if err := iter.ForEach(func(f *object.File) error {
+		if licencePattern.MatchString(f.Name) {
+			filename = f.Name
+			return storer.ErrStop
+		}
+
+		return nil
+	}); err != nil {
+		return "", err
+	}
+
+	return filename, nil
+}
diff --git a/src/repo/tree.go b/src/repo/tree.go
index 36dba07..8709225 100644
--- a/src/repo/tree.go
+++ b/src/repo/tree.go
@@ -57,6 +57,13 @@ func HandleTree(w http.ResponseWriter, r *http.Request) {
 			return
 		}
 	} else {
+		if readme, _ := findReadme(gr, ref); readme != "" {
+			data.Readme = path.Join("/", repo.Name, "file", readme)
+		}
+		if licence, _ := findLicence(gr, ref); licence != "" {
+			data.Licence = path.Join("/", repo.Name, "file", licence)
+		}
+
 		commit, err := gr.CommitObject(ref.Hash())
 		if err != nil {
 			log.Println("[/repo/tree]", err.Error())