depp

No frills static page generator for Git repositories

git clone https://git.8pit.net/depp.git

  1package main
  2
  3import (
  4	"embed"
  5	"flag"
  6	"fmt"
  7	"html/template"
  8	"log"
  9	"os"
 10	"path/filepath"
 11	"sort"
 12	"time"
 13
 14	"github.com/nmeum/depp/css"
 15	"github.com/nmeum/depp/gitweb"
 16)
 17
 18type Repo struct {
 19	Name     string
 20	Title    string
 21	Desc     string
 22	Modified time.Time
 23}
 24
 25type Page struct {
 26	Title string
 27	Desc  string
 28	Repos []Repo
 29}
 30
 31//go:embed tmpl
 32var templates embed.FS
 33
 34var (
 35	desc  = flag.String("s", "", "short description of git host")
 36	title = flag.String("t", "depp-index", "page title")
 37	dest  = flag.String("d", "./www", "output directory for HTML files")
 38	strip = flag.Bool("x", false, "strip .git extension from repository name in link")
 39)
 40
 41func usage() {
 42	fmt.Fprintf(flag.CommandLine.Output(),
 43		"USAGE: %s [FLAGS] REPOSITORY...\n\n"+
 44			"The following flags are supported:\n\n", os.Args[0])
 45
 46	flag.PrintDefaults()
 47	os.Exit(2)
 48}
 49
 50func repoLink(repo *Repo) string {
 51	if *strip {
 52		// Return a post-processed repository name without .git
 53		return repo.Title
 54	} else {
 55		// Return the raw file name, potentially including .git
 56		return repo.Name
 57	}
 58}
 59
 60func createHTML(page Page, path string) error {
 61	const name = "base.tmpl"
 62
 63	html := template.New(name)
 64	html.Funcs(template.FuncMap{
 65		"repoLink": repoLink,
 66	})
 67
 68	tmpl, err := html.ParseFS(templates, "tmpl/*.tmpl")
 69	if err != nil {
 70		return err
 71	}
 72
 73	file, err := os.Create(path)
 74	if err != nil {
 75		return err
 76	}
 77	defer file.Close()
 78
 79	err = tmpl.Execute(file, page)
 80	if err != nil {
 81		return err
 82	}
 83
 84	return nil
 85}
 86
 87func getRepos(fps []string) ([]Repo, error) {
 88	repos := make([]Repo, len(fps))
 89	for i, fp := range fps {
 90		r, err := gitweb.NewRepo(fp, nil, 0)
 91		if err != nil {
 92			return []Repo{}, err
 93		}
 94
 95		commit, err := r.Tip()
 96		if err != nil {
 97			return []Repo{}, err
 98		}
 99		desc, err := r.Description()
100		if err != nil {
101			return []Repo{}, err
102		}
103
104		sig := commit.Committer()
105		repos[i] = Repo{
106			Name:     filepath.Base(fp),
107			Title:    r.Title,
108			Desc:     desc,
109			Modified: sig.When,
110		}
111	}
112
113	sort.Sort(byModified(repos))
114	return repos, nil
115}
116
117func main() {
118	flag.Usage = usage
119	flag.Parse()
120
121	log.SetFlags(log.Lshortfile)
122	if flag.NArg() == 0 {
123		usage()
124	}
125
126	repos, err := getRepos(flag.Args())
127	if err != nil {
128		log.Fatal(err)
129	}
130
131	page := Page{
132		Title: *title,
133		Desc:  *desc,
134		Repos: repos,
135	}
136
137	err = os.MkdirAll(*dest, 0755)
138	if err != nil {
139		log.Fatal(err)
140	}
141
142	err = css.Create(filepath.Join(*dest, "style.css"))
143	if err != nil {
144		log.Fatal(err)
145	}
146	err = createHTML(page, filepath.Join(*dest, "index.html"))
147	if err != nil {
148		log.Fatal(err)
149	}
150}