main
1package index
2
3import (
4 "embed"
5 "fmt"
6 "html/template"
7 "os"
8 "path/filepath"
9
10 "forge/internal/repo"
11)
12
13//go:embed templates/root.html templates/category.html
14var templateFS embed.FS
15
16var (
17 rootTmpl = template.Must(template.ParseFS(templateFS, "templates/root.html"))
18 categoryTmpl = template.Must(template.ParseFS(templateFS, "templates/category.html"))
19)
20
21type rootData struct {
22 Categories []rootCategory
23}
24
25type rootCategory struct {
26 Name string
27 Repos []rootRepo
28}
29
30type rootRepo struct {
31 Name string
32 Category string
33}
34
35type categoryData struct {
36 Category string
37 Repos []repoEntry
38}
39
40type repoEntry struct {
41 Name string
42}
43
44// GenerateAll creates index.html files for the root and each category
45// directory under outputRoot.
46func GenerateAll(outputRoot string, repos []repo.Repo) error {
47 grouped := make(map[string][]repo.Repo)
48 var categoryOrder []string
49 seen := make(map[string]bool)
50
51 for _, r := range repos {
52 if !seen[r.Category] {
53 seen[r.Category] = true
54 categoryOrder = append(categoryOrder, r.Category)
55 }
56 grouped[r.Category] = append(grouped[r.Category], r)
57 }
58
59 // Generate root index.
60 rd := rootData{}
61 for _, cat := range categoryOrder {
62 rc := rootCategory{Name: cat}
63 for _, r := range grouped[cat] {
64 rc.Repos = append(rc.Repos, rootRepo{Name: r.Name, Category: r.Category})
65 }
66 rd.Categories = append(rd.Categories, rc)
67 }
68
69 err := writeTemplate(rootTmpl, filepath.Join(outputRoot, "index.html"), rd)
70 if err != nil {
71 return fmt.Errorf("generating root index: %w", err)
72 }
73
74 // Generate per-category indexes.
75 for _, cat := range categoryOrder {
76 cd := categoryData{Category: cat}
77 for _, r := range grouped[cat] {
78 cd.Repos = append(cd.Repos, repoEntry{Name: r.Name})
79 }
80
81 catDir := filepath.Join(outputRoot, cat)
82 err := os.MkdirAll(catDir, 0o755)
83 if err != nil {
84 return fmt.Errorf("creating category dir (category=%s): %w", cat, err)
85 }
86
87 err = writeTemplate(categoryTmpl, filepath.Join(catDir, "index.html"), cd)
88 if err != nil {
89 return fmt.Errorf("generating category index (category=%s): %w", cat, err)
90 }
91 }
92
93 return nil
94}
95
96func writeTemplate(tmpl *template.Template, path string, data any) error {
97 err := os.MkdirAll(filepath.Dir(path), 0o755)
98 if err != nil {
99 return fmt.Errorf("creating output dir (path=%s): %w", path, err)
100 }
101
102 f, err := os.Create(path)
103 if err != nil {
104 return fmt.Errorf("creating file (path=%s): %w", path, err)
105 }
106 defer f.Close()
107
108 err = tmpl.Execute(f, data)
109 if err != nil {
110 return fmt.Errorf("executing template (path=%s): %w", path, err)
111 }
112 return nil
113}