fierj
PublicTiny personal git forge
e1e14992b26f527cd37610ae2c60285bd60ad466
diff --git a/main.go b/main.go
index 87deb84..db05552 100644
--- a/main.go
+++ b/main.go
@@ -63,10 +63,10 @@ func main() {
mux.HandleFunc("GET /users", UsersGet(users, cfg.UsersPath, tmpl))
mux.HandleFunc("POST /users", UsersPost(users, cfg.UsersPath, tmpl))
mux.HandleFunc("GET /{repo}", Tree(cfg, tmpl))
- mux.HandleFunc("GET /{repo}/tree/{ref}/{path...}", Tree(cfg, tmpl))
- mux.HandleFunc("GET /{repo}/blob/{ref}/{path...}", Blob(cfg, tmpl))
- mux.HandleFunc("GET /{repo}/log/{ref}", Log(cfg, tmpl))
- mux.HandleFunc("GET /{repo}/commit/{ref}", Diff(cfg, tmpl))
+ mux.HandleFunc("GET /{repo}/tree/{refpath...}", Tree(cfg, tmpl))
+ mux.HandleFunc("GET /{repo}/blob/{refpath...}", Blob(cfg, tmpl))
+ mux.HandleFunc("GET /{repo}/log/{refpath...}", Log(cfg, tmpl))
+ mux.HandleFunc("GET /{repo}/commit/{hash}", Diff(cfg, tmpl))
mux.HandleFunc("GET /{repo}/refs/", Refs(cfg, tmpl))
mux.HandleFunc("GET /{repo}/settings", SettingsGet(cfg, tmpl))
mux.HandleFunc("POST /{repo}/settings", SettingsPost(cfg, tmpl))
diff --git a/repo_handlers.go b/repo_handlers.go
index bcd16e6..10b569f 100644
--- a/repo_handlers.go
+++ b/repo_handlers.go
@@ -138,6 +138,30 @@ func Repos(cfg Config, tmpl *template.Template) http.HandlerFunc {
}
}
+// splitRefPath splits a combined "ref/path" URL segment into a git ref and
+// a filesystem path by matching increasingly long prefixes against known
+// branches and tags. Falls back to treating the first segment as the ref.
+func splitRefPath(git *Git, refpath string) (ref, path string) {
+ if refpath == "" {
+ return git.DefaultBranch(), ""
+ }
+ refs := make(map[string]bool)
+ for _, b := range git.Branches() {
+ refs[b] = true
+ }
+ for _, t := range git.Tags() {
+ refs[t] = true
+ }
+ parts := strings.Split(refpath, "/")
+ for i := len(parts); i > 0; i-- {
+ candidate := strings.Join(parts[:i], "/")
+ if refs[candidate] {
+ return candidate, strings.Join(parts[i:], "/")
+ }
+ }
+ return parts[0], strings.Join(parts[1:], "/")
+}
+
func Tree(cfg Config, tmpl *template.Template) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
type FileEntry struct {
@@ -148,10 +172,10 @@ func Tree(cfg Config, tmpl *template.Template) http.HandlerFunc {
if !checkRepoAccess(w, r, git) {
return
}
- treePath := r.PathValue("path")
- ref := r.PathValue("ref")
- if ref == "" {
- ref = git.DefaultBranch()
+ treePath := ""
+ ref := git.DefaultBranch()
+ if rp := r.PathValue("refpath"); rp != "" {
+ ref, treePath = splitRefPath(git, rp)
}
cloneSSH := ""
cloneHTTPS := ""
@@ -229,11 +253,7 @@ func Blob(cfg Config, tmpl *template.Template) http.HandlerFunc {
if !checkRepoAccess(w, r, git) {
return
}
- filePath := r.PathValue("path")
- ref := r.PathValue("ref")
- if ref == "" {
- ref = git.DefaultBranch()
- }
+ ref, filePath := splitRefPath(git, r.PathValue("refpath"))
content, err := git.Blob(ref, filePath)
if err != nil {
@@ -262,7 +282,7 @@ func Log(cfg Config, tmpl *template.Template) http.HandlerFunc {
if !checkRepoAccess(w, r, git) {
return
}
- ref := r.PathValue("ref")
+ ref, _ := splitRefPath(git, r.PathValue("refpath"))
commits, err := git.Log(ref, 50)
if err != nil {
renderError(w, tmpl, http.StatusInternalServerError, err.Error())
@@ -290,7 +310,7 @@ func Diff(cfg Config, tmpl *template.Template) http.HandlerFunc {
if !checkRepoAccess(w, r, git) {
return
}
- ref := r.PathValue("ref")
+ ref := r.PathValue("hash")
commit, err := git.Diff(ref)
if err != nil || len(commit) == 0 {
renderError(w, tmpl, http.StatusNotFound, "commit not found")