Migration This is my new public git source viewer. Source coming soon. Please contact with concerns/bugs. Contact me

main.go

c0427d5fc7c0fcf8606c546071085e8af231fb81 · 2.5 KB · 94 lines raw

1 // Command gsg serves a modular git browser.
2 //
3 // gsg -root /srv/git -addr :8080 -name "rschanz.org"
4 // gsg -root /srv/git -templates ./templates # hot-reload the theme
5 //
6 // Per-repository settings live in each repo's own git config, cgit-style:
7 //
8 // git --git-dir=/srv/git/foo.git config gsg.title "foo"
9 // git --git-dir=/srv/git/foo.git config gsg.description "a thing"
10 // git --git-dir=/srv/git/foo.git config gsg.hide true
11 // git --git-dir=/srv/git/foo.git config gsg.gpgkeyring /srv/git/foo-keys.asc
12 package main
13
14 import (
15 "embed"
16 "flag"
17 "io/fs"
18 "log"
19 "log/slog"
20 "net/http"
21 "os"
22 "time"
23
24 "gsg/internal/core"
25 _ "gsg/internal/modules" // registers the built-in modules
26 "gsg/internal/site"
27 )
28
29 //go:embed templates
30 var templateFS embed.FS
31
32 //go:embed static
33 var staticFS embed.FS
34
35 func main() {
36 var (
37 root = flag.String("root", "/srv/git", "directory containing bare repositories")
38 addr = flag.String("addr", ":8080", "listen address")
39 name = flag.String("name", "git", "site name")
40 base = flag.String("base", "", "base URL")
41 tmplDir = flag.String("templates", "", "serve templates from this directory, re-parsed per request")
42 cache = flag.Int("cache", 4096, "module cache entries")
43 timeout = flag.Duration("timeout", 10*time.Second, "per-request git budget")
44 )
45 flag.Parse()
46
47 if err := run(*root, *addr, *name, *base, *tmplDir, *cache, *timeout); err != nil {
48 log.Fatalf("gsg: %v", err)
49 }
50 }
51
52 func run(root, addr, name, base, tmplDir string, cacheSize int, timeout time.Duration) error {
53 siteCfg := &core.Site{Name: name, BaseURL: base, Root: root}
54
55 if err := core.Start(siteCfg); err != nil {
56 return err
57 }
58
59 var tfs fs.FS
60 var err error
61 if tmplDir != "" {
62 tfs = os.DirFS(tmplDir)
63 } else if tfs, err = fs.Sub(templateFS, "templates"); err != nil {
64 return err
65 }
66
67 srv, err := core.NewServer(siteCfg, site.Routes(), tfs, cacheSize)
68 if err != nil {
69 return err
70 }
71 srv.TemplateDir = tmplDir
72 srv.Timeout = timeout
73
74 static, err := fs.Sub(staticFS, "static")
75 if err != nil {
76 return err
77 }
78
79 mux := http.NewServeMux()
80 mux.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.FS(static))))
81 mux.Handle("/", srv.Handler())
82
83 slog.Info("gsg listening",
84 "addr", addr, "repos", len(siteCfg.RepoList()),
85 "routes", len(site.Routes()), "modules", len(core.Names()))
86
87 hs := &http.Server{
88 Addr: addr,
89 Handler: mux,
90 ReadHeaderTimeout: 5 * time.Second,
91 WriteTimeout: timeout + 5*time.Second,
92 }
93 return hs.ListenAndServe()
94 }