Skip to content

Commit 7c20f31

Browse files
committed
catalogsite: checkpoint of a (skeletal) catalog html generator.
Containing copious hacks in the "test". Not production-ready. But still I still may want to merge this just to move forward. The exact filesystem layout may be subject to change. This is a rebase of an old prototype (from before warpforge v0.2); the exact filesystem I'd like to use nowaday should more closely mirror the paths of the catalog filesystem projection in JSON, just with different extensions (which is not what we have here). Everything else _also_ subject to change :) There's no styling, etc. Future work includes turning this into a real CLI command; giving it parameters for which catalog(s?) to generate content from; teaching it to render and link up certain pieces of metadata (especially, right now, Replays); and probably a lot more.
1 parent f2eb65a commit 7c20f31

2 files changed

Lines changed: 216 additions & 0 deletions

File tree

pkg/cataloghtml/cataloghtml.go

Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,180 @@
1+
package cataloghtml
2+
3+
import (
4+
"context"
5+
"html/template"
6+
"os"
7+
"path"
8+
"path/filepath"
9+
"reflect"
10+
11+
"github.com/warpfork/warpforge/pkg/workspace"
12+
"github.com/warpfork/warpforge/wfapi"
13+
)
14+
15+
type SiteConfig struct {
16+
Ctx context.Context
17+
18+
// Data Access Broker for getting Catalog info.
19+
// Some functions pass around data in memory,
20+
// but sometimes those objects just contain CIDs, which we'll need to go load.
21+
// This has helper functions that do the loading.
22+
// Arguably should be a parameter, but would end up in almost every single function, so, eh.
23+
Cat_dab workspace.Catalog
24+
25+
// A plain string for output path prefix is used because golang still lacks
26+
// an interface for filesystem *writing* -- io/fs is only reading. Sigh.
27+
OutputPath string
28+
29+
// Set to "/" if you'll be publishing at the root of a subdomain.
30+
URLPrefix string
31+
}
32+
33+
func (cfg SiteConfig) tfuncs() map[string]interface{} {
34+
return map[string]interface{}{
35+
"string": func(x interface{}) string { // golang would you please shut the fuck up and let me be productive, honestly
36+
// this is for things that are literally typedefs of string but the template package isn't smart enough to be calm about unboxing it.
37+
return reflect.ValueOf(x).String()
38+
},
39+
"url": func(parts ...string) string {
40+
return path.Join(append([]string{cfg.URLPrefix}, parts...)...)
41+
},
42+
}
43+
}
44+
45+
func (cfg SiteConfig) CatalogAndChildrenToHtml() error {
46+
if err := cfg.CatalogToHtml(); err != nil {
47+
return err
48+
}
49+
modNames := cfg.Cat_dab.Modules()
50+
for _, modName := range modNames {
51+
catMod, err := cfg.Cat_dab.GetModule(wfapi.CatalogRef{modName, "", ""})
52+
if err != nil {
53+
return err
54+
}
55+
if err := cfg.CatalogModuleAndChildrenToHtml(*catMod); err != nil {
56+
return err
57+
}
58+
}
59+
return nil
60+
}
61+
62+
// CatalogToHtml generates a root page that links to all the modules.
63+
//
64+
// This function has no parameters because it uses the DAB in the SiteConfig entirely.
65+
func (cfg SiteConfig) CatalogToHtml() error {
66+
// Future: It's perhaps a bit odd that this uses the workspace.Catalog object instead of the API object. We probably haven't hammered out appropriate data access helpers yet.
67+
if err := os.MkdirAll(cfg.OutputPath, 0775); err != nil {
68+
return err
69+
}
70+
f, err := os.OpenFile(filepath.Join(cfg.OutputPath, "index.html"), os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0664)
71+
if err != nil {
72+
return err
73+
}
74+
defer f.Close()
75+
76+
// TODO: it's completely bork that we don't have access to the CIDs here. workspace.Catalog is Not Good right now.
77+
// TODO: this probably needs sorting to be stable.
78+
// Future: we should have a CID of the entire catalog tree root snapshot somewhere, too. (It should probably use prolly trees or something, though, which is not available as a convenient library yet.)
79+
t := template.Must(template.New("main").Funcs(cfg.tfuncs()).Parse(`
80+
<html>
81+
<div style="border: 1px solid; padding 0.5em;">
82+
<h1 style="display:inline">catalog</h1>
83+
</div>
84+
<h2>modules</h2>
85+
<ul>
86+
{{- range $moduleName := . }}
87+
<li><a href="{{ (url (string $moduleName) "index.html") }}">{{ $moduleName }}</a></li>
88+
{{- end }}
89+
</ul>
90+
</html>
91+
`))
92+
return t.Execute(f, cfg.Cat_dab.Modules())
93+
}
94+
95+
func (cfg SiteConfig) CatalogModuleAndChildrenToHtml(catMod wfapi.CatalogModule) error {
96+
if err := cfg.CatalogModuleToHtml(catMod); err != nil {
97+
return err
98+
}
99+
for _, releaseName := range catMod.Releases.Keys {
100+
rel, err := cfg.Cat_dab.GetRelease(wfapi.CatalogRef{catMod.Name, releaseName, ""})
101+
if err != nil {
102+
return err
103+
}
104+
if err := cfg.ReleaseToHtml(catMod, *rel); err != nil {
105+
return err
106+
}
107+
}
108+
return nil
109+
}
110+
111+
func (cfg SiteConfig) CatalogModuleToHtml(catMod wfapi.CatalogModule) error {
112+
if err := os.MkdirAll(filepath.Join(cfg.OutputPath, string(catMod.Name)), 0775); err != nil {
113+
return err
114+
}
115+
f, err := os.OpenFile(filepath.Join(cfg.OutputPath, string(catMod.Name), "index.html"), os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0664)
116+
if err != nil {
117+
return err
118+
}
119+
defer f.Close()
120+
121+
t := template.Must(template.New("main").Funcs(cfg.tfuncs()).Parse(`
122+
<html>
123+
<div style="border: 1px solid; padding 0.5em;">
124+
<i>module:</i>
125+
<h1 style="display:inline">{{ .Name }}</h1>
126+
</div>
127+
(<a href="{{ (url "index.html") }}">back to root</a>)
128+
<h2>releases</h2>
129+
<ul>
130+
{{- $dot := . -}}
131+
{{- range $releaseKey := .Releases.Keys }}
132+
<li><a href="{{ (url (string $dot.Name) (string $releaseKey) "index.html") }}">{{ $releaseKey }}</a> <small>(cid: {{ index $dot.Releases.Values $releaseKey }})</small></li>
133+
{{- end }}
134+
</ul>
135+
<h2>metadata</h2>
136+
{{- range $metadataKey := .Metadata.Keys }}
137+
<dt>{{ $metadataKey }}</dt><dd>{{ index $dot.Metadata.Values $metadataKey }}</dd>
138+
{{- end }}
139+
</html>
140+
`))
141+
return t.Execute(f, catMod)
142+
}
143+
144+
func (cfg SiteConfig) ReleaseToHtml(catMod wfapi.CatalogModule, rel wfapi.CatalogRelease) error {
145+
if err := os.MkdirAll(filepath.Join(cfg.OutputPath, string(catMod.Name), string(rel.ReleaseName)), 0775); err != nil {
146+
return err
147+
}
148+
f, err := os.OpenFile(filepath.Join(cfg.OutputPath, string(catMod.Name), string(rel.ReleaseName), "index.html"), os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0664)
149+
if err != nil {
150+
return err
151+
}
152+
defer f.Close()
153+
154+
t := template.Must(template.New("main").Funcs(cfg.tfuncs()).Parse(`
155+
<html>
156+
<div style="border: 1px solid; padding 0.5em;">
157+
<i>module:</i>
158+
<h1 style="display:inline">{{ .Module.Name }}</h1>
159+
<i>release:</i>
160+
<h1 style="display:inline">{{ .Release.ReleaseName }}</h1>
161+
</div>
162+
(<a href="{{ (url "index.html") }}">back to root</a>; <a href="{{ (url (string .Module.Name) "index.html") }}">back to module index</a>)
163+
<h2>items</h2>
164+
<ul>
165+
{{- $dot := .Release -}}
166+
{{- range $itemKey := .Release.Items.Keys }}
167+
<li>{{ $itemKey }} : {{ index $dot.Items.Values $itemKey }}</li>
168+
{{- end }}
169+
</ul>
170+
<h2>metadata</h2>
171+
{{- range $metadataKey := .Release.Metadata.Keys }}
172+
<dt>{{ $metadataKey }}</dt><dd>{{ index $dot.Metadata.Values $metadataKey }}</dd>
173+
{{- end }}
174+
</html>
175+
`))
176+
return t.Execute(f, map[string]interface{}{
177+
"Module": catMod,
178+
"Release": rel,
179+
})
180+
}

