shroomgit

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

tree.go
1package main
2
3import (
4 "fmt"
5 "io"
6 "io/fs"
7 "log"
8 "os"
9 "path/filepath"
10 "strings"
11)
12
13// TODO make it more tree like
14func treeRepo(topPart string, repo string, output string) {
15 logsDir := filepath.Join(output, "files")
16
17 err := os.MkdirAll(logsDir, 0o755)
18 if err != nil {
19 panic(err)
20 }
21
22 outputFile := filepath.Join(output, "tree.html")
23 file, err := os.Create(outputFile)
24 if err != nil {
25 log.Fatal(err)
26 }
27 defer file.Close()
28
29 file.WriteString(topPart)
30
31 file.WriteString("<table>\n")
32
33 file.WriteString("\n<tr>")
34 file.WriteString("<td>Mode</td>")
35 file.WriteString("<td>Bytes</td>")
36 file.WriteString("</tr>")
37
38 err = filepath.WalkDir(repo, func(path string, d fs.DirEntry, err error) error {
39 relPath, _ := filepath.Rel(repo, path)
40
41 if d.Name() == ".git" {
42 return filepath.SkipDir
43 } else if relPath == "." {
44 return nil
45 } else if d.IsDir() {
46 return nil
47 }
48 info, _ := d.Info()
49
50 file.WriteString("<tr>")
51 file.WriteString("<td>")
52 file.WriteString(info.Mode().String())
53 file.WriteString("&nbsp;</td>")
54 file.WriteString("<td valign=\"top\" align=\"right\">")
55 fmt.Fprintf(file, " %d", info.Size())
56 file.WriteString("</td>\n")
57 file.WriteString("<td>")
58 file.WriteString("<a href=\"files/")
59 file.WriteString(relPath)
60 file.WriteString(".html\">")
61 file.WriteString(relPath)
62 treeFiles(path, output, relPath, repo)
63 file.WriteString("</a>")
64 file.WriteString("</td>")
65
66 file.WriteString("</tr>")
67
68 return nil
69 })
70 if err != nil {
71 log.Fatal(err)
72 }
73
74 file.WriteString("</table>\n")
75
76 file.WriteString("</body>\n")
77 file.WriteString("</html>")
78}
79
80func treeFiles(path string, output string, relPath string, repo string) {
81 outputFile := filepath.Join(output, "files", fmt.Sprintf("%s.html", relPath))
82 os.MkdirAll(filepath.Dir(outputFile), 0o755)
83 file, _ := os.Create(outputFile)
84 defer file.Close()
85
86 depth := strings.Count(relPath, "/")
87 topPart := genTopPart(repo, depth+1)
88 file.WriteString(topPart)
89
90 // TODO handle binaries better
91 ex := filepath.Ext(path)
92 if ex == ".png" || ex == ".jpg" || ex == ".webp" || ex == ".jpeg" {
93 outputFile = filepath.Join(output, "media", relPath)
94 os.MkdirAll(filepath.Dir(outputFile), 0o755)
95
96 err := copyFile(path, outputFile)
97 if err != nil {
98 panic(err)
99 }
100
101 file.WriteString("\n<img src=\"")
102 depth += 1
103 for range depth {
104 file.WriteString("../")
105 }
106
107 file.WriteString("media/" + relPath + "\">")
108 return
109 }
110
111 writePerFile(file, path)
112}
113
114func copyFile(src, dst string) error {
115 if err := os.MkdirAll(filepath.Dir(dst), 0o755); err != nil {
116 return err
117 }
118
119 in, err := os.Open(src)
120 if err != nil {
121 return err
122 }
123 defer in.Close()
124
125 out, err := os.Create(dst)
126 if err != nil {
127 return err
128 }
129 defer out.Close()
130
131 _, err = io.Copy(out, in)
132 if err != nil {
133 return err
134 }
135
136 return out.Sync()
137}