+1
.gitignore
+1
.gitignore
appview.db-journal
appview.db-journal
This is a binary file and will not be displayed.
+10
appview/pages/pages.go
+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
+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
+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
+1
knotserver/handler.go
+21
-10
knotserver/routes.go
+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)