-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #16 from warpfork/catalogsite
catalogsite: first pass
- Loading branch information
Showing
6 changed files
with
315 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
{{- /* | ||
This template is for the index page made at the root of the catalog html view. | ||
It just lists and links to all the modules in the catalog. | ||
|
||
A couple of todos for this document: | ||
- We should print CIDs of the modules! | ||
... But we don't right now because the our accessor functions don't make it easy to get. (Work needed on workspace.Catalog.) | ||
- Farther future: we should have a CID of the entire catalog tree root snapshot somewhere, too. | ||
... But we don't right now, because that should probably use prolly trees (or some other scalable hash tree thing), which is not available and rigged up as a convenient library yet. | ||
|
||
*/ -}} | ||
<html> | ||
<head> | ||
<link rel="stylesheet" href="{{ (url "css.css") }}" /> | ||
</head> | ||
<body> | ||
<div style="border: 1px solid; padding 0.5em;"> | ||
<h1 style="display:inline">catalog</h1> | ||
</div> | ||
<h2>modules</h2> | ||
<ul> | ||
{{- range $moduleName := . }} | ||
<li><a href="{{ (url (string $moduleName) "_module.html") }}">{{ $moduleName }}</a></li> | ||
{{- end }} | ||
</ul> | ||
</body> | ||
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
<html> | ||
<head> | ||
<link rel="stylesheet" href="{{ (url "css.css") }}" /> | ||
</head> | ||
<body> | ||
<div style="border: 1px solid; padding 0.5em;"> | ||
<i>module:</i> | ||
<h1 style="display:inline">{{ .Name }}</h1> | ||
</div> | ||
(<a href="{{ (url "index.html") }}">back to root</a>) | ||
<h2>releases</h2> | ||
<ul> | ||
{{- $dot := . -}} | ||
{{- range $releaseKey := .Releases.Keys }} | ||
<li><a href="{{ (url (string $dot.Name) "_releases" (print $releaseKey ".html")) }}">{{ $releaseKey }}</a> <small>(cid: {{ index $dot.Releases.Values $releaseKey }})</small></li> | ||
{{- end }} | ||
</ul> | ||
<h2>metadata</h2> | ||
{{- range $metadataKey := .Metadata.Keys }} | ||
<dt>{{ $metadataKey }}</dt><dd>{{ index $dot.Metadata.Values $metadataKey }}</dd> | ||
{{- end }} | ||
</body> | ||
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
<html> | ||
<head> | ||
<link rel="stylesheet" href="{{ (url "css.css") }}" /> | ||
</head> | ||
<body> | ||
<div style="border: 1px solid; padding 0.5em;"> | ||
<i>module:</i> | ||
<h1 style="display:inline">{{ .Module.Name }}</h1> | ||
<i>release:</i> | ||
<h1 style="display:inline">{{ .Release.ReleaseName }}</h1> | ||
</div> | ||
(<a href="{{ (url "index.html") }}">back to root</a>; <a href="{{ (url (string .Module.Name) "_module.html") }}">back to module index</a>) | ||
<h2>items</h2> | ||
<ul> | ||
{{- $dot := .Release -}} | ||
{{- range $itemKey := .Release.Items.Keys }} | ||
<li>{{ $itemKey }} : {{ index $dot.Items.Values $itemKey }}</li> | ||
{{- end }} | ||
</ul> | ||
<h2>metadata</h2> | ||
{{- range $metadataKey := .Release.Metadata.Keys }} | ||
<dt>{{ $metadataKey }}</dt><dd>{{ index $dot.Metadata.Values $metadataKey }}</dd> | ||
{{- end }} | ||
</body> | ||
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,202 @@ | ||
package cataloghtml | ||
|
||
import ( | ||
"context" | ||
_ "embed" | ||
"html/template" | ||
"os" | ||
"path" | ||
"path/filepath" | ||
"reflect" | ||
|
||
"github.com/warpfork/warpforge/pkg/workspace" | ||
"github.com/warpfork/warpforge/wfapi" | ||
) | ||
|
||
var ( | ||
//go:embed catalogIndex.tmpl.html | ||
catalogIndexTemplate string | ||
|
||
//go:embed catalogModule.tmpl.html | ||
catalogModuleTemplate string | ||
|
||
//go:embed catalogRelease.tmpl.html | ||
catalogReleaseTemplate string | ||
|
||
//go:embed css.css | ||
cssBody []byte | ||
|
||
// FUTURE: consider the use of `embed.FS` and `template.ParseFS()`, if there grow to be many files here. | ||
// It has slightly less compile-time safety checks on filenames, though. | ||
) | ||
|
||
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 { | ||
// Very small helper function to stringify things. | ||
// This is useful for things that are literally typedefs of string but the template package isn't smart enough to be calm about unboxing it. | ||
// (It also does return something for values of non-string types, but not something very useful.) | ||
return reflect.ValueOf(x).String() | ||
}, | ||
"url": func(parts ...string) string { | ||
return path.Join(append([]string{cfg.URLPrefix}, parts...)...) | ||
}, | ||
} | ||
} | ||
|
||
// CatalogAndChildrenToHtml performs CatalogToHtml, and also | ||
// procedes to invoke the html'ing of all modules within. | ||
// Additionally, it does all the other "once" things | ||
// (namely, outputs a copy of the css). | ||
// | ||
// Errors: | ||
// | ||
// - warpforge-error-io -- in case of errors writing out the new html content. | ||
// - warpforge-error-internal -- in case of templating errors. | ||
// - warpforge-error-catalog-invalid -- in case the catalog data is invalid. | ||
// - warpforge-error-catalog-parse -- in case the catalog data failed to parse entirely. | ||
func (cfg SiteConfig) CatalogAndChildrenToHtml() error { | ||
// Emit catalog index. | ||
if err := cfg.CatalogToHtml(); err != nil { | ||
return err | ||
} | ||
// Emit the "once" stuff. | ||
if err := os.WriteFile(filepath.Join(cfg.OutputPath, "css.css"), cssBody, 0644); err != nil { | ||
return wfapi.ErrorIo("couldn't open file for css as part of cataloghtml emission", nil, err) | ||
} | ||
// Emit all modules within. | ||
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 | ||
} | ||
|
||
// doTemplate does the common bits of making files, processing the template, | ||
// and getting the output where it needs to go. | ||
// | ||
// Errors: | ||
// | ||
// - warpforge-error-io -- in case of errors writing out the new html content. | ||
// - warpforge-error-internal -- in case of templating errors. | ||
func (cfg SiteConfig) doTemplate(outputPath string, tmpl string, data interface{}) error { | ||
if err := os.MkdirAll(filepath.Dir(outputPath), 0775); err != nil { | ||
return wfapi.ErrorIo("couldn't mkdir during cataloghtml emission", nil, err) | ||
} | ||
f, err := os.OpenFile(outputPath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0664) | ||
if err != nil { | ||
return wfapi.ErrorIo("couldn't open file for writing during cataloghtml emission", nil, err) | ||
} | ||
defer f.Close() | ||
|
||
t := template.Must(template.New("main").Funcs(cfg.tfuncs()).Parse(tmpl)) | ||
if err := t.Execute(f, data); err != nil { | ||
return wfapi.ErrorInternal("templating failed", 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. | ||
// | ||
// Errors: | ||
// | ||
// - warpforge-error-io -- in case of errors writing out the new html content. | ||
// - warpforge-error-internal -- in case of templating errors. | ||
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. | ||
return cfg.doTemplate( | ||
filepath.Join(cfg.OutputPath, "index.html"), | ||
catalogIndexTemplate, | ||
cfg.Cat_dab.Modules(), | ||
) | ||
} | ||
|
||
// CatalogModuleAndChildrenToHtml performs CatalogModuleToHtml, and also | ||
// procedes to invoke the html'ing of all releases within. | ||
// | ||
// Errors: | ||
// | ||
// - warpforge-error-io -- in case of errors writing out the new html content. | ||
// - warpforge-error-internal -- in case of templating errors. | ||
// - warpforge-error-catalog-invalid -- in case the catalog data is invalid. | ||
// - warpforge-error-catalog-parse -- in case the catalog data failed to parse entirely. | ||
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 | ||
} | ||
|
||
// CatalogModuleToHtml generates a page for a module which enumerates | ||
// and links to all the releases within it, | ||
// as well as enumerates all the metadata attached to the catalog module. | ||
// | ||
// Errors: | ||
// | ||
// - warpforge-error-io -- in case of errors writing out the new html content. | ||
// - warpforge-error-internal -- in case of templating errors. | ||
func (cfg SiteConfig) CatalogModuleToHtml(catMod wfapi.CatalogModule) error { | ||
return cfg.doTemplate( | ||
filepath.Join(cfg.OutputPath, string(catMod.Name), "_module.html"), | ||
catalogModuleTemplate, | ||
catMod, | ||
) | ||
} | ||
|
||
// CatalogModuleToHtml generates a page for a release within a catalog module | ||
// which enumerates all the items within it, | ||
// as well as enumerates all the metadata attached to the release. | ||
// | ||
// Possible but not-yet-implemented future features of this output might include: | ||
// linking better to metadata that references other documents (such as Replays); | ||
// links to neighboring (e.g. forward and previous) releases; etc. | ||
// | ||
// Errors: | ||
// | ||
// - warpforge-error-io -- in case of errors writing out the new html content. | ||
// - warpforge-error-internal -- in case of templating errors. | ||
func (cfg SiteConfig) ReleaseToHtml(catMod wfapi.CatalogModule, rel wfapi.CatalogRelease) error { | ||
return cfg.doTemplate( | ||
filepath.Join(cfg.OutputPath, string(catMod.Name), "_releases", string(rel.ReleaseName)+".html"), | ||
catalogReleaseTemplate, | ||
map[string]interface{}{ | ||
"Module": catMod, | ||
"Release": rel, | ||
}, | ||
) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
/* | ||
body { | ||
color: #F00; | ||
} | ||
*/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
package cataloghtml | ||
|
||
import ( | ||
"context" | ||
"os" | ||
"path/filepath" | ||
"testing" | ||
|
||
"github.com/warpfork/warpforge/pkg/workspace" | ||
) | ||
|
||
func TestWhee(t *testing.T) { | ||
cwd, err := os.Getwd() | ||
if err != nil { | ||
panic(err) | ||
} | ||
cat_dab, err := workspace.OpenCatalog(os.DirFS("/"), filepath.Join(cwd, "../../.warpforge/catalog")[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) | ||
} | ||
} |