| 1 | package main
|
| 2 |
|
| 3 | import (
|
| 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
|
| 14 | func 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
|
| 50 | var 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("</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 | b.WriteString("<table>\n")
|
| 119 |
|
| 120 | b.WriteString("<tr>\n<td>\n<code style=\"background-color: #222; color: white; padding: 4px; user-select: all; border: none;\">")
|
| 121 | b.WriteString("git clone " + config.url + repoName + ".git")
|
| 122 | b.WriteString("\n</code></td>")
|
| 123 |
|
| 124 | b.WriteString("</tr>\n")
|
| 125 | b.WriteString("</table>")
|
| 126 |
|
| 127 | b.WriteString("\n<div style=\"display:flex; flex-wrap:wrap; gap:30px;margin-top:3px;\">\n")
|
| 128 |
|
| 129 | b.WriteString("\n<div style=\"display:flex;padding-left:20px;\">\n")
|
| 130 | b.WriteString("<a href=\"")
|
| 131 | for range depth {
|
| 132 | b.WriteString("../")
|
| 133 | }
|
| 134 | b.WriteString("index.html\">")
|
| 135 | b.WriteString("index\n")
|
| 136 | b.WriteString("</a>")
|
| 137 | b.WriteString("</div>\n")
|
| 138 |
|
| 139 | b.WriteString("\n<div style=\"display:flex;\">\n")
|
| 140 | b.WriteString("<a href=\"")
|
| 141 | for range depth {
|
| 142 | b.WriteString("../")
|
| 143 | }
|
| 144 | b.WriteString("log.html\">")
|
| 145 | b.WriteString("logs\n")
|
| 146 | b.WriteString("</a>")
|
| 147 | b.WriteString("</div>\n")
|
| 148 |
|
| 149 | b.WriteString("\n<div style=\"display:flex;\">\n")
|
| 150 | b.WriteString("<a href=\"")
|
| 151 | for range depth {
|
| 152 | b.WriteString("../")
|
| 153 | }
|
| 154 | b.WriteString("tree.html\">")
|
| 155 | b.WriteString("tree\n")
|
| 156 | b.WriteString("</a>")
|
| 157 | b.WriteString("</div>\n")
|
| 158 |
|
| 159 | files := []string{"LICENSE", "LICENSE.txt", "LICENSE.md", "license", "COPYING"}
|
| 160 |
|
| 161 | for _, f := range files {
|
| 162 | possibleL := filepath.Join(repo, f)
|
| 163 | if _, err := os.ReadFile(possibleL); err == nil {
|
| 164 | b.WriteString("\n<div style=\"display:flex;\">\n")
|
| 165 | b.WriteString("<a href=\"")
|
| 166 | for range depth {
|
| 167 | b.WriteString("../")
|
| 168 | }
|
| 169 | b.WriteString("files/")
|
| 170 | b.WriteString(filepath.Base(possibleL))
|
| 171 | b.WriteString(".html\">")
|
| 172 | b.WriteString("license\n")
|
| 173 | b.WriteString("</a>")
|
| 174 | b.WriteString("</div>\n")
|
| 175 | break
|
| 176 | }
|
| 177 | }
|
| 178 |
|
| 179 | b.WriteString("\n</div>\n")
|
| 180 |
|
| 181 | b.WriteString("<hr>")
|
| 182 |
|
| 183 | return b.String()
|
| 184 | }
|
| 185 |
|
| 186 | func getRepoNameAndDesc(repo string) (string, string) {
|
| 187 | descFile := filepath.Join(repo, ".git", "description")
|
| 188 | desc := ""
|
| 189 | if data, err := os.ReadFile(descFile); err == nil {
|
| 190 | desc = string(data)
|
| 191 | }
|
| 192 |
|
| 193 | gitConfig := filepath.Join(repo, ".git", "config")
|
| 194 | data, err := os.ReadFile(gitConfig)
|
| 195 | if err != nil {
|
| 196 | return filepath.Base(repo), desc
|
| 197 | }
|
| 198 |
|
| 199 | content := string(data)
|
| 200 |
|
| 201 | for line := range strings.SplitSeq(content, "\n") {
|
| 202 | line = strings.TrimSpace(line)
|
| 203 | if strings.HasPrefix(line, "url =") {
|
| 204 | parts := strings.Fields(line)
|
| 205 | if len(parts) < 3 {
|
| 206 | continue
|
| 207 | }
|
| 208 | url := parts[2]
|
| 209 | url = strings.TrimSuffix(url, ".git")
|
| 210 | segments := strings.Split(url, "/")
|
| 211 | return segments[len(segments)-1], desc
|
| 212 | }
|
| 213 | }
|
| 214 |
|
| 215 | return filepath.Base(repo), desc
|
| 216 | }
|
| 217 |
|