Goit

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

Goit/src/repo/file.go (152 lines, 3.8 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
5aa454c Jakob Wakeling 2023-07-27 17:45:56
3
package repo
5aa454c Jakob Wakeling 2023-07-27 17:45:56
4
5aa454c Jakob Wakeling 2023-07-27 17:45:56
5
import (
5aa454c Jakob Wakeling 2023-07-27 17:45:56
6
	"errors"
db4ceeb Jakob Wakeling 2023-11-30 23:38:18
7
	"fmt"
86e8cb8 Jakob Wakeling 2023-11-29 00:14:36
8
	"html/template"
5aa454c Jakob Wakeling 2023-07-27 17:45:56
9
	"net/http"
86e8cb8 Jakob Wakeling 2023-11-29 00:14:36
10
	"path"
5aa454c Jakob Wakeling 2023-07-27 17:45:56
11
	"strings"
5aa454c Jakob Wakeling 2023-07-27 17:45:56
12
945fd71 Jakob Wakeling 2023-11-05 15:39:31
13
	"github.com/Jamozed/Goit/src/goit"
5aa454c Jakob Wakeling 2023-07-27 17:45:56
14
	"github.com/Jamozed/Goit/src/util"
5aa454c Jakob Wakeling 2023-07-27 17:45:56
15
	"github.com/dustin/go-humanize"
3f4c3f4 Jakob Wakeling 2023-12-01 23:26:03
16
	"github.com/go-chi/chi/v5"
5aa454c Jakob Wakeling 2023-07-27 17:45:56
17
	"github.com/go-git/go-git/v5"
5aa454c Jakob Wakeling 2023-07-27 17:45:56
18
	"github.com/go-git/go-git/v5/plumbing"
5aa454c Jakob Wakeling 2023-07-27 17:45:56
19
	"github.com/go-git/go-git/v5/plumbing/object"
5aa454c Jakob Wakeling 2023-07-27 17:45:56
20
)
5aa454c Jakob Wakeling 2023-07-27 17:45:56
21
5aa454c Jakob Wakeling 2023-07-27 17:45:56
22
func HandleFile(w http.ResponseWriter, r *http.Request) {
473d02c Jakob Wakeling 2023-11-28 00:01:06
23
	auth, user, err := goit.Auth(w, r, true)
473d02c Jakob Wakeling 2023-11-28 00:01:06
24
	if err != nil {
a0ac27c Jakob Wakeling 2024-07-06 23:32:05
25
		util.PrintFuncError(err)
473d02c Jakob Wakeling 2023-11-28 00:01:06
26
		goit.HttpError(w, http.StatusInternalServerError)
473d02c Jakob Wakeling 2023-11-28 00:01:06
27
	}
5aa454c Jakob Wakeling 2023-07-27 17:45:56
28
3f4c3f4 Jakob Wakeling 2023-12-01 23:26:03
29
	tpath := chi.URLParam(r, "*")
5aa454c Jakob Wakeling 2023-07-27 17:45:56
30
3f4c3f4 Jakob Wakeling 2023-12-01 23:26:03
31
	repo, err := goit.GetRepoByName(chi.URLParam(r, "repo"))
5aa454c Jakob Wakeling 2023-07-27 17:45:56
32
	if err != nil {
5aa454c Jakob Wakeling 2023-07-27 17:45:56
33
		goit.HttpError(w, http.StatusInternalServerError)
5aa454c Jakob Wakeling 2023-07-27 17:45:56
34
		return
778d467 Jakob Wakeling 2024-01-17 18:29:55
35
	} else if repo == nil || !goit.IsVisible(repo, auth, user) {
5aa454c Jakob Wakeling 2023-07-27 17:45:56
36
		goit.HttpError(w, http.StatusNotFound)
5aa454c Jakob Wakeling 2023-07-27 17:45:56
37
		return
5aa454c Jakob Wakeling 2023-07-27 17:45:56
38
	}
5aa454c Jakob Wakeling 2023-07-27 17:45:56
39
5aa454c Jakob Wakeling 2023-07-27 17:45:56
40
	data := struct {
2e13a8c Jakob Wakeling 2023-12-23 19:40:09
41
		HeaderFields
2e13a8c Jakob Wakeling 2023-12-23 19:40:09
42
		Title, Path, LineC, Size, Mode string
2e13a8c Jakob Wakeling 2023-12-23 19:40:09
43
		Lines                          []string
d737f58 Jakob Wakeling 2023-12-28 21:15:51
44
		HtmlBody, HtmlPath, BodyCss    template.HTML
a0ac27c Jakob Wakeling 2024-07-06 23:32:05
45
		IsText                         bool
5aa454c Jakob Wakeling 2023-07-27 17:45:56
46
	}{
d737f58 Jakob Wakeling 2023-12-28 21:15:51
47
		Title:        repo.Name + " - " + tpath,
2e13a8c Jakob Wakeling 2023-12-23 19:40:09
48
		HeaderFields: GetHeaderFields(auth, user, repo, r.Host),
5aa454c Jakob Wakeling 2023-07-27 17:45:56
49
	}
5aa454c Jakob Wakeling 2023-07-27 17:45:56
50
08dff9a Jakob Wakeling 2023-11-07 21:03:04
51
	gr, err := git.PlainOpen(goit.RepoPath(repo.Name, true))
5aa454c Jakob Wakeling 2023-07-27 17:45:56
52
	if err != nil {
a0ac27c Jakob Wakeling 2024-07-06 23:32:05
53
		util.PrintFuncError(err)
5aa454c Jakob Wakeling 2023-07-27 17:45:56
54
		goit.HttpError(w, http.StatusInternalServerError)
5aa454c Jakob Wakeling 2023-07-27 17:45:56
55
		return
5aa454c Jakob Wakeling 2023-07-27 17:45:56
56
	}
5aa454c Jakob Wakeling 2023-07-27 17:45:56
57
5aa454c Jakob Wakeling 2023-07-27 17:45:56
58
	ref, err := gr.Head()
5aa454c Jakob Wakeling 2023-07-27 17:45:56
59
	if errors.Is(err, plumbing.ErrReferenceNotFound) {
5aa454c Jakob Wakeling 2023-07-27 17:45:56
60
		goit.HttpError(w, http.StatusNotFound)
5aa454c Jakob Wakeling 2023-07-27 17:45:56
61
		return
5aa454c Jakob Wakeling 2023-07-27 17:45:56
62
	} else if err != nil {
a0ac27c Jakob Wakeling 2024-07-06 23:32:05
63
		util.PrintFuncError(err)
5aa454c Jakob Wakeling 2023-07-27 17:45:56
64
		goit.HttpError(w, http.StatusInternalServerError)
5aa454c Jakob Wakeling 2023-07-27 17:45:56
65
		return
7ba1b21 Jakob Wakeling 2023-08-02 21:44:07
66
	}
7ba1b21 Jakob Wakeling 2023-08-02 21:44:07
67
b4b291e Jakob Wakeling 2023-12-23 17:05:01
68
	if readme, _ := findPattern(gr, ref, readmePattern); readme != "" {
86e8cb8 Jakob Wakeling 2023-11-29 00:14:36
69
		data.Readme = path.Join("/", repo.Name, "file", readme)
7ba1b21 Jakob Wakeling 2023-08-02 21:44:07
70
	}
b4b291e Jakob Wakeling 2023-12-23 17:05:01
71
	if licence, _ := findPattern(gr, ref, licencePattern); licence != "" {
86e8cb8 Jakob Wakeling 2023-11-29 00:14:36
72
		data.Licence = path.Join("/", repo.Name, "file", licence)
5aa454c Jakob Wakeling 2023-07-27 17:45:56
73
	}
5aa454c Jakob Wakeling 2023-07-27 17:45:56
74
5aa454c Jakob Wakeling 2023-07-27 17:45:56
75
	commit, err := gr.CommitObject(ref.Hash())
5aa454c Jakob Wakeling 2023-07-27 17:45:56
76
	if err != nil {
a0ac27c Jakob Wakeling 2024-07-06 23:32:05
77
		util.PrintFuncError(err)
5aa454c Jakob Wakeling 2023-07-27 17:45:56
78
		goit.HttpError(w, http.StatusInternalServerError)
5aa454c Jakob Wakeling 2023-07-27 17:45:56
79
		return
5aa454c Jakob Wakeling 2023-07-27 17:45:56
80
	}
5aa454c Jakob Wakeling 2023-07-27 17:45:56
81
3f4c3f4 Jakob Wakeling 2023-12-01 23:26:03
82
	file, err := commit.File(tpath)
5aa454c Jakob Wakeling 2023-07-27 17:45:56
83
	if errors.Is(err, object.ErrFileNotFound) {
5aa454c Jakob Wakeling 2023-07-27 17:45:56
84
		goit.HttpError(w, http.StatusNotFound)
5aa454c Jakob Wakeling 2023-07-27 17:45:56
85
		return
5aa454c Jakob Wakeling 2023-07-27 17:45:56
86
	} else if err != nil {
a0ac27c Jakob Wakeling 2024-07-06 23:32:05
87
		util.PrintFuncError(err)
5aa454c Jakob Wakeling 2023-07-27 17:45:56
88
		goit.HttpError(w, http.StatusInternalServerError)
5aa454c Jakob Wakeling 2023-07-27 17:45:56
89
		return
5aa454c Jakob Wakeling 2023-07-27 17:45:56
90
	}
5aa454c Jakob Wakeling 2023-07-27 17:45:56
91
5aa454c Jakob Wakeling 2023-07-27 17:45:56
92
	data.Mode = util.ModeString(uint32(file.Mode))
86e8cb8 Jakob Wakeling 2023-11-29 00:14:36
93
	data.Path = file.Name
5aa454c Jakob Wakeling 2023-07-27 17:45:56
94
	data.Size = humanize.IBytes(uint64(file.Size))
86e8cb8 Jakob Wakeling 2023-11-29 00:14:36
95
86e8cb8 Jakob Wakeling 2023-11-29 00:14:36
96
	parts := strings.Split(file.Name, "/")
86e8cb8 Jakob Wakeling 2023-11-29 00:14:36
97
	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
98
	dirPath := ""
86e8cb8 Jakob Wakeling 2023-11-29 00:14:36
99
86e8cb8 Jakob Wakeling 2023-11-29 00:14:36
100
	for i := 0; i < len(parts)-1; i += 1 {
86e8cb8 Jakob Wakeling 2023-11-29 00:14:36
101
		dirPath = path.Join(dirPath, parts[i])
86e8cb8 Jakob Wakeling 2023-11-29 00:14:36
102
		htmlPath += "<a href=\"/" + repo.Name + "/tree/" + dirPath + "\">" + parts[i] + "</a>/"
86e8cb8 Jakob Wakeling 2023-11-29 00:14:36
103
	}
86e8cb8 Jakob Wakeling 2023-11-29 00:14:36
104
	htmlPath += parts[len(parts)-1]
86e8cb8 Jakob Wakeling 2023-11-29 00:14:36
105
86e8cb8 Jakob Wakeling 2023-11-29 00:14:36
106
	data.HtmlPath = template.HTML(htmlPath)
5aa454c Jakob Wakeling 2023-07-27 17:45:56
107
a0ac27c Jakob Wakeling 2024-07-06 23:32:05
108
	ftype, err := goit.GetFileType(file)
a0ac27c Jakob Wakeling 2024-07-06 23:32:05
109
	if err != nil {
a0ac27c Jakob Wakeling 2024-07-06 23:32:05
110
		util.PrintFuncError(err)
5aa454c Jakob Wakeling 2023-07-27 17:45:56
111
		goit.HttpError(w, http.StatusInternalServerError)
5aa454c Jakob Wakeling 2023-07-27 17:45:56
112
		return
a0ac27c Jakob Wakeling 2024-07-06 23:32:05
113
	}
5aa454c Jakob Wakeling 2023-07-27 17:45:56
114
a0ac27c Jakob Wakeling 2024-07-06 23:32:05
115
	/* Only populate lines for text files */
a0ac27c Jakob Wakeling 2024-07-06 23:32:05
116
	if strings.HasPrefix(ftype, "text") {
a0ac27c Jakob Wakeling 2024-07-06 23:32:05
117
		rc, err := file.Blob.Reader()
a0ac27c Jakob Wakeling 2024-07-06 23:32:05
118
		if err != nil {
a0ac27c Jakob Wakeling 2024-07-06 23:32:05
119
			util.PrintFuncError(err)
a0ac27c Jakob Wakeling 2024-07-06 23:32:05
120
			goit.HttpError(w, http.StatusInternalServerError)
a0ac27c Jakob Wakeling 2024-07-06 23:32:05
121
			return
a0ac27c Jakob Wakeling 2024-07-06 23:32:05
122
		}
a0ac27c Jakob Wakeling 2024-07-06 23:32:05
123
		defer rc.Close()
a0ac27c Jakob Wakeling 2024-07-06 23:32:05
124
a0ac27c Jakob Wakeling 2024-07-06 23:32:05
125
		buf := make([]byte, min(file.Size, (10*1024*1024)))
5aa454c Jakob Wakeling 2023-07-27 17:45:56
126
		if _, err := rc.Read(buf); err != nil {
a0ac27c Jakob Wakeling 2024-07-06 23:32:05
127
			util.PrintFuncError(err)
5aa454c Jakob Wakeling 2023-07-27 17:45:56
128
			goit.HttpError(w, http.StatusInternalServerError)
5aa454c Jakob Wakeling 2023-07-27 17:45:56
129
			return
5aa454c Jakob Wakeling 2023-07-27 17:45:56
130
		}
5aa454c Jakob Wakeling 2023-07-27 17:45:56
131
a0ac27c Jakob Wakeling 2024-07-06 23:32:05
132
		body, css, err := Highlight(file.Name, string(buf), false)
a0ac27c Jakob Wakeling 2024-07-06 23:32:05
133
		if err != nil {
a0ac27c Jakob Wakeling 2024-07-06 23:32:05
134
			util.PrintFuncError(err)
a0ac27c Jakob Wakeling 2024-07-06 23:32:05
135
			goit.HttpError(w, http.StatusInternalServerError)
a0ac27c Jakob Wakeling 2024-07-06 23:32:05
136
			return
5aa454c Jakob Wakeling 2023-07-27 17:45:56
137
		}
b4de626 Jakob Wakeling 2023-11-16 23:06:56
138
a0ac27c Jakob Wakeling 2024-07-06 23:32:05
139
		data.HtmlBody = template.HTML(body)
a0ac27c Jakob Wakeling 2024-07-06 23:32:05
140
		data.BodyCss = template.HTML("<style>" + css + "</style>")
a0ac27c Jakob Wakeling 2024-07-06 23:32:05
141
		data.Lines = strings.Split(string(buf), "\n")
a0ac27c Jakob Wakeling 2024-07-06 23:32:05
142
		data.IsText = true
5aa454c Jakob Wakeling 2023-07-27 17:45:56
143
	}
db4ceeb Jakob Wakeling 2023-11-30 23:38:18
144
db4ceeb Jakob Wakeling 2023-11-30 23:38:18
145
	data.LineC = fmt.Sprint(len(data.Lines), " lines")
5aa454c Jakob Wakeling 2023-07-27 17:45:56
146
5aa454c Jakob Wakeling 2023-07-27 17:45:56
147
	if err := goit.Tmpl.ExecuteTemplate(w, "repo/file", data); err != nil {
a0ac27c Jakob Wakeling 2024-07-06 23:32:05
148
		util.PrintFuncError(err)
5aa454c Jakob Wakeling 2023-07-27 17:45:56
149
	}
5aa454c Jakob Wakeling 2023-07-27 17:45:56
150
}
151