Align topdata wiki canonical paths (#11)

Reviewed-on: https://gitea.westgate.pw/ShadowsOverWestgate/sow-tools/pulls/11
Co-authored-by: Michał Piasecki <mpiasecki720@protonmail.com>
Co-committed-by: Michał Piasecki <mpiasecki720@protonmail.com>
This commit is contained in:
2026-05-23 16:38:02 +02:00
committed by archvillainette
parent 7288d7e2b7
commit 6d6367ad18
6 changed files with 754 additions and 76 deletions
+86 -29
View File
@@ -119,6 +119,7 @@ type wikiContext struct {
visibilityPolicy *wikiVisibilityDefinitions
visibleWikiKeys map[string]bool
namespaceTitles map[string]string
namespacePaths map[string]string
}
func buildWiki(p *project.Project, nativeResult BuildResult, force bool, progress func(string)) (wikiResult, error) {
@@ -178,6 +179,7 @@ func buildWiki(p *project.Project, nativeResult BuildResult, force bool, progres
return wikiResult{}, err
}
ctx.namespaceTitles = wikiNamespaceTitles(namespaceDeclarations)
ctx.namespacePaths = wikiNamespacePaths(namespaceDeclarations)
if err := os.RemoveAll(outputDir); err != nil {
return wikiResult{}, fmt.Errorf("clean wiki output: %w", err)
@@ -231,10 +233,10 @@ func buildWiki(p *project.Project, nativeResult BuildResult, force bool, progres
if err := generateEntityPages(outputDir, ctx, writePage); err != nil {
return wikiResult{}, err
}
if err := generateStatusPages(outputDir, pageStatuses, pageTitles, p.EffectiveConfig().TopData.Wiki.ManagedNamespaces, p.EffectiveConfig().TopData.Wiki.StatusListingScope, manualSections); err != nil {
if err := generateStatusPages(outputDir, pageStatuses, pageTitles, p.EffectiveConfig().TopData.Wiki.ManagedNamespaces, p.EffectiveConfig().TopData.Wiki.StatusListingScope, manualSections, ctx); err != nil {
return wikiResult{}, err
}
if err := indexUnregisteredWikiPages(rootDir, outputDir, p.EffectiveConfig().TopData.Wiki.StalePages.Default, &pageIndex); err != nil {
if err := indexUnregisteredWikiPages(rootDir, outputDir, p.EffectiveConfig().TopData.Wiki.StalePages.Default, ctx, &pageIndex); err != nil {
return wikiResult{}, err
}
if err := saveWikiPageIndex(filepath.Join(rootDir, "page-index.json"), pageIndex); err != nil {
@@ -345,10 +347,14 @@ func validateWikiPageIndex(index wikiPageIndex) error {
return fmt.Errorf("duplicate wiki page-index output_path %q for %s and %s", entry.OutputPath, previous, entry.PageID)
}
if entry.PublicPath != "" {
if previous, ok := publicPaths[entry.PublicPath]; ok {
publicPathKey := canonicalWikiSlashPathFoldedKey(entry.PublicPath)
if publicPathKey == "" {
publicPathKey = entry.PublicPath
}
if previous, ok := publicPaths[publicPathKey]; ok {
return fmt.Errorf("duplicate wiki page-index public_path %q for %s and %s", entry.PublicPath, previous, entry.PageID)
}
publicPaths[entry.PublicPath] = entry.PageID
publicPaths[publicPathKey] = entry.PageID
}
pageIDs[entry.PageID] = entry.OutputPath
outputPaths[entry.OutputPath] = entry.PageID
@@ -356,11 +362,14 @@ func validateWikiPageIndex(index wikiPageIndex) error {
return nil
}
func indexUnregisteredWikiPages(rootDir, outputDir, stalePolicy string, index *wikiPageIndex) error {
func indexUnregisteredWikiPages(rootDir, outputDir, stalePolicy string, ctx *wikiContext, index *wikiPageIndex) error {
seen := map[string]struct{}{}
for _, entry := range index.Pages {
seen[entry.PageID] = struct{}{}
}
if ctx == nil {
ctx = &wikiContext{}
}
return filepath.WalkDir(outputDir, func(path string, d fs.DirEntry, err error) error {
if err != nil {
return err
@@ -389,13 +398,14 @@ func indexUnregisteredWikiPages(rootDir, outputDir, stalePolicy string, index *w
if err != nil {
relToRoot = filepath.Base(path)
}
title := extractHTMLTitle(string(raw), pageID)
index.Pages = append(index.Pages, wikiPageIndexEntry{
PageID: pageID,
Namespace: namespace,
SourceDataset: categoryFromWikiNamespace(namespace),
SourceKey: pageID,
Title: extractHTMLTitle(string(raw), pageID),
PublicPath: (&wikiContext{}).publicWikiPath(namespace, extractHTMLTitle(string(raw), pageID)),
Title: title,
PublicPath: ctx.publicWikiPath(namespace, title),
Hash: computeManagedHash(string(raw)),
OutputPath: filepath.ToSlash(relToRoot),
EditPolicy: wikiEditPolicy(namespace),
@@ -1507,19 +1517,19 @@ func wikiStatusNoun(category string) string {
}
}
func generateStatusPages(outputDir string, pageStatuses map[string]string, pageTitles map[string]string, namespaces []string, listingScope string, manualSections []wikiManualSection) error {
func generateStatusPages(outputDir string, pageStatuses map[string]string, pageTitles map[string]string, namespaces []string, listingScope string, manualSections []wikiManualSection, ctx *wikiContext) error {
summaries := buildWikiNamespaceSummaries(pageStatuses, namespaces)
if err := writeWikiFile(filepath.Join(outputDir, "meta", "wikistatus.html"), renderWikiStatusReportPage(summaries, namespaces), manualSections); err != nil {
if err := writeWikiFile(filepath.Join(outputDir, "meta", "wikistatus.html"), renderWikiStatusReportPage(summaries, namespaces, ctx), manualSections); err != nil {
return err
}
for _, namespace := range namespaces {
summary := summaries[namespace]
if err := writeWikiFile(filepath.Join(outputDir, "meta", "wikistatus", namespace+".html"), renderWikiNamespaceFragment(namespace, summary), manualSections); err != nil {
if err := writeWikiFile(filepath.Join(outputDir, "meta", "wikistatus", namespace+".html"), renderWikiNamespaceFragment(namespace, summary, ctx), manualSections); err != nil {
return err
}
for _, status := range []string{wikiStatusNew, wikiStatusModified, wikiStatusVanilla} {
pageIDs := filterWikiPageIDs(pageStatuses, namespace, status)
if err := writeWikiFile(filepath.Join(outputDir, "meta", "wikistatus", namespace, status+".html"), renderWikiStatusListingPage(namespaceTitle(namespace)+" "+wikiStatusLabels[status]+" Pages", pageIDs, pageTitles), manualSections); err != nil {
if err := writeWikiFile(filepath.Join(outputDir, "meta", "wikistatus", namespace, status+".html"), renderWikiStatusListingPage(wikiNamespacePublicTitle(ctx, namespace)+" "+wikiStatusLabels[status]+" Pages", pageIDs, pageTitles, ctx), manualSections); err != nil {
return err
}
}
@@ -1530,7 +1540,7 @@ func generateStatusPages(outputDir string, pageStatuses map[string]string, pageT
if listingScope == "all" {
for _, status := range []string{wikiStatusNew, wikiStatusModified, wikiStatusVanilla} {
pageIDs := filterWikiPageIDs(pageStatuses, "", status)
if err := writeWikiFile(filepath.Join(outputDir, "meta", "wikistatus", status+".html"), renderWikiStatusListingPage(wikiStatusLabels[status]+" Pages", pageIDs, pageTitles), manualSections); err != nil {
if err := writeWikiFile(filepath.Join(outputDir, "meta", "wikistatus", status+".html"), renderWikiStatusListingPage(wikiStatusLabels[status]+" Pages", pageIDs, pageTitles, ctx), manualSections); err != nil {
return err
}
}
@@ -1587,20 +1597,36 @@ func rollupWikiStatuses(statuses []string) string {
return best
}
func renderWikiNamespaceFragment(namespace string, summary map[string]any) string {
return renderStatusTable(namespaceTitle(namespace), summary, "")
func wikiNamespacePublicTitle(ctx *wikiContext, namespace string) string {
if ctx != nil && ctx.namespaceTitles != nil {
if declared := strings.TrimSpace(ctx.namespaceTitles[namespace]); declared != "" {
return declared
}
}
return namespaceTitle(namespace)
}
func renderWikiStatusReportPage(summaries map[string]map[string]any, namespaces []string) string {
func renderWikiNamespaceFragment(namespace string, summary map[string]any, ctx *wikiContext) string {
return renderStatusTable(wikiNamespacePublicTitle(ctx, namespace), summary, "")
}
func renderWikiStatusReportPage(summaries map[string]map[string]any, namespaces []string, ctx *wikiContext) string {
if ctx == nil {
ctx = &wikiContext{}
}
lines := []string{"====== Wiki Status ======", "", "This page is auto-generated from builder source provenance.", ""}
for _, namespace := range namespaces {
summary := summaries[namespace]
lines = append(lines, renderStatusTable(namespaceTitle(namespace), summary, fmt.Sprintf("[[%s:index|%s]]", namespace, namespaceTitle(namespace))))
title := wikiNamespacePublicTitle(ctx, namespace)
lines = append(lines, renderStatusTable(title, summary, fmt.Sprintf("[[%s|%s]]", ctx.publicWikiPath(namespace, ""), title)))
}
return strings.Join(lines, "\n")
}
func renderWikiStatusListingPage(title string, pageIDs []string, pageTitles map[string]string) string {
func renderWikiStatusListingPage(title string, pageIDs []string, pageTitles map[string]string, ctx *wikiContext) string {
if ctx == nil {
ctx = &wikiContext{}
}
lines := []string{"====== " + title + " ======", ""}
if len(pageIDs) == 0 {
lines = append(lines, "No matching generated pages.")
@@ -1610,7 +1636,8 @@ func renderWikiStatusListingPage(title string, pageIDs []string, pageTitles map[
if title == "" {
title = pageID
}
lines = append(lines, " * [["+pageID+"|"+title+"]]")
namespace := strings.SplitN(pageID, ":", 2)[0]
lines = append(lines, " * [["+ctx.publicWikiPath(namespace, title)+"|"+title+"]]")
}
}
return strings.Join(lines, "\n")
@@ -1659,6 +1686,18 @@ func wikiNamespaceTitles(declarations []wikiNamespaceDeclaration) map[string]str
return titles
}
func wikiNamespacePaths(declarations []wikiNamespaceDeclaration) map[string]string {
paths := map[string]string{}
for _, declaration := range declarations {
id := strings.TrimSpace(declaration.ID)
path := strings.TrimSpace(declaration.CanonicalPath)
if id != "" && path != "" {
paths[id] = path
}
}
return paths
}
func wikiPageIDForKey(key string) string {
if key == "" {
return ""
@@ -1703,17 +1742,37 @@ func (ctx *wikiContext) publicWikiTargetForKey(key, fallbackTitle string) string
}
func (ctx *wikiContext) publicWikiPath(namespace, title string) string {
namespaceTitle := namespaceTitle(namespace)
if ctx != nil && ctx.namespaceTitles != nil {
if declared := strings.TrimSpace(ctx.namespaceTitles[namespace]); declared != "" {
namespaceTitle = declared
namespacePath := canonicalWikiSegment(namespaceTitle(namespace))
if ctx != nil && ctx.namespacePaths != nil {
if declared := strings.TrimSpace(ctx.namespacePaths[namespace]); declared != "" {
namespacePath = declared
}
}
segments := []string{namespaceTitle}
for _, part := range strings.Split(title, " :: ") {
segments = append(segments, part)
if ctx != nil && ctx.namespaceTitles != nil && (ctx.namespacePaths == nil || strings.TrimSpace(ctx.namespacePaths[namespace]) == "") {
if declared := strings.TrimSpace(ctx.namespaceTitles[namespace]); declared != "" {
namespacePath = canonicalWikiSegment(declared)
}
}
return canonicalWikiPath(segments...)
titlePath := canonicalWikiPath(wikiTitlePathParts(title)...)
switch {
case namespacePath == "":
return titlePath
case titlePath == "":
return namespacePath
default:
return namespacePath + "/" + titlePath
}
}
func wikiTitlePathParts(title string) []string {
parts := []string{}
for _, part := range strings.Split(title, "::") {
part = strings.TrimSpace(part)
if part != "" {
parts = append(parts, part)
}
}
return parts
}
func wikiSlugifyTitle(value string) string {
@@ -1726,9 +1785,7 @@ func wikiPageOutputRelPath(pageID, title string) string {
namespace = "page"
}
parts := []string{namespace}
for _, part := range strings.Split(title, " :: ") {
parts = append(parts, part)
}
parts = append(parts, wikiTitlePathParts(title)...)
path := canonicalWikiPath(parts...)
if path == "" {
path = wikiPageIDToRelPath(pageID)