diff --git a/internal/topdata/native.go b/internal/topdata/native.go index 92a1723..ab65f0a 100644 --- a/internal/topdata/native.go +++ b/internal/topdata/native.go @@ -211,7 +211,7 @@ func BuildNativeWithOptions(p *project.Project, opts NativeBuildOptions, progres outputDir := wikiOutputPagesDir(p) if stateInfo, err := os.Stat(statePath); err == nil && !newestWikiSource.After(stateInfo.ModTime()) { if outputInfo, err := os.Stat(outputDir); err == nil && outputInfo.IsDir() { - if state, err := loadWikiState(statePath); err == nil { + if state, err := loadWikiState(statePath); err == nil && wikiCachedPagesAreCurrent(outputDir, state) { prebuiltWiki = &wikiResult{ OutputDir: outputDir, PageCount: state.Pages, diff --git a/internal/topdata/wiki_native.go b/internal/topdata/wiki_native.go index 1ce5b49..e39bb27 100644 --- a/internal/topdata/wiki_native.go +++ b/internal/topdata/wiki_native.go @@ -136,7 +136,7 @@ func buildWiki(p *project.Project, nativeResult BuildResult, force bool, progres } state, _ := loadWikiState(statePath) - if !force && digest != "" && state.Digest == digest { + if !force && digest != "" && state.Digest == digest && wikiCachedPagesAreCurrent(outputDir, state) { return wikiResult{ OutputDir: outputDir, PageCount: state.Pages, @@ -248,6 +248,23 @@ func buildWiki(p *project.Project, nativeResult BuildResult, force bool, progres }, nil } +func wikiCachedPagesAreCurrent(outputDir string, state wikiStateDocument) bool { + if state.Pages <= 0 { + return false + } + count := 0 + err := filepath.WalkDir(outputDir, func(path string, d fs.DirEntry, err error) error { + if err != nil { + return err + } + if !d.IsDir() && strings.EqualFold(filepath.Ext(path), ".html") { + count++ + } + return nil + }) + return err == nil && count == state.Pages +} + func loadWikiManualSections(p *project.Project) []wikiManualSection { defaults := defaultWikiManualSections() cfg := p.EffectiveConfig().TopData.Wiki diff --git a/internal/topdata/wiki_native_test.go b/internal/topdata/wiki_native_test.go index 066a08d..851f2d4 100644 --- a/internal/topdata/wiki_native_test.go +++ b/internal/topdata/wiki_native_test.go @@ -115,6 +115,71 @@ func TestBuildNativeGeneratesAndSkipsWikiPages(t *testing.T) { } } +func TestBuildWikiRegeneratesMissingCachedPages(t *testing.T) { + root := testProjectRoot(t) + mkdirAll(t, filepath.Join(root, "topdata", "data", "skills")) + writeFile(t, filepath.Join(root, "topdata", "base_dialog.json"), "{}\n") + writeFile(t, filepath.Join(root, "topdata", "data", "skills", "base.json"), `{ + "output": "skills.2da", + "columns": ["Label", "Name", "Description", "HideFromLevelUp", "Untrained", "KeyAbility", "ArmorCheckPenalty", "Constant"], + "rows": [ + { + "id": 0, + "key": "skills:athletics", + "Label": "Athletics", + "Name": {"tlk": {"key": "skills:athletics.name", "text": "Athletics"}}, + "Description": {"tlk": {"key": "skills:athletics.description", "text": "Ability: Strength."}}, + "HideFromLevelUp": "0", + "Untrained": "1", + "KeyAbility": "STR", + "ArmorCheckPenalty": "1", + "Constant": "SKILL_ATHLETICS" + } + ] +}`+"\n") + writeFile(t, filepath.Join(root, "topdata", "data", "skills", "lock.json"), `{"skills:athletics":0}`+"\n") + + proj := testProject(root) + proj.Config.TopData.ReferenceBuilder = "" + if _, err := BuildNative(proj, nil); err != nil { + t.Fatalf("BuildNative failed: %v", err) + } + + pagesDir := filepath.Join(root, ".cache", "wiki", "pages") + if err := os.RemoveAll(pagesDir); err != nil { + t.Fatalf("remove generated wiki pages: %v", err) + } + if err := os.MkdirAll(pagesDir, 0o755); err != nil { + t.Fatalf("recreate empty wiki pages dir: %v", err) + } + + result, err := BuildWikiWithOptions(proj, BuildWikiOptions{}, nil) + if err != nil { + t.Fatalf("BuildWikiWithOptions failed: %v", err) + } + if result.Status != wikiGeneratedStatus { + t.Fatalf("expected missing cached pages to regenerate, got wiki status %q", result.Status) + } + if _, err := os.Stat(filepath.Join(pagesDir, "skills", "athletics.html")); err != nil { + t.Fatalf("expected regenerated skill page: %v", err) + } + + if err := os.RemoveAll(pagesDir); err != nil { + t.Fatalf("remove regenerated wiki pages: %v", err) + } + if err := os.MkdirAll(pagesDir, 0o755); err != nil { + t.Fatalf("recreate empty wiki pages dir before native build: %v", err) + } + + nativeResult, err := BuildNative(proj, nil) + if err != nil { + t.Fatalf("BuildNative with missing cached pages failed: %v", err) + } + if nativeResult.WikiStatus != wikiGeneratedStatus { + t.Fatalf("expected native build to regenerate missing cached pages, got wiki status %q", nativeResult.WikiStatus) + } +} + func TestBuildNativeCanOmitAggregateWikiStatusListings(t *testing.T) { root := testProjectRoot(t) mkdirAll(t, filepath.Join(root, "topdata", "data", "skills"))