aboutsummaryrefslogtreecommitdiff
path: root/forged/internal/incoming/web/handlers/repo/raw.go
diff options
context:
space:
mode:
authorRunxi Yu <me@runxiyu.org>2025-08-12 11:01:07 +0800
committerRunxi Yu <me@runxiyu.org>2025-09-16 08:58:16 +0800
commitc12fe030fe5935882047e75ac8a3792faea27574 (patch)
treee2b6f795410348596a7965694bed7e85511d0874 /forged/internal/incoming/web/handlers/repo/raw.go
parentRemove forge-specific functions from misc (diff)
downloadforge-c12fe030fe5935882047e75ac8a3792faea27574.tar.gz
forge-c12fe030fe5935882047e75ac8a3792faea27574.tar.zst
forge-c12fe030fe5935882047e75ac8a3792faea27574.zip
RefactorHEADmaster
Diffstat (limited to 'forged/internal/incoming/web/handlers/repo/raw.go')
-rw-r--r--forged/internal/incoming/web/handlers/repo/raw.go90
1 files changed, 90 insertions, 0 deletions
diff --git a/forged/internal/incoming/web/handlers/repo/raw.go b/forged/internal/incoming/web/handlers/repo/raw.go
new file mode 100644
index 0000000..6d5db1e
--- /dev/null
+++ b/forged/internal/incoming/web/handlers/repo/raw.go
@@ -0,0 +1,90 @@
+package repo
+
+import (
+ "fmt"
+ "log/slog"
+ "net/http"
+ "net/url"
+ "path/filepath"
+ "strings"
+
+ "go.lindenii.runxiyu.org/forge/forged/internal/common/misc"
+ "go.lindenii.runxiyu.org/forge/forged/internal/database/queries"
+ wtypes "go.lindenii.runxiyu.org/forge/forged/internal/incoming/web/types"
+ "go.lindenii.runxiyu.org/forge/forged/internal/ipc/git2c"
+)
+
+func (h *HTTP) Raw(w http.ResponseWriter, r *http.Request, v wtypes.Vars) {
+ base := wtypes.Base(r)
+ repoName := v["repo"]
+ rawPathSpec := v["rest"]
+ pathSpec := strings.TrimSuffix(rawPathSpec, "/")
+
+ var userID int64
+ if base.UserID != "" {
+ _, _ = fmt.Sscan(base.UserID, &userID)
+ }
+ grp, err := base.Global.Queries.GetGroupByPath(r.Context(), queries.GetGroupByPathParams{Column1: base.GroupPath, UserID: userID})
+ if err != nil {
+ slog.Error("get group by path", "error", err)
+ http.Error(w, "Group not found", http.StatusNotFound)
+ return
+ }
+ repoRow, err := base.Global.Queries.GetRepoByGroupAndName(r.Context(), queries.GetRepoByGroupAndNameParams{GroupID: grp.ID, Name: repoName})
+ if err != nil {
+ slog.Error("get repo by name", "error", err)
+ http.Error(w, "Repository not found", http.StatusNotFound)
+ return
+ }
+
+ repoPath := filepath.Join(base.Global.Config.Git.RepoDir, fmt.Sprintf("%d.git", repoRow.ID))
+
+ client, err := git2c.NewClient(r.Context(), base.Global.Config.Git.Socket)
+ if err != nil {
+ slog.Error("git2d connect failed", "error", err)
+ http.Error(w, "Internal Server Error", http.StatusInternalServerError)
+ return
+ }
+ defer func() { _ = client.Close() }()
+
+ files, content, err := client.CmdTreeRaw(repoPath, pathSpec)
+ if err != nil {
+ slog.Error("git2d CmdTreeRaw failed", "error", err, "path", repoPath, "spec", pathSpec)
+ http.Error(w, "Internal Server Error", http.StatusInternalServerError)
+ return
+ }
+
+ repoURLRoot := "/" + misc.SegmentsToURL(base.GroupPath) + "/-/repos/" + url.PathEscape(repoRow.Name) + "/"
+
+ switch {
+ case files != nil:
+ if !base.DirMode && misc.RedirectDir(w, r) {
+ return
+ }
+ data := map[string]any{
+ "BaseData": base,
+ "group_path": base.GroupPath,
+ "repo_name": repoRow.Name,
+ "repo_description": repoRow.Description,
+ "repo_url_root": repoURLRoot,
+ "ref_name": base.RefName,
+ "path_spec": pathSpec,
+ "files": files,
+ "global": map[string]any{
+ "forge_title": base.Global.ForgeTitle,
+ },
+ }
+ if err := h.r.Render(w, "repo_raw_dir", data); err != nil {
+ slog.Error("render repo raw dir", "error", err)
+ http.Error(w, "Internal Server Error", http.StatusInternalServerError)
+ }
+ case content != "":
+ if base.DirMode && misc.RedirectNoDir(w, r) {
+ return
+ }
+ w.Header().Set("Content-Type", "application/octet-stream")
+ _, _ = w.Write([]byte(content))
+ default:
+ http.Error(w, "Unknown object type", http.StatusInternalServerError)
+ }
+}