Opt-In Wiki Generation
This commit is contained in:
+3
-1
@@ -508,8 +508,10 @@ func parseBuildTopDataArgs(commandName string, args []string) (topdata.BuildAndP
|
|||||||
switch arg {
|
switch arg {
|
||||||
case "--force":
|
case "--force":
|
||||||
opts.Force = true
|
opts.Force = true
|
||||||
|
case "--wiki":
|
||||||
|
opts.BuildWiki = true
|
||||||
case "-h", "--help":
|
case "-h", "--help":
|
||||||
return opts, fmt.Errorf("usage: %s [--force]", commandName)
|
return opts, fmt.Errorf("usage: %s [--force] [--wiki]", commandName)
|
||||||
default:
|
default:
|
||||||
return opts, fmt.Errorf("unknown %s argument %q", commandName, arg)
|
return opts, fmt.Errorf("unknown %s argument %q", commandName, arg)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -135,7 +135,15 @@ func Build(p *project.Project, progress func(string)) (BuildResult, error) {
|
|||||||
return BuildNative(p, progress)
|
return BuildNative(p, progress)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type NativeBuildOptions struct {
|
||||||
|
BuildWiki bool
|
||||||
|
}
|
||||||
|
|
||||||
func BuildNative(p *project.Project, progress func(string)) (BuildResult, error) {
|
func BuildNative(p *project.Project, progress func(string)) (BuildResult, error) {
|
||||||
|
return BuildNativeWithOptions(p, NativeBuildOptions{BuildWiki: true}, progress)
|
||||||
|
}
|
||||||
|
|
||||||
|
func BuildNativeWithOptions(p *project.Project, opts NativeBuildOptions, progress func(string)) (BuildResult, error) {
|
||||||
if progress == nil {
|
if progress == nil {
|
||||||
progress = func(string) {}
|
progress = func(string) {}
|
||||||
}
|
}
|
||||||
@@ -152,6 +160,7 @@ func BuildNative(p *project.Project, progress func(string)) (BuildResult, error)
|
|||||||
return BuildResult{}, fmt.Errorf("topdata validation failed with %d error(s)", report.ErrorCount())
|
return BuildResult{}, fmt.Errorf("topdata validation failed with %d error(s)", report.ErrorCount())
|
||||||
}
|
}
|
||||||
var prebuiltWiki *wikiResult
|
var prebuiltWiki *wikiResult
|
||||||
|
if opts.BuildWiki {
|
||||||
if newestWikiSource, _, err := newestRelevantWikiSource(p.TopDataSourceDir()); err == nil && !newestWikiSource.IsZero() {
|
if newestWikiSource, _, err := newestRelevantWikiSource(p.TopDataSourceDir()); err == nil && !newestWikiSource.IsZero() {
|
||||||
statePath := filepath.Join(p.TopDataSourceDir(), wikiRootDirName, wikiStateFileName)
|
statePath := filepath.Join(p.TopDataSourceDir(), wikiRootDirName, wikiStateFileName)
|
||||||
outputDir := filepath.Join(p.TopDataSourceDir(), wikiRootDirName, wikiPagesDirName)
|
outputDir := filepath.Join(p.TopDataSourceDir(), wikiRootDirName, wikiPagesDirName)
|
||||||
@@ -168,10 +177,11 @@ func BuildNative(p *project.Project, progress func(string)) (BuildResult, error)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return buildNativeUnchecked(p, progress, prebuiltWiki)
|
}
|
||||||
|
return buildNativeUnchecked(p, opts, progress, prebuiltWiki)
|
||||||
}
|
}
|
||||||
|
|
||||||
func buildNativeUnchecked(p *project.Project, progress func(string), prebuiltWiki *wikiResult) (BuildResult, error) {
|
func buildNativeUnchecked(p *project.Project, opts NativeBuildOptions, progress func(string), prebuiltWiki *wikiResult) (BuildResult, error) {
|
||||||
if progress == nil {
|
if progress == nil {
|
||||||
progress = func(string) {}
|
progress = func(string) {}
|
||||||
}
|
}
|
||||||
@@ -333,7 +343,7 @@ func buildNativeUnchecked(p *project.Project, progress func(string), prebuiltWik
|
|||||||
wikiBuild := wikiResult{Status: wikiSkippedStatus}
|
wikiBuild := wikiResult{Status: wikiSkippedStatus}
|
||||||
if prebuiltWiki != nil {
|
if prebuiltWiki != nil {
|
||||||
wikiBuild = *prebuiltWiki
|
wikiBuild = *prebuiltWiki
|
||||||
} else {
|
} else if opts.BuildWiki {
|
||||||
wikiBuild, err = buildWiki(p, BuildResult{
|
wikiBuild, err = buildWiki(p, BuildResult{
|
||||||
Mode: "native",
|
Mode: "native",
|
||||||
Output2DADir: output2DA,
|
Output2DADir: output2DA,
|
||||||
|
|||||||
@@ -45,14 +45,6 @@ func resolveReleasedPartsManifest(p *project.Project, progress func(string)) (ma
|
|||||||
if progress == nil {
|
if progress == nil {
|
||||||
progress = func(string) {}
|
progress = func(string) {}
|
||||||
}
|
}
|
||||||
spec, err := deriveSowAssetsRepoSpec(p.Root)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
manifestURL, err := resolvePartsManifestAssetURL(spec)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
cachePath := filepath.Join(p.Root, ".cache", "topdata", partsManifestCacheFileName)
|
cachePath := filepath.Join(p.Root, ".cache", "topdata", partsManifestCacheFileName)
|
||||||
if strings.TrimSpace(os.Getenv("SOW_PARTS_MANIFEST_REFRESH")) == "" {
|
if strings.TrimSpace(os.Getenv("SOW_PARTS_MANIFEST_REFRESH")) == "" {
|
||||||
manifest, fresh, err := readFreshPartsManifestCache(cachePath, partsManifestCacheMaxAge)
|
manifest, fresh, err := readFreshPartsManifestCache(cachePath, partsManifestCacheMaxAge)
|
||||||
@@ -63,6 +55,14 @@ func resolveReleasedPartsManifest(p *project.Project, progress func(string)) (ma
|
|||||||
return inventoryFromPartsManifest(manifest), nil
|
return inventoryFromPartsManifest(manifest), nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
spec, err := deriveSowAssetsRepoSpec(p.Root)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
manifestURL, err := resolvePartsManifestAssetURL(spec)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
progress(fmt.Sprintf("Fetching released parts manifest from %s...", manifestURL))
|
progress(fmt.Sprintf("Fetching released parts manifest from %s...", manifestURL))
|
||||||
manifest, err := fetchPartsManifest(manifestURL)
|
manifest, err := fetchPartsManifest(manifestURL)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -220,6 +220,10 @@ func writePartsManifestCache(path string, manifest *partsManifest) error {
|
|||||||
payload = append(payload, '\n')
|
payload = append(payload, '\n')
|
||||||
current, err := os.ReadFile(path)
|
current, err := os.ReadFile(path)
|
||||||
if err == nil && bytes.Equal(current, payload) {
|
if err == nil && bytes.Equal(current, payload) {
|
||||||
|
now := time.Now()
|
||||||
|
if err := os.Chtimes(path, now, now); err != nil {
|
||||||
|
return fmt.Errorf("refresh parts manifest cache timestamp: %w", err)
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
if err != nil && !os.IsNotExist(err) {
|
if err != nil && !os.IsNotExist(err) {
|
||||||
|
|||||||
@@ -61,6 +61,7 @@ func BuildAndPackage(p *project.Project, progress func(string)) (PackageResult,
|
|||||||
|
|
||||||
type BuildAndPackageOptions struct {
|
type BuildAndPackageOptions struct {
|
||||||
Force bool
|
Force bool
|
||||||
|
BuildWiki bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func BuildAndPackageWithOptions(p *project.Project, opts BuildAndPackageOptions, progress func(string)) (PackageResult, error) {
|
func BuildAndPackageWithOptions(p *project.Project, opts BuildAndPackageOptions, progress func(string)) (PackageResult, error) {
|
||||||
@@ -87,11 +88,11 @@ func BuildAndPackageWithOptions(p *project.Project, opts BuildAndPackageOptions,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return buildAndPackageFull(p, progress)
|
return buildAndPackageFull(p, opts, progress)
|
||||||
}
|
}
|
||||||
|
|
||||||
func buildAndPackageFull(p *project.Project, progress func(string)) (PackageResult, error) {
|
func buildAndPackageFull(p *project.Project, opts BuildAndPackageOptions, progress func(string)) (PackageResult, error) {
|
||||||
nativeResult, err := BuildNative(p, progress)
|
nativeResult, err := BuildNativeWithOptions(p, NativeBuildOptions{BuildWiki: opts.BuildWiki}, progress)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return PackageResult{}, err
|
return PackageResult{}, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1554,7 +1554,7 @@ func validateNativeBuildability(p *project.Project, report *ValidationReport) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
defer restoreLockfiles(lockSnapshot)
|
defer restoreLockfiles(lockSnapshot)
|
||||||
if _, err := buildNativeUnchecked(&clone, nil, nil); err != nil {
|
if _, err := buildNativeUnchecked(&clone, NativeBuildOptions{}, nil, nil); err != nil {
|
||||||
report.Diagnostics = append(report.Diagnostics, Diagnostic{
|
report.Diagnostics = append(report.Diagnostics, Diagnostic{
|
||||||
Severity: SeverityError,
|
Severity: SeverityError,
|
||||||
Path: p.TopDataSourceDir(),
|
Path: p.TopDataSourceDir(),
|
||||||
@@ -1958,7 +1958,7 @@ func compareNativeSelfCheck(p *project.Project, actual2DA, actualTLK string, pro
|
|||||||
|
|
||||||
nativeProject := *p
|
nativeProject := *p
|
||||||
nativeProject.Config.TopData.Build = tempBuild
|
nativeProject.Config.TopData.Build = tempBuild
|
||||||
nativeResult, err := buildNativeUnchecked(&nativeProject, nil, nil)
|
nativeResult, err := buildNativeUnchecked(&nativeProject, NativeBuildOptions{}, nil, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, 0, 0, len(projectOutputs), nil
|
return 0, 0, 0, len(projectOutputs), nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -86,6 +86,56 @@ func TestBuildNativeGeneratesAndSkipsWikiPages(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestBuildAndPackageBuildsWikiOnlyWhenRequested(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": "Skill text."}},
|
||||||
|
"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 = ""
|
||||||
|
|
||||||
|
result, err := BuildAndPackageWithOptions(proj, BuildAndPackageOptions{}, nil)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("BuildAndPackageWithOptions failed: %v", err)
|
||||||
|
}
|
||||||
|
if result.WikiOutputDir != "" || result.WikiPages != 0 {
|
||||||
|
t.Fatalf("expected wiki generation to be skipped by default, got dir=%q pages=%d", result.WikiOutputDir, result.WikiPages)
|
||||||
|
}
|
||||||
|
if _, err := os.Stat(filepath.Join(root, "topdata", ".wiki", "state.json")); !os.IsNotExist(err) {
|
||||||
|
t.Fatalf("expected no wiki state without explicit wiki build, got %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
result, err = BuildAndPackageWithOptions(proj, BuildAndPackageOptions{Force: true, BuildWiki: true}, nil)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("BuildAndPackageWithOptions with wiki failed: %v", err)
|
||||||
|
}
|
||||||
|
if result.WikiPages != 1 {
|
||||||
|
t.Fatalf("expected one generated wiki page when requested, got %d", result.WikiPages)
|
||||||
|
}
|
||||||
|
if _, err := os.Stat(filepath.Join(root, "topdata", ".wiki", "state.json")); err != nil {
|
||||||
|
t.Fatalf("expected wiki state after explicit wiki build: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestBuildNativeRegeneratesWikiWhenTLKTextChanges(t *testing.T) {
|
func TestBuildNativeRegeneratesWikiWhenTLKTextChanges(t *testing.T) {
|
||||||
root := testProjectRoot(t)
|
root := testProjectRoot(t)
|
||||||
mkdirAll(t, filepath.Join(root, "topdata", "data", "skills"))
|
mkdirAll(t, filepath.Join(root, "topdata", "data", "skills"))
|
||||||
|
|||||||
Reference in New Issue
Block a user