From 96908354a00108e16112fa2a27d446b4d4a153bd Mon Sep 17 00:00:00 2001 From: Anirudh Oppiliappan Date: Tue, 11 Feb 2025 21:03:31 +0200 Subject: [PATCH] appview: repo file content --- appview/pages/pages.go | 25 ++++++++++++++- appview/pages/templates/repo/blob.html | 12 +++++++ appview/pages/templates/repo/file.html | 34 -------------------- appview/state/repo.go | 43 ++++++++++++++++++++++++-- appview/state/state.go | 1 + knotserver/file.go | 24 +++----------- knotserver/handler.go | 2 +- knotserver/routes.go | 34 ++++++++------------ types/repo.go | 8 +++++ types/tree.go | 10 +++--- 10 files changed, 108 insertions(+), 85 deletions(-) create mode 100644 appview/pages/templates/repo/blob.html delete mode 100644 appview/pages/templates/repo/file.html diff --git a/appview/pages/pages.go b/appview/pages/pages.go index eab31eeb..e2f0c58c 100644 --- a/appview/pages/pages.go +++ b/appview/pages/pages.go @@ -22,6 +22,17 @@ type Pages struct { t map[string]*template.Template } +func funcMap() template.FuncMap { + return template.FuncMap{ + "split": func(s string) []string { + return strings.Split(s, "\n") + }, + "add": func(a, b int) int { + return a + b + }, + } +} + func NewPages() *Pages { templates := make(map[string]*template.Template) @@ -37,7 +48,9 @@ func NewPages() *Pages { if !strings.HasPrefix(path, "templates/layouts/") { // Add the page template on top of the base - tmpl, err := template.New(name).ParseFS(files, "templates/layouts/*.html", path) + tmpl, err := template.New(name). + Funcs(funcMap()). + ParseFS(files, "templates/layouts/*.html", path) if err != nil { return fmt.Errorf("setting up template: %w", err) } @@ -215,3 +228,13 @@ type RepoTagsParams struct { func (p *Pages) RepoTags(w io.Writer, params RepoTagsParams) error { return p.executeRepo("repo/tags", w, params) } + +type RepoBlobParams struct { + LoggedInUser *auth.User + RepoInfo RepoInfo + types.RepoBlobResponse +} + +func (p *Pages) RepoBlob(w io.Writer, params RepoBlobParams) error { + return p.executeRepo("repo/blob", w, params) +} diff --git a/appview/pages/templates/repo/blob.html b/appview/pages/templates/repo/blob.html new file mode 100644 index 00000000..345b944b --- /dev/null +++ b/appview/pages/templates/repo/blob.html @@ -0,0 +1,12 @@ +{{ define "repoContent" }} + + + + + +
+ {{ range $i, $x := split .Contents }} + {{ add $i 1 }} {{ $x }}
+ {{ end }} +
+{{end}} diff --git a/appview/pages/templates/repo/file.html b/appview/pages/templates/repo/file.html deleted file mode 100644 index 5dea3f60..00000000 --- a/appview/pages/templates/repo/file.html +++ /dev/null @@ -1,34 +0,0 @@ - - {{ template "layouts/head" . }} - {{ template "layouts/repo-header" . }} - - {{ template "layouts/nav" . }} -
-

{{ .path }} (view raw)

- {{if .chroma }} -
- {{ .content }} -
- {{else}} -
- - - - - -
-
-            {{- range .linecount }}
- {{ . }}
-            {{- end -}}
-              
-
-
-             {{- .content -}}
-              
-
-
- {{end}} -
- - diff --git a/appview/state/repo.go b/appview/state/repo.go index bfecd23f..5ed49306 100644 --- a/appview/state/repo.go +++ b/appview/state/repo.go @@ -48,7 +48,6 @@ func (s *State) RepoIndex(w http.ResponseWriter, r *http.Request) { OwnerDid: id.DID.String(), OwnerHandle: id.Handle.String(), Name: repoName, - Description: result.Description, }, RepoIndexResponse: result, }) @@ -89,7 +88,6 @@ func (s *State) RepoLog(w http.ResponseWriter, r *http.Request) { OwnerDid: id.DID.String(), OwnerHandle: id.Handle.String(), Name: repoName, - Description: result.Description, }, RepoLogResponse: result, }) @@ -171,7 +169,6 @@ func (s *State) RepoTree(w http.ResponseWriter, r *http.Request) { OwnerDid: id.DID.String(), OwnerHandle: id.Handle.String(), Name: repoName, - Description: result.Description, }, RepoTreeResponse: result, }) @@ -254,6 +251,46 @@ func (s *State) RepoBranches(w http.ResponseWriter, r *http.Request) { return } +func (s *State) RepoBlob(w http.ResponseWriter, r *http.Request) { + repoName, knot, id, err := repoKnotAndId(r) + if err != nil { + log.Println("failed to get repo and knot", err) + return + } + + ref := chi.URLParam(r, "ref") + filePath := chi.URLParam(r, "*") + resp, err := http.Get(fmt.Sprintf("http://%s/%s/%s/blob/%s/%s", knot, id.DID.String(), repoName, ref, filePath)) + if err != nil { + log.Println("failed to reach knotserver", err) + return + } + + body, err := io.ReadAll(resp.Body) + if err != nil { + log.Fatalf("Error reading response body: %v", err) + return + } + + var result types.RepoBlobResponse + err = json.Unmarshal(body, &result) + if err != nil { + log.Println("failed to parse response:", err) + return + } + + s.pages.RepoBlob(w, pages.RepoBlobParams{ + LoggedInUser: s.auth.GetUser(r), + RepoInfo: pages.RepoInfo{ + OwnerDid: id.DID.String(), + OwnerHandle: id.Handle.String(), + Name: repoName, + }, + RepoBlobResponse: result, + }) + return +} + func repoKnotAndId(r *http.Request) (string, string, identity.Identity, error) { repoName := chi.URLParam(r, "repo") knot, ok := r.Context().Value("knot").(string) diff --git a/appview/state/state.go b/appview/state/state.go index 6acf47ef..c901b71c 100644 --- a/appview/state/state.go +++ b/appview/state/state.go @@ -617,6 +617,7 @@ func (s *State) UserRouter() http.Handler { r.Get("/commit/{ref}", s.RepoCommit) r.Get("/branches", s.RepoBranches) r.Get("/tags", s.RepoTags) + r.Get("/blob/{ref}/*", s.RepoBlob) // These routes get proxied to the knot r.Get("/info/refs", s.InfoRefs) diff --git a/knotserver/file.go b/knotserver/file.go index d10334a9..7c3a43bf 100644 --- a/knotserver/file.go +++ b/knotserver/file.go @@ -43,30 +43,14 @@ func countLines(r io.Reader) (int, error) { } } -func (h *Handle) showFile(content string, data map[string]any, w http.ResponseWriter, l *slog.Logger) { - lc, err := countLines(strings.NewReader(content)) +func (h *Handle) showFile(resp types.RepoBlobResponse, w http.ResponseWriter, l *slog.Logger) { + lc, err := countLines(strings.NewReader(resp.Contents)) if err != nil { // Non-fatal, we'll just skip showing line numbers in the template. l.Warn("counting lines", "error", err) } - lines := make([]int, lc) - if lc > 0 { - for i := range lines { - lines[i] = i + 1 - } - } - - data["linecount"] = lines - data["content"] = content - - writeJSON(w, data) - return -} - -func (h *Handle) showRaw(content string, w http.ResponseWriter) { - w.WriteHeader(http.StatusOK) - w.Header().Set("Content-Type", "text/plain") - w.Write([]byte(content)) + resp.Lines = lc + writeJSON(w, resp) return } diff --git a/knotserver/handler.go b/knotserver/handler.go index cce5669f..6a45ffe8 100644 --- a/knotserver/handler.go +++ b/knotserver/handler.go @@ -78,7 +78,7 @@ func Setup(ctx context.Context, c *config.Config, db *db.DB, e *rbac.Enforcer, l }) r.Route("/blob/{ref}", func(r chi.Router) { - r.Get("/*", h.FileContent) + r.Get("/*", h.Blob) }) r.Get("/log/{ref}", h.Log) diff --git a/knotserver/routes.go b/knotserver/routes.go index a3e894b5..314b97f3 100644 --- a/knotserver/routes.go +++ b/knotserver/routes.go @@ -129,23 +129,12 @@ func (h *Handle) RepoTree(w http.ResponseWriter, r *http.Request) { DotDot: filepath.Dir(treePath), Files: files, } - // data := make(map[string]any) - // data["ref"] = ref - // data["parent"] = treePath - // data["desc"] = getDescription(path) - // data["dotdot"] = filepath.Dir(treePath) writeJSON(w, resp) - // h.listFiles(files, data, w) return } -func (h *Handle) FileContent(w http.ResponseWriter, r *http.Request) { - var raw bool - if rawParam, err := strconv.ParseBool(r.URL.Query().Get("raw")); err == nil { - raw = rawParam - } - +func (h *Handle) Blob(w http.ResponseWriter, r *http.Request) { treePath := chi.URLParam(r, "*") ref := chi.URLParam(r, "ref") @@ -163,18 +152,16 @@ func (h *Handle) FileContent(w http.ResponseWriter, r *http.Request) { writeError(w, err.Error(), http.StatusInternalServerError) return } - data := make(map[string]any) - data["ref"] = ref - data["desc"] = getDescription(path) - data["path"] = treePath - safe := sanitize([]byte(contents)) + safe := string(sanitize([]byte(contents))) - if raw { - h.showRaw(string(safe), w) - } else { - h.showFile(string(safe), data, w, l) + resp := types.RepoBlobResponse{ + Ref: ref, + Contents: string(safe), + Path: treePath, } + + h.showFile(resp, w, l) } func (h *Handle) Archive(w http.ResponseWriter, r *http.Request) { @@ -341,6 +328,11 @@ func (h *Handle) Tags(w http.ResponseWriter, r *http.Request) { }, Tag: tag.TagObject(), } + + if tag.Message() != "" { + tr.Message = tag.Message() + } + rtags = append(rtags, &tr) } diff --git a/types/repo.go b/types/repo.go index 904138bf..9c41cb7c 100644 --- a/types/repo.go +++ b/types/repo.go @@ -59,3 +59,11 @@ type RepoTagsResponse struct { type RepoBranchesResponse struct { Branches []Branch `json:"branches,omitempty"` } + +type RepoBlobResponse struct { + Contents string `json:"contents,omitempty"` + Ref string `json:"ref,omitempty"` + Path string `json:"path,omitempty"` + + Lines int `json:"lines,omitempty"` +} diff --git a/types/tree.go b/types/tree.go index 5b0063fb..de100aa6 100644 --- a/types/tree.go +++ b/types/tree.go @@ -2,9 +2,9 @@ package types // A nicer git tree representation. type NiceTree struct { - Name string - Mode string - Size int64 - IsFile bool - IsSubtree bool + Name string `json:"name"` + Mode string `json:"mode"` + Size int64 `json:"size"` + IsFile bool `json:"is_file"` + IsSubtree bool `json:"is_subtree"` } -- 2.51.2