Goit

Simple and lightweight Git web server
git clone http://git.omkov.net/Goit
Log | Tree | Refs | README | Download

Goit/src/repo/tree.go (220 lines, 5.3 KiB) -rw-r--r-- file download

c2c5250 Jakob Wakeling 2023-12-12 09:13:37
0
// Copyright (C) 2023, Jakob Wakeling
c2c5250 Jakob Wakeling 2023-12-12 09:13:37
1
// All rights reserved.
c2c5250 Jakob Wakeling 2023-12-12 09:13:37
2
8e4646b Jakob Wakeling 2023-07-26 00:53:25
3
package repo
8e4646b Jakob Wakeling 2023-07-26 00:53:25
4
8e4646b Jakob Wakeling 2023-07-26 00:53:25
5
import (
6f00d17 Jakob Wakeling 2023-07-26 12:39:54
6
	"errors"
86e8cb8 Jakob Wakeling 2023-11-29 00:14:36
7
	"html/template"
8e4646b Jakob Wakeling 2023-07-26 00:53:25
8
	"log"
8e4646b Jakob Wakeling 2023-07-26 00:53:25
9
	"net/http"
86e8cb8 Jakob Wakeling 2023-11-29 00:14:36
10
	"path"
6f00d17 Jakob Wakeling 2023-07-26 12:39:54
11
	"sort"
8e4646b Jakob Wakeling 2023-07-26 00:53:25
12
	"strings"
8e4646b Jakob Wakeling 2023-07-26 00:53:25
13
945fd71 Jakob Wakeling 2023-11-05 15:39:31
14
	"github.com/Jamozed/Goit/src/goit"
8e4646b Jakob Wakeling 2023-07-26 00:53:25
15
	"github.com/Jamozed/Goit/src/util"
8e4646b Jakob Wakeling 2023-07-26 00:53:25
16
	"github.com/dustin/go-humanize"
3f4c3f4 Jakob Wakeling 2023-12-01 23:26:03
17
	"github.com/go-chi/chi/v5"
8e4646b Jakob Wakeling 2023-07-26 00:53:25
18
	"github.com/go-git/go-git/v5"
20732d3 Jakob Wakeling 2023-07-26 22:38:15
19
	"github.com/go-git/go-git/v5/plumbing"
8e4646b Jakob Wakeling 2023-07-26 00:53:25
20
	"github.com/go-git/go-git/v5/plumbing/object"
8e4646b Jakob Wakeling 2023-07-26 00:53:25
21
)
8e4646b Jakob Wakeling 2023-07-26 00:53:25
22
8e4646b Jakob Wakeling 2023-07-26 00:53:25
23
func HandleTree(w http.ResponseWriter, r *http.Request) {
473d02c Jakob Wakeling 2023-11-28 00:01:06
24
	auth, user, err := goit.Auth(w, r, true)
473d02c Jakob Wakeling 2023-11-28 00:01:06
25
	if err != nil {
473d02c Jakob Wakeling 2023-11-28 00:01:06
26
		log.Println("[admin]", err.Error())
473d02c Jakob Wakeling 2023-11-28 00:01:06
27
		goit.HttpError(w, http.StatusInternalServerError)
473d02c Jakob Wakeling 2023-11-28 00:01:06
28
	}
473d02c Jakob Wakeling 2023-11-28 00:01:06
29
3f4c3f4 Jakob Wakeling 2023-12-01 23:26:03
30
	tpath := chi.URLParam(r, "*")
8e4646b Jakob Wakeling 2023-07-26 00:53:25
31
3f4c3f4 Jakob Wakeling 2023-12-01 23:26:03
32
	repo, err := goit.GetRepoByName(chi.URLParam(r, "repo"))
8e4646b Jakob Wakeling 2023-07-26 00:53:25
33
	if err != nil {
8e4646b Jakob Wakeling 2023-07-26 00:53:25
34
		goit.HttpError(w, http.StatusInternalServerError)
8e4646b Jakob Wakeling 2023-07-26 00:53:25
35
		return
778d467 Jakob Wakeling 2024-01-17 18:29:55
36
	} else if repo == nil || !goit.IsVisible(repo, auth, user) {
8e4646b Jakob Wakeling 2023-07-26 00:53:25
37
		goit.HttpError(w, http.StatusNotFound)
8e4646b Jakob Wakeling 2023-07-26 00:53:25
38
		return
8e4646b Jakob Wakeling 2023-07-26 00:53:25
39
	}
8e4646b Jakob Wakeling 2023-07-26 00:53:25
40
8e4646b Jakob Wakeling 2023-07-26 00:53:25
41
	type row struct {
d314664 Jakob Wakeling 2023-11-03 23:00:26
42
		Mode, Name, Path, RawPath, Size string
a0ac27c Jakob Wakeling 2024-07-06 23:32:05
43
		IsFile, IsText, B               bool
8e4646b Jakob Wakeling 2023-07-26 00:53:25
44
	}
8e4646b Jakob Wakeling 2023-07-26 00:53:25
45
	data := struct {
2e13a8c Jakob Wakeling 2023-12-23 19:40:09
46
		HeaderFields
2e13a8c Jakob Wakeling 2023-12-23 19:40:09
47
		Title, Path, Size string
2e13a8c Jakob Wakeling 2023-12-23 19:40:09
48
		Files             []row
2e13a8c Jakob Wakeling 2023-12-23 19:40:09
49
		HtmlPath          template.HTML
8e4646b Jakob Wakeling 2023-07-26 00:53:25
50
	}{
2e13a8c Jakob Wakeling 2023-12-23 19:40:09
51
		Title:        repo.Name + " - Tree",
2e13a8c Jakob Wakeling 2023-12-23 19:40:09
52
		HeaderFields: GetHeaderFields(auth, user, repo, r.Host),
8e4646b Jakob Wakeling 2023-07-26 00:53:25
53
	}
8e4646b Jakob Wakeling 2023-07-26 00:53:25
54
3f4c3f4 Jakob Wakeling 2023-12-01 23:26:03
55
	parts := strings.Split(tpath, "/")
86e8cb8 Jakob Wakeling 2023-11-29 00:14:36
56
	htmlPath := "<b style=\"padding-left: 0.4rem;\"><a href=\"/" + repo.Name + "/tree\">" + repo.Name + "</a></b>/"
86e8cb8 Jakob Wakeling 2023-11-29 00:14:36
57
	dirPath := ""
86e8cb8 Jakob Wakeling 2023-11-29 00:14:36
58
86e8cb8 Jakob Wakeling 2023-11-29 00:14:36
59
	for i := 0; i < len(parts)-1; i += 1 {
86e8cb8 Jakob Wakeling 2023-11-29 00:14:36
60
		dirPath = path.Join(dirPath, parts[i])
86e8cb8 Jakob Wakeling 2023-11-29 00:14:36
61
		htmlPath += "<a href=\"/" + repo.Name + "/tree/" + dirPath + "\">" + parts[i] + "</a>/"
86e8cb8 Jakob Wakeling 2023-11-29 00:14:36
62
	}
86e8cb8 Jakob Wakeling 2023-11-29 00:14:36
63
	htmlPath += parts[len(parts)-1]
86e8cb8 Jakob Wakeling 2023-11-29 00:14:36
64
2e13a8c Jakob Wakeling 2023-12-23 19:40:09
65
	data.Path = tpath
86e8cb8 Jakob Wakeling 2023-11-29 00:14:36
66
	data.HtmlPath = template.HTML(htmlPath)
86e8cb8 Jakob Wakeling 2023-11-29 00:14:36
67
08dff9a Jakob Wakeling 2023-11-07 21:03:04
68
	gr, err := git.PlainOpen(goit.RepoPath(repo.Name, true))
8e4646b Jakob Wakeling 2023-07-26 00:53:25
69
	if err != nil {
8e4646b Jakob Wakeling 2023-07-26 00:53:25
70
		log.Println("[/repo/tree]", err.Error())
8e4646b Jakob Wakeling 2023-07-26 00:53:25
71
		goit.HttpError(w, http.StatusInternalServerError)
8e4646b Jakob Wakeling 2023-07-26 00:53:25
72
		return
8e4646b Jakob Wakeling 2023-07-26 00:53:25
73
	}
8e4646b Jakob Wakeling 2023-07-26 00:53:25
74
20732d3 Jakob Wakeling 2023-07-26 22:38:15
75
	if ref, err := gr.Head(); err != nil {
20732d3 Jakob Wakeling 2023-07-26 22:38:15
76
		if !errors.Is(err, plumbing.ErrReferenceNotFound) {
20732d3 Jakob Wakeling 2023-07-26 22:38:15
77
			log.Println("[/repo/tree]", err.Error())
20732d3 Jakob Wakeling 2023-07-26 22:38:15
78
			goit.HttpError(w, http.StatusInternalServerError)
6f00d17 Jakob Wakeling 2023-07-26 12:39:54
79
			return
20732d3 Jakob Wakeling 2023-07-26 22:38:15
80
		}
20732d3 Jakob Wakeling 2023-07-26 22:38:15
81
	} else {
b4b291e Jakob Wakeling 2023-12-23 17:05:01
82
		if readme, _ := findPattern(gr, ref, readmePattern); readme != "" {
86e8cb8 Jakob Wakeling 2023-11-29 00:14:36
83
			data.Readme = path.Join("/", repo.Name, "file", readme)
7ba1b21 Jakob Wakeling 2023-08-02 21:44:07
84
		}
b4b291e Jakob Wakeling 2023-12-23 17:05:01
85
		if licence, _ := findPattern(gr, ref, licencePattern); licence != "" {
86e8cb8 Jakob Wakeling 2023-11-29 00:14:36
86
			data.Licence = path.Join("/", repo.Name, "file", licence)
7ba1b21 Jakob Wakeling 2023-08-02 21:44:07
87
		}
7ba1b21 Jakob Wakeling 2023-08-02 21:44:07
88
20732d3 Jakob Wakeling 2023-07-26 22:38:15
89
		commit, err := gr.CommitObject(ref.Hash())
20732d3 Jakob Wakeling 2023-07-26 22:38:15
90
		if err != nil {
6f00d17 Jakob Wakeling 2023-07-26 12:39:54
91
			log.Println("[/repo/tree]", err.Error())
6f00d17 Jakob Wakeling 2023-07-26 12:39:54
92
			goit.HttpError(w, http.StatusInternalServerError)
6f00d17 Jakob Wakeling 2023-07-26 12:39:54
93
			return
6f00d17 Jakob Wakeling 2023-07-26 12:39:54
94
		}
6f00d17 Jakob Wakeling 2023-07-26 12:39:54
95
20732d3 Jakob Wakeling 2023-07-26 22:38:15
96
		tree, err := commit.Tree()
20732d3 Jakob Wakeling 2023-07-26 22:38:15
97
		if err != nil {
20732d3 Jakob Wakeling 2023-07-26 22:38:15
98
			log.Println("[/repo/tree]", err.Error())
20732d3 Jakob Wakeling 2023-07-26 22:38:15
99
			goit.HttpError(w, http.StatusInternalServerError)
20732d3 Jakob Wakeling 2023-07-26 22:38:15
100
			return
6f00d17 Jakob Wakeling 2023-07-26 12:39:54
101
		}
6f00d17 Jakob Wakeling 2023-07-26 12:39:54
102
3f4c3f4 Jakob Wakeling 2023-12-01 23:26:03
103
		if tpath != "" {
5aa454c Jakob Wakeling 2023-07-27 17:45:56
104
			data.Files = append(data.Files, row{
3f4c3f4 Jakob Wakeling 2023-12-01 23:26:03
105
				Mode: "d---------", Name: "..", Path: path.Join("tree", path.Dir(tpath)),
5aa454c Jakob Wakeling 2023-07-27 17:45:56
106
			})
6f00d17 Jakob Wakeling 2023-07-26 12:39:54
107
3f4c3f4 Jakob Wakeling 2023-12-01 23:26:03
108
			tree, err = tree.Tree(tpath)
20732d3 Jakob Wakeling 2023-07-26 22:38:15
109
			if errors.Is(err, object.ErrDirectoryNotFound) {
20732d3 Jakob Wakeling 2023-07-26 22:38:15
110
				goit.HttpError(w, http.StatusNotFound)
20732d3 Jakob Wakeling 2023-07-26 22:38:15
111
				return
20732d3 Jakob Wakeling 2023-07-26 22:38:15
112
			} else if err != nil {
6f00d17 Jakob Wakeling 2023-07-26 12:39:54
113
				log.Println("[/repo/tree]", err.Error())
6f00d17 Jakob Wakeling 2023-07-26 12:39:54
114
				goit.HttpError(w, http.StatusInternalServerError)
6f00d17 Jakob Wakeling 2023-07-26 12:39:54
115
				return
6f00d17 Jakob Wakeling 2023-07-26 12:39:54
116
			}
6f00d17 Jakob Wakeling 2023-07-26 12:39:54
117
		}
6f00d17 Jakob Wakeling 2023-07-26 12:39:54
118
20732d3 Jakob Wakeling 2023-07-26 22:38:15
119
		sort.SliceStable(tree.Entries, func(i, j int) bool {
20732d3 Jakob Wakeling 2023-07-26 22:38:15
120
			if tree.Entries[i].Mode&0o40000 != 0 && tree.Entries[j].Mode&0o40000 == 0 {
20732d3 Jakob Wakeling 2023-07-26 22:38:15
121
				return true
20732d3 Jakob Wakeling 2023-07-26 22:38:15
122
			}
20732d3 Jakob Wakeling 2023-07-26 22:38:15
123
20732d3 Jakob Wakeling 2023-07-26 22:38:15
124
			return tree.Entries[i].Name < tree.Entries[j].Name
8e4646b Jakob Wakeling 2023-07-26 00:53:25
125
		})
20732d3 Jakob Wakeling 2023-07-26 22:38:15
126
86e8cb8 Jakob Wakeling 2023-11-29 00:14:36
127
		var totalSize uint64
86e8cb8 Jakob Wakeling 2023-11-29 00:14:36
128
20732d3 Jakob Wakeling 2023-07-26 22:38:15
129
		for _, v := range tree.Entries {
d314664 Jakob Wakeling 2023-11-03 23:00:26
130
			var fpath, rpath, size string
a0ac27c Jakob Wakeling 2024-07-06 23:32:05
131
			var isFile, isText bool
20732d3 Jakob Wakeling 2023-07-26 22:38:15
132
20732d3 Jakob Wakeling 2023-07-26 22:38:15
133
			if v.Mode&0o40000 == 0 {
3f4c3f4 Jakob Wakeling 2023-12-01 23:26:03
134
				fpath = path.Join("file", tpath, v.Name)
3f4c3f4 Jakob Wakeling 2023-12-01 23:26:03
135
				rpath = path.Join(tpath, v.Name)
1c90d8b Jakob Wakeling 2023-11-20 22:14:10
136
				isFile = true
86e8cb8 Jakob Wakeling 2023-11-29 00:14:36
137
313c62b Jakob Wakeling 2023-12-24 00:08:13
138
				goit.SizesLock.RLock()
313c62b Jakob Wakeling 2023-12-24 00:08:13
139
				sz, ok := goit.Sizes[v.Hash]
313c62b Jakob Wakeling 2023-12-24 00:08:13
140
				goit.SizesLock.RUnlock()
cfc2b79 Jakob Wakeling 2023-07-27 13:12:30
141
313c62b Jakob Wakeling 2023-12-24 00:08:13
142
				if !ok {
313c62b Jakob Wakeling 2023-12-24 00:08:13
143
					file, err := tree.File(v.Name)
313c62b Jakob Wakeling 2023-12-24 00:08:13
144
					if err != nil {
313c62b Jakob Wakeling 2023-12-24 00:08:13
145
						log.Println("[/repo/tree]", err.Error())
313c62b Jakob Wakeling 2023-12-24 00:08:13
146
						goit.HttpError(w, http.StatusInternalServerError)
313c62b Jakob Wakeling 2023-12-24 00:08:13
147
						return
313c62b Jakob Wakeling 2023-12-24 00:08:13
148
					}
313c62b Jakob Wakeling 2023-12-24 00:08:13
149
313c62b Jakob Wakeling 2023-12-24 00:08:13
150
					sz = uint64(file.Size)
cfc2b79 Jakob Wakeling 2023-07-27 13:12:30
151
313c62b Jakob Wakeling 2023-12-24 00:08:13
152
					goit.SizesLock.Lock()
313c62b Jakob Wakeling 2023-12-24 00:08:13
153
					goit.Sizes[v.Hash] = sz
313c62b Jakob Wakeling 2023-12-24 00:08:13
154
					goit.SizesLock.Unlock()
cfc2b79 Jakob Wakeling 2023-07-27 13:12:30
155
				}
cfc2b79 Jakob Wakeling 2023-07-27 13:12:30
156
313c62b Jakob Wakeling 2023-12-24 00:08:13
157
				size = humanize.IBytes(sz)
313c62b Jakob Wakeling 2023-12-24 00:08:13
158
				totalSize += sz
a0ac27c Jakob Wakeling 2024-07-06 23:32:05
159
a0ac27c Jakob Wakeling 2024-07-06 23:32:05
160
				file, err := tree.File(v.Name)
a0ac27c Jakob Wakeling 2024-07-06 23:32:05
161
				if err == nil {
a0ac27c Jakob Wakeling 2024-07-06 23:32:05
162
					ftype, err := goit.GetFileType(file)
a0ac27c Jakob Wakeling 2024-07-06 23:32:05
163
					if err == nil {
a0ac27c Jakob Wakeling 2024-07-06 23:32:05
164
						if strings.HasPrefix(ftype, "text") {
a0ac27c Jakob Wakeling 2024-07-06 23:32:05
165
							isText = true
a0ac27c Jakob Wakeling 2024-07-06 23:32:05
166
						}
a0ac27c Jakob Wakeling 2024-07-06 23:32:05
167
					}
a0ac27c Jakob Wakeling 2024-07-06 23:32:05
168
				}
313c62b Jakob Wakeling 2023-12-24 00:08:13
169
			} else {
3f4c3f4 Jakob Wakeling 2023-12-01 23:26:03
170
				fpath = path.Join("tree", tpath, v.Name)
3f4c3f4 Jakob Wakeling 2023-12-01 23:26:03
171
				rpath = path.Join(tpath, v.Name)
313c62b Jakob Wakeling 2023-12-24 00:08:13
172
313c62b Jakob Wakeling 2023-12-24 00:08:13
173
				goit.SizesLock.RLock()
313c62b Jakob Wakeling 2023-12-24 00:08:13
174
				sz, ok := goit.Sizes[v.Hash]
313c62b Jakob Wakeling 2023-12-24 00:08:13
175
				goit.SizesLock.RUnlock()
313c62b Jakob Wakeling 2023-12-24 00:08:13
176
313c62b Jakob Wakeling 2023-12-24 00:08:13
177
				if !ok {
313c62b Jakob Wakeling 2023-12-24 00:08:13
178
					dirt, err := tree.Tree(v.Name)
313c62b Jakob Wakeling 2023-12-24 00:08:13
179
					if err != nil {
313c62b Jakob Wakeling 2023-12-24 00:08:13
180
						log.Println("[/repo/tree]", err.Error())
313c62b Jakob Wakeling 2023-12-24 00:08:13
181
						goit.HttpError(w, http.StatusInternalServerError)
313c62b Jakob Wakeling 2023-12-24 00:08:13
182
						return
313c62b Jakob Wakeling 2023-12-24 00:08:13
183
					}
86e8cb8 Jakob Wakeling 2023-11-29 00:14:36
184
313c62b Jakob Wakeling 2023-12-24 00:08:13
185
					var dirSize uint64
313c62b Jakob Wakeling 2023-12-24 00:08:13
186
					if err := dirt.Files().ForEach(func(f *object.File) error {
313c62b Jakob Wakeling 2023-12-24 00:08:13
187
						dirSize += uint64(f.Size)
313c62b Jakob Wakeling 2023-12-24 00:08:13
188
						return nil
313c62b Jakob Wakeling 2023-12-24 00:08:13
189
					}); err != nil {
313c62b Jakob Wakeling 2023-12-24 00:08:13
190
						log.Println("[/repo/tree]", err.Error())
313c62b Jakob Wakeling 2023-12-24 00:08:13
191
						goit.HttpError(w, http.StatusInternalServerError)
313c62b Jakob Wakeling 2023-12-24 00:08:13
192
						return
313c62b Jakob Wakeling 2023-12-24 00:08:13
193
					}
313c62b Jakob Wakeling 2023-12-24 00:08:13
194
313c62b Jakob Wakeling 2023-12-24 00:08:13
195
					sz = dirSize
313c62b Jakob Wakeling 2023-12-24 00:08:13
196
313c62b Jakob Wakeling 2023-12-24 00:08:13
197
					goit.SizesLock.Lock()
313c62b Jakob Wakeling 2023-12-24 00:08:13
198
					goit.Sizes[v.Hash] = sz
313c62b Jakob Wakeling 2023-12-24 00:08:13
199
					goit.SizesLock.Unlock()
313c62b Jakob Wakeling 2023-12-24 00:08:13
200
				}
313c62b Jakob Wakeling 2023-12-24 00:08:13
201
313c62b Jakob Wakeling 2023-12-24 00:08:13
202
				size = humanize.IBytes(sz)
313c62b Jakob Wakeling 2023-12-24 00:08:13
203
				totalSize += sz
20732d3 Jakob Wakeling 2023-07-26 22:38:15
204
			}
20732d3 Jakob Wakeling 2023-07-26 22:38:15
205
20732d3 Jakob Wakeling 2023-07-26 22:38:15
206
			data.Files = append(data.Files, row{
d314664 Jakob Wakeling 2023-11-03 23:00:26
207
				Mode: util.ModeString(uint32(v.Mode)), Name: v.Name, Path: fpath, RawPath: rpath, Size: size,
a0ac27c Jakob Wakeling 2024-07-06 23:32:05
208
				IsFile: isFile, IsText: isText, B: util.If(strings.HasSuffix(size, " B"), true, false),
20732d3 Jakob Wakeling 2023-07-26 22:38:15
209
			})
20732d3 Jakob Wakeling 2023-07-26 22:38:15
210
		}
86e8cb8 Jakob Wakeling 2023-11-29 00:14:36
211
86e8cb8 Jakob Wakeling 2023-11-29 00:14:36
212
		data.Size = humanize.IBytes(totalSize)
8e4646b Jakob Wakeling 2023-07-26 00:53:25
213
	}
8e4646b Jakob Wakeling 2023-07-26 00:53:25
214
8e4646b Jakob Wakeling 2023-07-26 00:53:25
215
	if err := goit.Tmpl.ExecuteTemplate(w, "repo/tree", data); err != nil {
8e4646b Jakob Wakeling 2023-07-26 00:53:25
216
		log.Println("[/repo/tree]", err.Error())
8e4646b Jakob Wakeling 2023-07-26 00:53:25
217
	}
8e4646b Jakob Wakeling 2023-07-26 00:53:25
218
}
219