aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRunxi Yu <me@runxiyu.org>2025-02-11 23:13:04 +0800
committerRunxi Yu <me@runxiyu.org>2025-02-11 23:15:51 +0800
commitb288beea9ddc5709769997a9101f25a78e286b89 (patch)
treedb548c0ca63f180b25acb6f9822ab38bc41c15d0
parentstyle.css: Fix file content background (diff)
downloadforge-b288beea9ddc5709769997a9101f25a78e286b89.tar.gz
forge-b288beea9ddc5709769997a9101f25a78e286b89.tar.zst
forge-b288beea9ddc5709769997a9101f25a78e286b89.zip
*: Use URL params to specify commits/branches/tags
-rw-r--r--handle_repo_raw.go25
-rw-r--r--handle_repo_tree.go20
-rw-r--r--main.go4
-rw-r--r--ref.go46
-rw-r--r--templates/repo_commit.html.tmpl4
-rw-r--r--templates/repo_index.html.tmpl2
-rw-r--r--templates/repo_tree_file.html.tmpl2
-rw-r--r--url_misc.go42
8 files changed, 127 insertions, 18 deletions
diff --git a/handle_repo_raw.go b/handle_repo_raw.go
index 5693660..d3ffe3e 100644
--- a/handle_repo_raw.go
+++ b/handle_repo_raw.go
@@ -1,11 +1,11 @@
package main
import (
+ "errors"
"net/http"
"path"
"strings"
- "github.com/go-git/go-git/v5/plumbing"
"github.com/go-git/go-git/v5/plumbing/object"
)
@@ -13,19 +13,32 @@ func handle_repo_raw(w http.ResponseWriter, r *http.Request) {
data := make(map[string]any)
// TODO: Sanitize path values
raw_path_spec := r.PathValue("rest")
- ref_name, group_name, repo_name, path_spec := r.PathValue("ref"), r.PathValue("group_name"), r.PathValue("repo_name"), strings.TrimSuffix(raw_path_spec, "/")
- data["ref"], data["group_name"], data["repo_name"], data["path_spec"] = ref_name, group_name, repo_name, path_spec
+ group_name, repo_name, path_spec := r.PathValue("group_name"), r.PathValue("repo_name"), strings.TrimSuffix(raw_path_spec, "/")
+
+ ref_type, ref_name, err := get_param_ref_and_type(r)
+ if err != nil {
+ if errors.Is(err, err_no_ref_spec) {
+ ref_type = "head"
+ } else {
+ _, _ = w.Write([]byte("Error querying ref type: " + err.Error()))
+ return
+ }
+ }
+
+ data["ref_type"], data["ref"], data["group_name"], data["repo_name"], data["path_spec"] = ref_type, ref_name, group_name, repo_name, path_spec
+
repo, err := open_git_repo(group_name, repo_name)
if err != nil {
_, _ = w.Write([]byte("Error opening repo: " + err.Error()))
return
}
- ref, err := repo.Reference(plumbing.NewBranchReferenceName(ref_name), true)
+
+ ref_hash, err := get_ref_hash_from_type_and_name(repo, ref_type, ref_name)
if err != nil {
- _, _ = w.Write([]byte("Error getting repo reference: " + err.Error()))
+ _, _ = w.Write([]byte("Error getting ref hash: " + err.Error()))
return
}
- ref_hash := ref.Hash()
+
commit_object, err := repo.CommitObject(ref_hash)
if err != nil {
_, _ = w.Write([]byte("Error getting commit object: " + err.Error()))
diff --git a/handle_repo_tree.go b/handle_repo_tree.go
index 2c1c31e..824f5df 100644
--- a/handle_repo_tree.go
+++ b/handle_repo_tree.go
@@ -2,6 +2,7 @@ package main
import (
"bytes"
+ "errors"
"html/template"
"net/http"
"path"
@@ -10,7 +11,6 @@ import (
chroma_formatters_html "github.com/alecthomas/chroma/v2/formatters/html"
chroma_lexers "github.com/alecthomas/chroma/v2/lexers"
chroma_styles "github.com/alecthomas/chroma/v2/styles"
- "github.com/go-git/go-git/v5/plumbing"
"github.com/go-git/go-git/v5/plumbing/object"
)
@@ -18,19 +18,27 @@ func handle_repo_tree(w http.ResponseWriter, r *http.Request) {
data := make(map[string]any)
// TODO: Sanitize path values
raw_path_spec := r.PathValue("rest")
- ref_name, group_name, repo_name, path_spec := r.PathValue("ref"), r.PathValue("group_name"), r.PathValue("repo_name"), strings.TrimSuffix(raw_path_spec, "/")
- data["ref"], data["group_name"], data["repo_name"], data["path_spec"] = ref_name, group_name, repo_name, path_spec
+ group_name, repo_name, path_spec := r.PathValue("group_name"), r.PathValue("repo_name"), strings.TrimSuffix(raw_path_spec, "/")
+ ref_type, ref_name, err := get_param_ref_and_type(r)
+ if err != nil {
+ if errors.Is(err, err_no_ref_spec) {
+ ref_type = "head"
+ } else {
+ _, _ = w.Write([]byte("Error querying ref type: " + err.Error()))
+ return
+ }
+ }
+ data["ref_type"], data["ref"], data["group_name"], data["repo_name"], data["path_spec"] = ref_type, ref_name, group_name, repo_name, path_spec
repo, err := open_git_repo(group_name, repo_name)
if err != nil {
_, _ = w.Write([]byte("Error opening repo: " + err.Error()))
return
}
- ref, err := repo.Reference(plumbing.NewBranchReferenceName(ref_name), true)
+ ref_hash, err := get_ref_hash_from_type_and_name(repo, ref_type, ref_name)
if err != nil {
- _, _ = w.Write([]byte("Error getting repo reference: " + err.Error()))
+ _, _ = w.Write([]byte("Error getting ref hash: " + err.Error()))
return
}
- ref_hash := ref.Hash()
commit_object, err := repo.CommitObject(ref_hash)
if err != nil {
_, _ = w.Write([]byte("Error getting commit object: " + err.Error()))
diff --git a/main.go b/main.go
index b7a9b76..8c06a77 100644
--- a/main.go
+++ b/main.go
@@ -36,8 +36,8 @@ func main() {
http.HandleFunc("/{$}", handle_index)
http.HandleFunc("/g/{group_name}/repos/{$}", handle_group_repos)
http.HandleFunc("/g/{group_name}/repos/{repo_name}/{$}", handle_repo_index)
- http.HandleFunc("/g/{group_name}/repos/{repo_name}/tree/{ref}/{rest...}", handle_repo_tree)
- http.HandleFunc("/g/{group_name}/repos/{repo_name}/raw/{ref}/{rest...}", handle_repo_raw)
+ http.HandleFunc("/g/{group_name}/repos/{repo_name}/tree/{rest...}", handle_repo_tree)
+ http.HandleFunc("/g/{group_name}/repos/{repo_name}/raw/{rest...}", handle_repo_raw)
http.HandleFunc("/g/{group_name}/repos/{repo_name}/log/{ref}/", handle_repo_log)
http.HandleFunc("/g/{group_name}/repos/{repo_name}/commit/{commit_id}", handle_repo_commit)
diff --git a/ref.go b/ref.go
new file mode 100644
index 0000000..19856e7
--- /dev/null
+++ b/ref.go
@@ -0,0 +1,46 @@
+package main
+
+import (
+ "errors"
+
+ "github.com/go-git/go-git/v5"
+ "github.com/go-git/go-git/v5/plumbing"
+ "go.lindenii.runxiyu.org/lindenii-common/misc"
+)
+
+var (
+ err_getting_tag_reference = errors.New("Error getting tag reference")
+ err_getting_branch_reference = errors.New("Error getting branch reference")
+ err_getting_head = errors.New("Error getting HEAD")
+)
+
+func get_ref_hash_from_type_and_name(repo *git.Repository, ref_type, ref_name string) (ref_hash plumbing.Hash, ret_err error) {
+ switch ref_type {
+ case "head":
+ head, err := repo.Head()
+ if err != nil {
+ ret_err = misc.Wrap_one_error(err_getting_head, err)
+ return
+ }
+ ref_hash = head.Hash()
+ case "commit":
+ ref_hash = plumbing.NewHash(ref_name)
+ case "branch":
+ ref, err := repo.Reference(plumbing.NewBranchReferenceName(ref_name), true)
+ if err != nil {
+ ret_err = misc.Wrap_one_error(err_getting_branch_reference, err)
+ return
+ }
+ ref_hash = ref.Hash()
+ case "tag":
+ ref, err := repo.Reference(plumbing.NewTagReferenceName(ref_name), true)
+ if err != nil {
+ ret_err = misc.Wrap_one_error(err_getting_tag_reference, err)
+ return
+ }
+ ref_hash = ref.Hash()
+ default:
+ panic("Invalid ref type " + ref_type)
+ }
+ return
+}
diff --git a/templates/repo_commit.html.tmpl b/templates/repo_commit.html.tmpl
index a288949..d568887 100644
--- a/templates/repo_commit.html.tmpl
+++ b/templates/repo_commit.html.tmpl
@@ -53,9 +53,9 @@
<input type="checkbox" id="toggle-{{ .From.Hash }}{{ .To.Hash }}" class="file-toggle toggle-on-toggle">
<label for="toggle-{{ .From.Hash }}{{ .To.Hash }}" class="file-header toggle-on-header">
<span>
- --- a/<a href="../../tree/{{ .From.Path }}?commit={{ $parent_commit_object.Hash }}">{{ .From.Path }}</a> {{ .From.Mode }}
+ --- a/<a href="../tree/{{ .From.Path }}?commit={{ $parent_commit_object.Hash }}">{{ .From.Path }}</a> {{ .From.Mode }}
<br />
- +++ b/<a href="../../tree/{{ .To.Path }}?commit={{ $commit_object.Hash }}">{{ .To.Path }}</a> {{ .To.Mode }}
+ +++ b/<a href="../tree/{{ .To.Path }}?commit={{ $commit_object.Hash }}">{{ .To.Path }}</a> {{ .To.Mode }}
</span>
</label>
<div class="file-content toggle-on-content scroll">
diff --git a/templates/repo_index.html.tmpl b/templates/repo_index.html.tmpl
index c3b4759..2f41aac 100644
--- a/templates/repo_index.html.tmpl
+++ b/templates/repo_index.html.tmpl
@@ -42,7 +42,7 @@
{{- range .files }}
<tr>
<td class="file-mode">{{ .Mode }}</td>
- <td class="file-name"><a href="tree/{{ $ref }}/{{ .Name }}">{{ .Name }}</a>{{ if not .Is_file }}/{{ end }}</td>
+ <td class="file-name"><a href="tree/{{ .Name }}">{{ .Name }}</a>{{ if not .Is_file }}/{{ end }}</td>
<td class="file-size">{{ .Size }}</td>
</tr>
{{- end }}
diff --git a/templates/repo_tree_file.html.tmpl b/templates/repo_tree_file.html.tmpl
index 7ddfce1..0401bb0 100644
--- a/templates/repo_tree_file.html.tmpl
+++ b/templates/repo_tree_file.html.tmpl
@@ -8,7 +8,7 @@
</head>
<body class="repo-tree-file">
<p>
- /{{ .path_spec }} (<a href="/g/{{ .group_name }}/repos/{{ .repo_name }}/raw/{{ .ref }}/{{ .path_spec }}">raw</a>)
+ /{{ .path_spec }} (<a href="/g/{{ .group_name }}/repos/{{ .repo_name }}/raw/{{ .path_spec }}?{{ .ref_type }}={{ .ref }}">raw</a>)
</p>
{{ .file_contents }}
<footer>
diff --git a/url_misc.go b/url_misc.go
new file mode 100644
index 0000000..906e06e
--- /dev/null
+++ b/url_misc.go
@@ -0,0 +1,42 @@
+package main
+
+import (
+ "errors"
+ "net/http"
+ "net/url"
+)
+
+var (
+ err_duplicate_ref_spec = errors.New("Duplicate ref spec")
+ err_no_ref_spec = errors.New("No ref spec")
+)
+
+func get_param_ref_and_type(r *http.Request) (ref_type, ref string, err error) {
+ qr := r.URL.RawQuery
+ q, err := url.ParseQuery(qr)
+ if err != nil {
+ return
+ }
+ done := false
+ for _, _ref_type := range []string{"commit", "branch", "tag"} {
+ _ref, ok := q[_ref_type]
+ if ok {
+ if done {
+ err = err_duplicate_ref_spec
+ return
+ } else {
+ done = true
+ if len(_ref) != 1 {
+ err = err_duplicate_ref_spec
+ return
+ }
+ ref = _ref[0]
+ ref_type = _ref_type
+ }
+ }
+ }
+ if !done {
+ err = err_no_ref_spec
+ }
+ return
+}