forked from tangled.org/core
this repo has no description

appview: implement a basic breadcrumb for files

This needs another pass to fix the intermediate directory links etc.

anirudh.fi f94a9007 0aa1229c

verified
Changed files
+48 -12
appview
pages
templates
repo
knotserver
types
+1
.gitignore
··· 1 1 .direnv/ 2 2 tmp 3 3 *.db 4 + *.db-* 4 5 .bin/ 5 6 appview/pages/static/* 6 7 result
appview.db-journal

This is a binary file and will not be displayed.

+10
appview/pages/pages.go
··· 8 8 "io/fs" 9 9 "log" 10 10 "net/http" 11 + "os" 11 12 "path" 13 + "path/filepath" 12 14 "strings" 13 15 14 16 "github.com/dustin/go-humanize" ··· 259 261 LoggedInUser *auth.User 260 262 RepoInfo RepoInfo 261 263 Active string 264 + File string 265 + PathElems []string 262 266 types.RepoBlobResponse 263 267 } 264 268 265 269 func (p *Pages) RepoBlob(w io.Writer, params RepoBlobParams) error { 270 + path := filepath.Dir(params.Path) 271 + file := filepath.Base(params.Path) 272 + 273 + params.PathElems = strings.Split(path, string(os.PathSeparator)) 274 + params.Path = path 275 + params.File = file 266 276 params.Active = "overview" 267 277 return p.executeRepo("repo/blob", w, params) 268 278 }
+9 -1
appview/pages/templates/repo/blob.html
··· 3 3 {{ $tot_lines := len $lines }} 4 4 {{ $tot_chars := len (printf "%d" $tot_lines) }} 5 5 {{ $code_number_style := "text-gray-400 left-0 bg-white text-right mr-2 select-none" }} 6 + <div class="pb-2 text-lg"> 7 + {{ range .PathElems }} 8 + <a href="/{{ $.RepoInfo.FullName }}/tree/{{ $.Ref }}/{{ . }}" class="text-bold text-gray-500">{{ . }}</a> / 9 + {{ end }}<span class="">{{ .File }}</span> 10 + </div> 11 + 12 + 13 + {{ if .IsBinary }}<p class="text-center text-gray-400">This is a binary file and will not be displayed.</p>{{ else }} 6 14 <pre class="font-mono text-sm overflow-auto relative text-ellipsis"><code>{{ range $idx, $line := $lines }}<span class="flex"> 7 15 <span class="{{ $code_number_style }}" style="min-width: {{$tot_chars}}ch;">{{ add $idx 1 }}</span> 8 - <span class="whitespace-pre">{{ $line }}</span></span>{{ else }}<em class="text-gray-400">this file is empty</em>{{ end }}</code></pre> 16 + <span class="whitespace-pre">{{ $line }}</span></span>{{ else }}<em class="text-gray-400">this file is empty</em>{{ end }}</code></pre>{{ end}} 9 17 {{ end }}
+5 -1
knotserver/git/git.go
··· 14 14 "github.com/go-git/go-git/v5/plumbing/object" 15 15 ) 16 16 17 + var ( 18 + ErrBinaryFile = fmt.Errorf("binary file") 19 + ) 20 + 17 21 type GitRepo struct { 18 22 r *git.Repository 19 23 h plumbing.Hash ··· 148 152 if !isbin { 149 153 return file.Contents() 150 154 } else { 151 - return "Not displaying binary file", nil 155 + return "", ErrBinaryFile 152 156 } 153 157 } 154 158
+1
knotserver/handler.go
··· 76 76 r.Post("/git-upload-pack", h.UploadPack) 77 77 78 78 r.Route("/tree/{ref}", func(r chi.Router) { 79 + r.Get("/", h.RepoIndex) 79 80 r.Get("/*", h.RepoTree) 80 81 }) 81 82
+21 -10
knotserver/routes.go
··· 32 32 func (h *Handle) RepoIndex(w http.ResponseWriter, r *http.Request) { 33 33 path, _ := securejoin.SecureJoin(h.c.Repo.ScanPath, didPath(r)) 34 34 l := h.l.With("path", path, "handler", "RepoIndex") 35 + ref := chi.URLParam(r, "ref") 35 36 36 - gr, err := git.Open(path, "") 37 + gr, err := git.Open(path, ref) 37 38 if err != nil { 38 39 if errors.Is(err, plumbing.ErrReferenceNotFound) { 39 40 resp := types.RepoIndexResponse{ ··· 84 85 l.Warn("no readme found") 85 86 } 86 87 87 - mainBranch, err := gr.FindMainBranch(h.c.Repo.MainBranch) 88 + files, err := gr.FileTree("") 88 89 if err != nil { 89 90 writeError(w, err.Error(), http.StatusInternalServerError) 90 - l.Error("finding main branch", "error", err.Error()) 91 + l.Error("file tree", "error", err.Error()) 91 92 return 92 93 } 93 94 94 - files, err := gr.FileTree("") 95 - if err != nil { 96 - writeError(w, err.Error(), http.StatusInternalServerError) 97 - l.Error("file tree", "error", err.Error()) 98 - return 95 + if ref == "" { 96 + mainBranch, err := gr.FindMainBranch(h.c.Repo.MainBranch) 97 + if err != nil { 98 + writeError(w, err.Error(), http.StatusInternalServerError) 99 + l.Error("finding main branch", "error", err.Error()) 100 + return 101 + } 102 + ref = mainBranch 99 103 } 100 104 101 105 resp := types.RepoIndexResponse{ 102 106 IsEmpty: false, 103 - Ref: mainBranch, 107 + Ref: ref, 104 108 Commits: commits, 105 109 Description: getDescription(path), 106 110 Readme: readmeContent, ··· 156 160 return 157 161 } 158 162 163 + var isBinaryFile bool = false 159 164 contents, err := gr.FileContent(treePath) 160 - if err != nil { 165 + if errors.Is(err, git.ErrBinaryFile) { 166 + isBinaryFile = true 167 + } else if errors.Is(err, object.ErrFileNotFound) { 168 + notFound(w) 169 + return 170 + } else if err != nil { 161 171 writeError(w, err.Error(), http.StatusInternalServerError) 162 172 return 163 173 } ··· 168 178 Ref: ref, 169 179 Contents: string(safe), 170 180 Path: treePath, 181 + IsBinary: isBinaryFile, 171 182 } 172 183 173 184 h.showFile(resp, w, l)
+1
types/repo.go
··· 65 65 Contents string `json:"contents,omitempty"` 66 66 Ref string `json:"ref,omitempty"` 67 67 Path string `json:"path,omitempty"` 68 + IsBinary bool `json:"is_binary,omitempty"` 68 69 69 70 Lines int `json:"lines,omitempty"` 70 71 }