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}