aboutsummaryrefslogtreecommitdiff
path: root/http_handle_repo_raw.go
diff options
context:
space:
mode:
authorRunxi Yu <me@runxiyu.org>2025-04-05 12:34:14 +0800
committerRunxi Yu <me@runxiyu.org>2025-04-05 12:36:54 +0800
commitd15089b985122d0841afdd1379791fa9deefa374 (patch)
tree633d3c95347dfdab65daefc4d4557a0e7fe08bbb /http_handle_repo_raw.go
parentgit2d: Add a basic command for tree (diff)
downloadforge-d15089b985122d0841afdd1379791fa9deefa374.tar.gz
forge-d15089b985122d0841afdd1379791fa9deefa374.tar.zst
forge-d15089b985122d0841afdd1379791fa9deefa374.zip
HTTP: Make the tree and raw endpoints use git2d
Diffstat (limited to 'http_handle_repo_raw.go')
-rw-r--r--http_handle_repo_raw.go159
1 files changed, 96 insertions, 63 deletions
diff --git a/http_handle_repo_raw.go b/http_handle_repo_raw.go
index 75296d6..5928f8c 100644
--- a/http_handle_repo_raw.go
+++ b/http_handle_repo_raw.go
@@ -4,102 +4,135 @@
package main
import (
+ "errors"
"fmt"
+ "html/template"
+ "io"
+ "net"
"net/http"
"strings"
- "time"
- "github.com/go-git/go-git/v5"
- "github.com/go-git/go-git/v5/plumbing"
- "github.com/go-git/go-git/v5/plumbing/object"
+ "git.sr.ht/~sircmpwn/go-bare"
)
// httpHandleRepoRaw serves raw files, or directory listings that point to raw
// files.
func httpHandleRepoRaw(writer http.ResponseWriter, request *http.Request, params map[string]any) {
- var rawPathSpec, pathSpec string
- var repo *git.Repository
- var refHash plumbing.Hash
- var refHashSlice []byte
- var commitObj *object.Commit
- var tree *object.Tree
- var err error
-
- rawPathSpec = params["rest"].(string)
- repo, pathSpec = params["repo"].(*git.Repository), strings.TrimSuffix(rawPathSpec, "/")
+ repoName := params["repo_name"].(string)
+ groupPath := params["group_path"].([]string)
+ rawPathSpec := params["rest"].(string)
+ pathSpec := strings.TrimSuffix(rawPathSpec, "/")
params["path_spec"] = pathSpec
- if refHash, err = getRefHash(repo, params["ref_type"].(string), params["ref_name"].(string)); err != nil {
- errorPage500(writer, params, "Error getting ref hash: "+err.Error())
+ _, repoPath, _, _, _, _, _ := getRepoInfo(request.Context(), groupPath, repoName, "")
+
+ conn, err := net.Dial("unix", config.Git.Socket)
+ if err != nil {
+ errorPage500(writer, params, "git2d connection failed: "+err.Error())
return
}
- refHashSlice = refHash[:]
+ defer conn.Close()
- cacheHandle := append(refHashSlice, stringToBytes(pathSpec)...) //nolint:gocritic
+ brWriter := bare.NewWriter(conn)
+ brReader := bare.NewReader(conn)
- if value, found := treeReadmeCache.Get(cacheHandle); found {
- params["files"] = value.DisplayTree
- renderTemplate(writer, "repo_raw_dir", params)
+ if err := brWriter.WriteData([]byte(repoPath)); err != nil {
+ errorPage500(writer, params, "sending repo path failed: "+err.Error())
return
}
- if value, found := commitPathFileRawCache.Get(cacheHandle); found {
- fmt.Fprint(writer, value)
+ if err := brWriter.WriteUint(2); err != nil {
+ errorPage500(writer, params, "sending command failed: "+err.Error())
return
}
-
- if commitObj, err = repo.CommitObject(refHash); err != nil {
- errorPage500(writer, params, "Error getting commit object: "+err.Error())
+ if err := brWriter.WriteData([]byte(pathSpec)); err != nil {
+ errorPage500(writer, params, "sending path failed: "+err.Error())
return
}
- if tree, err = commitObj.Tree(); err != nil {
- errorPage500(writer, params, "Error getting file tree: "+err.Error())
+
+ status, err := brReader.ReadUint()
+ if err != nil {
+ errorPage500(writer, params, "reading status failed: "+err.Error())
return
}
- start := time.Now()
- var target *object.Tree
- if pathSpec == "" {
- target = tree
- } else {
- if target, err = tree.Tree(pathSpec); err != nil {
- var file *object.File
- var fileContent string
- if file, err = tree.File(pathSpec); err != nil {
- errorPage500(writer, params, "Error retrieving path: "+err.Error())
+ switch status {
+ case 0:
+ kind, err := brReader.ReadUint()
+ if err != nil {
+ errorPage500(writer, params, "reading object kind failed: "+err.Error())
+ return
+ }
+
+ switch kind {
+ case 1:
+ // Tree
+ if redirectDir(writer, request) {
return
}
+ count, err := brReader.ReadUint()
+ if err != nil {
+ errorPage500(writer, params, "reading entry count failed: "+err.Error())
+ return
+ }
+
+ files := make([]displayTreeEntry, 0, count)
+ for i := uint64(0); i < count; i++ {
+ typeCode, err := brReader.ReadUint()
+ if err != nil {
+ errorPage500(writer, params, "error reading entry type: "+err.Error())
+ return
+ }
+ mode, err := brReader.ReadUint()
+ if err != nil {
+ errorPage500(writer, params, "error reading entry mode: "+err.Error())
+ return
+ }
+ size, err := brReader.ReadUint()
+ if err != nil {
+ errorPage500(writer, params, "error reading entry size: "+err.Error())
+ return
+ }
+ name, err := brReader.ReadData()
+ if err != nil {
+ errorPage500(writer, params, "error reading entry name: "+err.Error())
+ return
+ }
+ files = append(files, displayTreeEntry{
+ Name: string(name),
+ Mode: fmt.Sprintf("%06o", mode),
+ Size: int64(size),
+ IsFile: typeCode == 2,
+ IsSubtree: typeCode == 1,
+ })
+ }
+
+ params["files"] = files
+ params["readme_filename"] = "README.md"
+ params["readme"] = template.HTML("<p>README rendering here is WIP again</p>") // TODO
+
+ renderTemplate(writer, "repo_raw_dir", params)
+
+ case 2:
+ // Blob
if redirectNoDir(writer, request) {
return
}
- if fileContent, err = file.Contents(); err != nil {
- errorPage500(writer, params, "Error reading file: "+err.Error())
+ content, err := brReader.ReadData()
+ if err != nil && !errors.Is(err, io.EOF) {
+ errorPage500(writer, params, "error reading blob content: "+err.Error())
return
}
- cost := time.Since(start).Nanoseconds()
- commitPathFileRawCache.Set(cacheHandle, fileContent, cost)
writer.Header().Set("Content-Type", "application/octet-stream")
- fmt.Fprint(writer, fileContent)
- return
- }
- }
+ fmt.Fprint(writer, string(content))
- if redirectDir(writer, request) {
- return
- }
-
- displayTree := makeDisplayTree(target)
- readmeFilename, readmeRendered := renderReadmeAtTree(target)
- cost := time.Since(start).Nanoseconds()
-
- params["files"] = displayTree
- params["readme_filename"] = readmeFilename
- params["readme"] = readmeRendered
+ default:
+ errorPage500(writer, params, fmt.Sprintf("unknown object kind: %d", kind))
+ }
- treeReadmeCache.Set(cacheHandle, treeReadmeCacheEntry{
- DisplayTree: displayTree,
- ReadmeFilename: readmeFilename,
- ReadmeRendered: readmeRendered,
- }, cost)
+ case 3:
+ errorPage500(writer, params, fmt.Sprintf("path not found: %s", pathSpec))
- renderTemplate(writer, "repo_raw_dir", params)
+ default:
+ errorPage500(writer, params, fmt.Sprintf("unknown status code: %d", status))
+ }
}