1package main
2
3import (
4 "embed"
5 "flag"
6 "fmt"
7 "html/template"
8 "log"
9 "net/url"
10 "os"
11 "path/filepath"
12 "time"
13
14 "github.com/nmeum/depp/css"
15 "github.com/nmeum/depp/gitweb"
16)
17
18//go:embed tmpl
19var templates embed.FS
20
21var (
22 commits = flag.Uint("c", 5, "amount of recent commits to include")
23 gitURL = flag.String("u", "", "clone URL for the Git repository")
24 destination = flag.String("d", "./www", "output directory for HTML files")
25)
26
27var tmpl *template.Template
28
29func usage() {
30 fmt.Fprintf(flag.CommandLine.Output(),
31 "USAGE: %s [FLAGS] REPOSITORY\n\n"+
32 "The following flags are supported:\n\n", os.Args[0])
33
34 flag.PrintDefaults()
35 os.Exit(2)
36}
37
38func walkPages(page *gitweb.RepoPage) error {
39 name := page.CurrentFile.Path
40 if isIndexPage(page) {
41 name = "index"
42 }
43
44 fp := filepath.Join(*destination, name+".html")
45 err := os.MkdirAll(filepath.Dir(fp), 0755)
46 if err != nil {
47 return err
48 }
49 file, err := os.Create(fp)
50 if err != nil {
51 return err
52 }
53 defer file.Close()
54
55 err = tmpl.Execute(file, page)
56 if err != nil {
57 return err
58 }
59
60 return nil
61}
62
63func buildHTML() (*template.Template, error) {
64 var err error
65
66 const name = "base.tmpl"
67 tmpl := template.New(name)
68
69 funcMap := template.FuncMap{
70 "isBinary": isBinary,
71 "getRelPath": getRelPath,
72 "increment": increment,
73 "decrement": decrement,
74 "getLines": getLines,
75 "padNumber": padNumber,
76 "relIndex": relIndex,
77 "isIndexPage": isIndexPage,
78 "renderReadme": renderReadme,
79 }
80 tmpl = tmpl.Funcs(funcMap)
81
82 tmpl, err = tmpl.ParseFS(templates, "tmpl/*.tmpl")
83 if err != nil {
84 return nil, err
85 }
86
87 return tmpl, nil
88}
89
90func generate(repo *gitweb.Repo) error {
91 var err error
92 tmpl, err = buildHTML()
93 if err != nil {
94 return err
95 }
96 err = repo.Walk(walkPages)
97 if err != nil {
98 return err
99 }
100
101 err = css.Create(filepath.Join(*destination, "style.css"))
102 if err != nil {
103 return err
104 }
105
106 return nil
107}
108
109func main() {
110 // Time **before** start of file generation.
111 // Will later be used as the mtime/atime of `index.html`.
112 startTime := time.Now().Add(-1 * time.Second)
113
114 flag.Usage = usage
115 flag.Parse()
116
117 log.SetFlags(log.Lshortfile)
118 if flag.NArg() != 1 {
119 usage()
120 }
121
122 gitURL, err := url.Parse(*gitURL)
123 if err != nil {
124 log.Fatal(err)
125 }
126
127 path := flag.Arg(0)
128 repo, err := gitweb.NewRepo(path, gitURL, *commits)
129 if err != nil {
130 log.Fatal(err)
131 }
132 err = generate(repo)
133 if err != nil {
134 log.Fatal(err)
135 }
136
137 // Reset mtime/atime of index.html to detect untouched files.
138 index := filepath.Join(*destination, "index.html")
139 err = os.Chtimes(index, startTime, startTime)
140 if err != nil {
141 log.Fatal(err)
142 }
143}