shroomgit

generate static pages of git repos
git clone https://git.davidvoz.net/shroomgit.git
index
logs
tree
license

shared.go
1package main
2
3import (
4 "bufio"
5 "html"
6 "os"
7 "path/filepath"
8 "strconv"
9 "strings"
10)
11
12// prints an html section for each file inputted
13// TODO maybe see if you can add pandoc program coloring theme to it
14func writePerFile(file *os.File, path string) {
15 notFile, _ := os.Open(path)
16 defer notFile.Close()
17
18 scanner := bufio.NewScanner(notFile)
19 numLine := 1
20 var strNumLine string
21
22 fileName := filepath.Base(path)
23 file.WriteString("<b>" + fileName + "</b>")
24
25 file.WriteString("\n<table style=\"white-space:pre\">")
26 for scanner.Scan() {
27 line := scanner.Text()
28 escaped := html.EscapeString(line)
29 strNumLine = strconv.Itoa(numLine)
30
31 file.WriteString("<tr>")
32 file.WriteString("<td class=\"codeline\">")
33 file.WriteString("<a href=\"#" + strNumLine + "\" id=\"" + strNumLine + "\">")
34 file.WriteString(strNumLine)
35 file.WriteString("</a>")
36 file.WriteString("</td>")
37 file.WriteString("<td>")
38 file.WriteString(escaped + "\n")
39 file.WriteString("</td>")
40
41 file.WriteString("</tr>")
42
43 numLine++
44 }
45 file.WriteString("</table>")
46 file.WriteString("<br>")
47}
48
49// the common HTML lines that all files will share
50var genTopPart = func(repo string, depth int) string {
51 var b strings.Builder
52 config := shgit
53 repoName, desc := getRepoNameAndDesc(repo)
54
55 b.WriteString("<!DOCTYPE html>\n")
56 b.WriteString("<html>\n")
57 b.WriteString("<head>\n")
58 b.WriteString("<link rel=\"stylesheet\" href=\"")
59 for range depth {
60 b.WriteString("../")
61 }
62 b.WriteString("style.css\" \\>\n")
63 b.WriteString("<link rel=\"icon\" type=\"image/png\" href=\"")
64 for range depth {
65 b.WriteString("../")
66 }
67 b.WriteString(config.favicon)
68 b.WriteString("\" \\>\n")
69
70 b.WriteString("<style>")
71 b.WriteString(styles["codeline"])
72 b.WriteString("\n</style>\n")
73
74 b.WriteString("</head>\n")
75
76 b.WriteString("<body>\n")
77
78 b.WriteString("<table>")
79 b.WriteString("<tr>\n")
80
81 if config.logo != "" {
82 b.WriteString("<td>")
83 b.WriteString("<a href=\"")
84 for range depth {
85 b.WriteString("../")
86 }
87
88 b.WriteString(config.logoHref)
89
90 b.WriteString("\">")
91
92 b.WriteString("<img src=\"")
93 for range depth {
94 b.WriteString("../")
95 }
96
97 b.WriteString(config.logo)
98 b.WriteString("\" width=")
99 b.WriteString(strconv.Itoa(config.logoWidth))
100 b.WriteString(" height=")
101 b.WriteString(strconv.Itoa(config.logoHeight))
102 b.WriteString("/>")
103 b.WriteString("</a>")
104 b.WriteString("</td>")
105 }
106
107 b.WriteString("\n<td><h2 style=\"margin-left:10px\">")
108 b.WriteString(repoName)
109 b.WriteString("</h2>")
110
111 b.WriteString("</td>")
112
113 b.WriteString("</tr>")
114 b.WriteString("</table>")
115 b.WriteString(desc)
116
117 b.WriteString("<hr>")
118
119 if config.url != "" {
120 b.WriteString("<table>\n")
121 b.WriteString("<tr>\n<td>\n<code style=\"background-color: #222; padding: 4px; user-select: all; border: none;\">")
122 b.WriteString("git clone " + config.url + repoName + ".git")
123 b.WriteString("</code></td>")
124
125 b.WriteString("</tr>\n")
126 b.WriteString("</table>")
127 }
128
129 b.WriteString("\n<div style=\"display:flex; flex-wrap:wrap; gap:30px;margin-top:3px;\">\n")
130
131 b.WriteString("\n<div style=\"display:flex;padding-left:20px;\">\n")
132 b.WriteString("<a href=\"")
133 for range depth {
134 b.WriteString("../")
135 }
136 b.WriteString("index.html\">")
137 b.WriteString("index\n")
138 b.WriteString("</a>")
139 b.WriteString("</div>\n")
140
141 b.WriteString("\n<div style=\"display:flex;\">\n")
142 b.WriteString("<a href=\"")
143 for range depth {
144 b.WriteString("../")
145 }
146 b.WriteString("log.html\">")
147 b.WriteString("logs\n")
148 b.WriteString("</a>")
149 b.WriteString("</div>\n")
150
151 b.WriteString("\n<div style=\"display:flex;\">\n")
152 b.WriteString("<a href=\"")
153 for range depth {
154 b.WriteString("../")
155 }
156 b.WriteString("tree.html\">")
157 b.WriteString("tree\n")
158 b.WriteString("</a>")
159 b.WriteString("</div>\n")
160
161 files := []string{"LICENSE", "LICENSE.txt", "LICENSE.md", "license", "license.txt", "COPYING", "copying"}
162
163 for _, f := range files {
164 possibleL := filepath.Join(repo, f)
165 if _, err := os.ReadFile(possibleL); err == nil {
166 b.WriteString("\n<div style=\"display:flex;\">\n")
167 b.WriteString("<a href=\"")
168 for range depth {
169 b.WriteString("../")
170 }
171 b.WriteString("files/")
172 b.WriteString(filepath.Base(possibleL))
173 b.WriteString(".html\">")
174 b.WriteString("license\n")
175 b.WriteString("</a>")
176 b.WriteString("</div>\n")
177 break
178 }
179 }
180
181 b.WriteString("\n</div>\n")
182
183 b.WriteString("<hr>")
184
185 return b.String()
186}
187
188func getRepoNameAndDesc(repo string) (string, string) {
189 descFile := filepath.Join(repo, ".git", "description")
190 desc := ""
191 if data, err := os.ReadFile(descFile); err == nil {
192 desc = string(data)
193 }
194
195 gitConfig := filepath.Join(repo, ".git", "config")
196 data, err := os.ReadFile(gitConfig)
197 if err != nil {
198 return filepath.Base(repo), desc
199 }
200
201 content := string(data)
202
203 for line := range strings.SplitSeq(content, "\n") {
204 line = strings.TrimSpace(line)
205 if strings.HasPrefix(line, "url =") {
206 parts := strings.Fields(line)
207 if len(parts) < 3 {
208 continue
209 }
210 url := parts[2]
211 url = strings.TrimSuffix(url, ".git")
212 segments := strings.Split(url, "/")
213 return segments[len(segments)-1], desc
214 }
215 }
216
217 return filepath.Base(repo), desc
218}