pkg/cataloghtml/demo_test.go

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package cataloghtml
2+
3+
import (
4+
"context"
5+
"os"
6+
"path/filepath"
7+
"testing"
8+
9+
"github.com/warpfork/warpforge/pkg/workspace"
10+
)
11+
12+
func TestWhee(t *testing.T) {
13+
// t.Skip("incomplete")
14+
homedir, err := os.UserHomeDir()
15+
if err != nil {
16+
panic(err)
17+
}
18+
// This is a very sketchy "live" "test" that assumes you've run `warpforge catalog update` before,
19+
// and operates (readonly!) on that real data.
20+
cat_dab, err := workspace.OpenCatalog(os.DirFS("/"), filepath.Join(homedir, ".warpforge/catalogs/warpsys")[1:])
21+
if err != nil {
22+
panic(err)
23+
}
24+
// Output paths are currently hardcoded and can be seen in the config object below.
25+
// No actual assertions take place on this; the "test" is manually looking at that output.
26+
cfg := SiteConfig{
27+
Ctx: context.Background(),
28+
Cat_dab: cat_dab,
29+
OutputPath: "/tmp/wf-test-cathtml/",
30+
URLPrefix: "/tmp/wf-test-cathtml/",
31+
}
32+
os.RemoveAll(cfg.OutputPath)
33+
if err := cfg.CatalogAndChildrenToHtml(); err != nil {
34+
panic(err)
35+
}
36+
}

0 commit comments

Comments
 (0)