shroomgit

static git repos page gen
Log | Files | Refs | README

commit 059e266936ebd5c5bba709b72bb38efad829d6e9
Author: David Voznyarskiy <davidv@no-reply@disroot.org>
Date:   Fri, 20 Mar 2026 22:44:10 -0700

init commit

Signed-off-by: David Voznyarskiy <davidv@no-reply@disroot.org>

Diffstat:
A.gitignore | 1+
AMakefile | 14++++++++++++++
Aconfig/config.go | 26++++++++++++++++++++++++++
Ago.mod | 3+++
Ashgit/shgit.go | 8++++++++
Ashindex/shindex.go | 157+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
6 files changed, 209 insertions(+), 0 deletions(-)

diff --git a/.gitignore b/.gitignore @@ -0,0 +1 @@ +bin diff --git a/Makefile b/Makefile @@ -0,0 +1,14 @@ +.PHONY: all shindex shgit clean + +all: shindex shgit + +shindex: + @mkdir -p bin + go build -o bin/shindex shindex/shindex.go + +shgit: + @mkdir -p bin + go build -o bin/shgit shgit/shgit.go + +clean: + rm -rf bin diff --git a/config/config.go b/config/config.go @@ -0,0 +1,26 @@ +package config + +type Config struct { + Title string + Favicon string + Logo string + LogoHref string + LogoWidth int + LogoHeight int + Desc string +} + +// shindex config +var Shindex = Config{ + Title: "Repositories", + Logo: "logo.png", + LogoHref: "https://git.davidvoz.net", + LogoWidth: 88, + LogoHeight: 36, + Desc: "this is a static index of my repos, for more visit <a href='https://git.disroot.org/davidv'>here</a>", +} + +// shgit config +var Shgit = Config{ + Favicon: "favicon.png", +} diff --git a/go.mod b/go.mod @@ -0,0 +1,3 @@ +module shroomgit + +go 1.24.13 diff --git a/shgit/shgit.go b/shgit/shgit.go @@ -0,0 +1,8 @@ +package main + +import "fmt" + +func main() { + fmt.Println("shgit here") + fmt.Println("work in progress") +} diff --git a/shindex/shindex.go b/shindex/shindex.go @@ -0,0 +1,157 @@ +package main + +import ( + "fmt" + "os" + "os/exec" + "path/filepath" + "strings" + + "shroomgit/config" +) + +func main() { + args := os.Args[1:] + + if len(args) == 0 { + fmt.Println("ERROR not enough arguments") + printHelp() + os.Exit(1) + } + + basicPart() + gitTable(args) + fmt.Println("\n</body>") + fmt.Print("</html>") +} + +func gitTable(args []string) { + fmt.Println("<div style=\"display:flex; flex-wrap:wrap; gap;9px;\">") + + for _, repo := range args { + repoName := getRepoName(repo) + cmd := exec.Command( + "git", + "-C", repo, + "log", "-1", + "--pretty=format:%cd", + "--date=format:%Y-%m-%d", + ) + descFile := filepath.Join(repo, ".git", "description") + desc := "" + if data, err := os.ReadFile(descFile); err == nil { + desc = string(data) + } + lastCommit, _ := cmd.Output() + license := detectLicense(repo) + + fmt.Println("\n<div style=\"width:400px;\">") + fmt.Println("<div style=\"display:flex;padding:5px;\">") + fmt.Println("<div style=\"width:32px;height:32px;margin-right:8px;\">") + + // the line below assumes the directory path is the same as the repo's name, not arguments + // change the 'repoName' to 'repo' if you want the latter option + fmt.Printf("<a href=\"%s/log.html\" style=\"color:inherit\">", repoName) + + fmt.Println("<svg width=\"32\" height=\"32\">") + fmt.Println("<rect x=\"6\" y=\"10\" width=\"20\" height=\"20\"") + fmt.Println("fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" transform=\"rotate(45 20 20)\"/></svg></a></div><div>") + + // other instance of possible path argument issue + fmt.Printf("<a href=\"%s/log.html\" style=\"line-height:1.5;\">", repoName) + + fmt.Printf("<b>%s", repoName) + fmt.Printf("</b></a><br>%s", desc) + fmt.Printf("<br><br>%s", string(lastCommit)) + if license != "0" { + fmt.Printf(" - %s", license) + } + + fmt.Println("</div></div></div>") + } + + fmt.Println("</div>") +} + +func basicPart() { + config := config.Shindex + fmt.Println("<!DOCTYPE html>") + fmt.Println("<html>") + fmt.Println("<head>") + fmt.Printf("<title>%s</title>\n", config.Title) + fmt.Println("<link rel=\"stylesheet\" href=\"style.css\" \\>") + fmt.Println("<link rel=\"icon\" type=\"image/png\" href=\"favicon.png\" \\>") + fmt.Println("</head>\n") + fmt.Println("<body>") + fmt.Println("<table>") + fmt.Printf("<tr><td><a href=\"%s\">", config.LogoHref) + fmt.Printf("<img src=\"%s\" ", config.Logo) + fmt.Printf("alt=\"\" width=%d ", config.LogoWidth) + fmt.Printf("height=%d ", config.LogoHeight) + fmt.Print("/></a></td>\n") + fmt.Printf("<td>%s", config.Title) + fmt.Println("</td></tr>") + fmt.Println("</table>") + fmt.Println(config.Desc) + fmt.Println("<hr>") +} + +func getRepoName(repo string) string { + gitConfig := filepath.Join(repo, ".git", "config") + data, err := os.ReadFile(gitConfig) + if err != nil { + return filepath.Base(repo) + } + + content := string(data) + + for _, line := range strings.Split(content, "\n") { + line = strings.TrimSpace(line) + if strings.HasPrefix(line, "url =") { + parts := strings.Fields(line) + url := parts[2] + url = strings.TrimSuffix(url, ".git") + segments := strings.Split(url, "/") + return segments[len(segments)-1] + } + } + + return filepath.Base(repo) +} + +// Not very reliable, will fix later +func detectLicense(repo string) string { + files := []string{"LICENSE", "LICENSE.txt", "LICENSE.md", "license"} + + for _, f := range files { + path := filepath.Join(repo, f) + data, _ := os.ReadFile(path) + + text := string(data) + + switch { + case strings.Contains(text, "MIT License"): + return "MIT" + case strings.Contains(text, "Apache"): + return "Apache" + case strings.Contains(text, "GNU General"): + return "GPL" + case strings.Contains(text, "unlicense"): + return "unlicense" + case strings.Contains(text, "Mozilla"): + return "MPL" + case strings.Contains(text, "Creative Commons"): + return "CC" + case strings.Contains(text, "0BSD"), strings.Contains(text, "BSD-"): + return "BSD" + case strings.Contains(text, "license"): + return "other" + } + } + + return "0" +} + +func printHelp() { + fmt.Println("read source code for now") +}