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:
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")
+}