diff --git a/pkg/cataloghtml/whee.go b/pkg/cataloghtml/whee.go new file mode 100644 index 00000000..c299596a --- /dev/null +++ b/pkg/cataloghtml/whee.go @@ -0,0 +1,180 @@ +package cataloghtml + +import ( + "context" + "html/template" + "os" + "path" + "path/filepath" + "reflect" + + "github.com/warpfork/warpforge/pkg/workspace" + "github.com/warpfork/warpforge/wfapi" +) + +type SiteConfig struct { + Ctx context.Context + + // Data Access Broker for getting Catalog info. + // Some functions pass around data in memory, + // but sometimes those objects just contain CIDs, which we'll need to go load. + // This has helper functions that do the loading. + // Arguably should be a parameter, but would end up in almost every single function, so, eh. + Cat_dab workspace.Catalog + + // A plain string for output path prefix is used because golang still lacks + // an interface for filesystem *writing* -- io/fs is only reading. Sigh. + OutputPath string + + // Set to "/" if you'll be publishing at the root of a subdomain. + URLPrefix string +} + +func (cfg SiteConfig) tfuncs() map[string]interface{} { + return map[string]interface{}{ + "string": func(x interface{}) string { // golang would you please shut the fuck up and let me be productive, honestly + // this is for things that are literally typedefs of string but the template package isn't smart enough to be calm about unboxing it. + return reflect.ValueOf(x).String() + }, + "url": func(parts ...string) string { + return path.Join(append([]string{cfg.URLPrefix}, parts...)...) + }, + } +} + +func (cfg SiteConfig) CatalogAndChildrenToHtml() error { + if err := cfg.CatalogToHtml(); err != nil { + return err + } + modNames := cfg.Cat_dab.Modules() + for _, modName := range modNames { + catMod, err := cfg.Cat_dab.GetModule(wfapi.CatalogRef{modName, "", ""}) + if err != nil { + return err + } + if err := cfg.CatalogModuleAndChildrenToHtml(*catMod); err != nil { + return err + } + } + return nil +} + +// CatalogToHtml generates a root page that links to all the modules. +// +// This function has no parameters because it uses the DAB in the SiteConfig entirely. +func (cfg SiteConfig) CatalogToHtml() error { + // 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. + if err := os.MkdirAll(cfg.OutputPath, 0775); err != nil { + return err + } + f, err := os.OpenFile(filepath.Join(cfg.OutputPath, "index.html"), os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0664) + if err != nil { + return err + } + defer f.Close() + + // TODO: it's completely bork that we don't have access to the CIDs here. workspace.Catalog is Not Good right now. + // TODO: this probably needs sorting to be stable. + // 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.) + t := template.Must(template.New("main").Funcs(cfg.tfuncs()).Parse(` + +
+

catalog

+
+

modules

+ + + `)) + return t.Execute(f, cfg.Cat_dab.Modules()) +} + +func (cfg SiteConfig) CatalogModuleAndChildrenToHtml(catMod wfapi.CatalogModule) error { + if err := cfg.CatalogModuleToHtml(catMod); err != nil { + return err + } + for _, releaseName := range catMod.Releases.Keys { + rel, err := cfg.Cat_dab.GetRelease(wfapi.CatalogRef{catMod.Name, releaseName, ""}) + if err != nil { + return err + } + if err := cfg.ReleaseToHtml(catMod, *rel); err != nil { + return err + } + } + return nil +} + +func (cfg SiteConfig) CatalogModuleToHtml(catMod wfapi.CatalogModule) error { + if err := os.MkdirAll(filepath.Join(cfg.OutputPath, string(catMod.Name)), 0775); err != nil { + return err + } + f, err := os.OpenFile(filepath.Join(cfg.OutputPath, string(catMod.Name), "index.html"), os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0664) + if err != nil { + return err + } + defer f.Close() + + t := template.Must(template.New("main").Funcs(cfg.tfuncs()).Parse(` + +
+ module: +

{{ .Name }}

+
+ (back to root) +

releases

+ +

metadata

+ {{- range $metadataKey := .Metadata.Keys }} +
{{ $metadataKey }}
{{ index $dot.Metadata.Values $metadataKey }}
+ {{- end }} + + `)) + return t.Execute(f, catMod) +} + +func (cfg SiteConfig) ReleaseToHtml(catMod wfapi.CatalogModule, rel wfapi.CatalogRelease) error { + if err := os.MkdirAll(filepath.Join(cfg.OutputPath, string(catMod.Name), string(rel.ReleaseName)), 0775); err != nil { + return err + } + 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) + if err != nil { + return err + } + defer f.Close() + + t := template.Must(template.New("main").Funcs(cfg.tfuncs()).Parse(` + +
+ module: +

{{ .Module.Name }}

+ release: +

{{ .Release.ReleaseName }}

+
+ (back to root; back to module index) +

items

+ +

metadata

+ {{- range $metadataKey := .Release.Metadata.Keys }} +
{{ $metadataKey }}
{{ index $dot.Metadata.Values $metadataKey }}
+ {{- end }} + + `)) + return t.Execute(f, map[string]interface{}{ + "Module": catMod, + "Release": rel, + }) +} diff --git a/pkg/cataloghtml/whee_test.go b/pkg/cataloghtml/whee_test.go new file mode 100644 index 00000000..340d14c6 --- /dev/null +++ b/pkg/cataloghtml/whee_test.go @@ -0,0 +1,36 @@ +package cataloghtml + +import ( + "context" + "os" + "path/filepath" + "testing" + + "github.com/warpfork/warpforge/pkg/workspace" +) + +func TestWhee(t *testing.T) { + // t.Skip("incomplete") + homedir, err := os.UserHomeDir() + if err != nil { + panic(err) + } + // This is a very sketchy "live" "test" that assumes you've run `warpforge catalog update` before, + // and operates (readonly!) on that real data. + cat_dab, err := workspace.OpenCatalog(os.DirFS("/"), filepath.Join(homedir, ".warpforge/catalogs/warpsys")[1:]) + if err != nil { + panic(err) + } + // Output paths are currently hardcoded and can be seen in the config object below. + // No actual assertions take place on this; the "test" is manually looking at that output. + cfg := SiteConfig{ + Ctx: context.Background(), + Cat_dab: cat_dab, + OutputPath: "/tmp/wf-test-cathtml/", + URLPrefix: "/tmp/wf-test-cathtml/", + } + os.RemoveAll(cfg.OutputPath) + if err := cfg.CatalogAndChildrenToHtml(); err != nil { + panic(err) + } +}