+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
"io/fs"
9
"log"
10
"net/http"
11
"path"
12
"strings"
13
14
"github.com/dustin/go-humanize"
···
259
LoggedInUser *auth.User
260
RepoInfo RepoInfo
261
Active string
262
types.RepoBlobResponse
263
}
264
265
func (p *Pages) RepoBlob(w io.Writer, params RepoBlobParams) error {
266
params.Active = "overview"
267
return p.executeRepo("repo/blob", w, params)
268
}
···
8
"io/fs"
9
"log"
10
"net/http"
11
+
"os"
12
"path"
13
+
"path/filepath"
14
"strings"
15
16
"github.com/dustin/go-humanize"
···
261
LoggedInUser *auth.User
262
RepoInfo RepoInfo
263
Active string
264
+
File string
265
+
PathElems []string
266
types.RepoBlobResponse
267
}
268
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
276
params.Active = "overview"
277
return p.executeRepo("repo/blob", w, params)
278
}
+9
-1
appview/pages/templates/repo/blob.html
+9
-1
appview/pages/templates/repo/blob.html
···
3
{{ $tot_lines := len $lines }}
4
{{ $tot_chars := len (printf "%d" $tot_lines) }}
5
{{ $code_number_style := "text-gray-400 left-0 bg-white text-right mr-2 select-none" }}
6
<pre class="font-mono text-sm overflow-auto relative text-ellipsis"><code>{{ range $idx, $line := $lines }}<span class="flex">
7
<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>
9
{{ end }}
···
3
{{ $tot_lines := len $lines }}
4
{{ $tot_chars := len (printf "%d" $tot_lines) }}
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 }}
14
<pre class="font-mono text-sm overflow-auto relative text-ellipsis"><code>{{ range $idx, $line := $lines }}<span class="flex">
15
<span class="{{ $code_number_style }}" style="min-width: {{$tot_chars}}ch;">{{ add $idx 1 }}</span>
16
+
<span class="whitespace-pre">{{ $line }}</span></span>{{ else }}<em class="text-gray-400">this file is empty</em>{{ end }}</code></pre>{{ end}}
17
{{ end }}
+5
-1
knotserver/git/git.go
+5
-1
knotserver/git/git.go
···
14
"github.com/go-git/go-git/v5/plumbing/object"
15
)
16
17
+
var (
18
+
ErrBinaryFile = fmt.Errorf("binary file")
19
+
)
20
+
21
type GitRepo struct {
22
r *git.Repository
23
h plumbing.Hash
···
152
if !isbin {
153
return file.Contents()
154
} else {
155
+
return "", ErrBinaryFile
156
}
157
}
158
+1
knotserver/handler.go
+1
knotserver/handler.go
+21
-10
knotserver/routes.go
+21
-10
knotserver/routes.go
···
32
func (h *Handle) RepoIndex(w http.ResponseWriter, r *http.Request) {
33
path, _ := securejoin.SecureJoin(h.c.Repo.ScanPath, didPath(r))
34
l := h.l.With("path", path, "handler", "RepoIndex")
35
36
-
gr, err := git.Open(path, "")
37
if err != nil {
38
if errors.Is(err, plumbing.ErrReferenceNotFound) {
39
resp := types.RepoIndexResponse{
···
84
l.Warn("no readme found")
85
}
86
87
-
mainBranch, err := gr.FindMainBranch(h.c.Repo.MainBranch)
88
if err != nil {
89
writeError(w, err.Error(), http.StatusInternalServerError)
90
-
l.Error("finding main branch", "error", err.Error())
91
return
92
}
93
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
99
}
100
101
resp := types.RepoIndexResponse{
102
IsEmpty: false,
103
-
Ref: mainBranch,
104
Commits: commits,
105
Description: getDescription(path),
106
Readme: readmeContent,
···
156
return
157
}
158
159
contents, err := gr.FileContent(treePath)
160
-
if err != nil {
161
writeError(w, err.Error(), http.StatusInternalServerError)
162
return
163
}
···
168
Ref: ref,
169
Contents: string(safe),
170
Path: treePath,
171
}
172
173
h.showFile(resp, w, l)
···
32
func (h *Handle) RepoIndex(w http.ResponseWriter, r *http.Request) {
33
path, _ := securejoin.SecureJoin(h.c.Repo.ScanPath, didPath(r))
34
l := h.l.With("path", path, "handler", "RepoIndex")
35
+
ref := chi.URLParam(r, "ref")
36
37
+
gr, err := git.Open(path, ref)
38
if err != nil {
39
if errors.Is(err, plumbing.ErrReferenceNotFound) {
40
resp := types.RepoIndexResponse{
···
85
l.Warn("no readme found")
86
}
87
88
+
files, err := gr.FileTree("")
89
if err != nil {
90
writeError(w, err.Error(), http.StatusInternalServerError)
91
+
l.Error("file tree", "error", err.Error())
92
return
93
}
94
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
103
}
104
105
resp := types.RepoIndexResponse{
106
IsEmpty: false,
107
+
Ref: ref,
108
Commits: commits,
109
Description: getDescription(path),
110
Readme: readmeContent,
···
160
return
161
}
162
163
+
var isBinaryFile bool = false
164
contents, err := gr.FileContent(treePath)
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 {
171
writeError(w, err.Error(), http.StatusInternalServerError)
172
return
173
}
···
178
Ref: ref,
179
Contents: string(safe),
180
Path: treePath,
181
+
IsBinary: isBinaryFile,
182
}
183
184
h.showFile(resp, w, l)
+1
types/repo.go
+1
types/repo.go