feat(assets): wire builder into dispatch, shim, smoke, docs
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,11 @@
|
|||||||
|
// Command crucible-assets is the standalone assets builder (equivalent to
|
||||||
|
// `crucible assets`). A single-token binary keeps consumer wrapper scripts simple.
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"git.westgate.pw/ShadowsOverWestgate/sow-tools/internal/dispatch"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() { os.Exit(dispatch.RunBuilder("assets", os.Args[1:])) }
|
||||||
@@ -22,6 +22,13 @@ aliases.
|
|||||||
| `topdata` | `convert` | Convert between 2DA and native JSON/module formats. |
|
| `topdata` | `convert` | Convert between 2DA and native JSON/module formats. |
|
||||||
| `wiki` | `build` | Render wiki page drafts from compiled topdata. |
|
| `wiki` | `build` | Render wiki page drafts from compiled topdata. |
|
||||||
| `wiki` | `deploy` | Deploy generated wiki pages to NodeBB. |
|
| `wiki` | `deploy` | Deploy generated wiki pages to NodeBB. |
|
||||||
|
| `assets` | `compile` | Compile ASCII `.mdl` models to binary in place. |
|
||||||
|
| `assets` | `convert` | Convert textures to/from NWN DDS (flips vertically). |
|
||||||
|
| `assets` | `upscale` | Upscale textures through an installed backend. |
|
||||||
|
| `assets` | `check-mdl` | Report uncompiled ASCII `.mdl` and model-name mismatches. |
|
||||||
|
| `assets` | `fix-mdl` | Lowercase `.mdl` names and rewrite model identity to match. |
|
||||||
|
| `assets` | `check-dupes` | Report runtime-name (basename) collisions across dirs. |
|
||||||
|
| `assets` | `clean-dupes` | Delete clean-tree files whose basename collides with primary. |
|
||||||
|
|
||||||
`crucible-depot` remains registered but unwired. It fails closed with exit `70`
|
`crucible-depot` remains registered but unwired. It fails closed with exit `70`
|
||||||
and never emits placeholder artifacts.
|
and never emits placeholder artifacts.
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -17,6 +17,7 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
|
|
||||||
"git.westgate.pw/ShadowsOverWestgate/sow-tools/internal/app"
|
"git.westgate.pw/ShadowsOverWestgate/sow-tools/internal/app"
|
||||||
|
"git.westgate.pw/ShadowsOverWestgate/sow-tools/internal/assets"
|
||||||
"git.westgate.pw/ShadowsOverWestgate/sow-tools/internal/buildinfo"
|
"git.westgate.pw/ShadowsOverWestgate/sow-tools/internal/buildinfo"
|
||||||
"git.westgate.pw/ShadowsOverWestgate/sow-tools/internal/depot"
|
"git.westgate.pw/ShadowsOverWestgate/sow-tools/internal/depot"
|
||||||
"git.westgate.pw/ShadowsOverWestgate/sow-tools/internal/menu"
|
"git.westgate.pw/ShadowsOverWestgate/sow-tools/internal/menu"
|
||||||
@@ -103,6 +104,21 @@ var Registry = []Builder{
|
|||||||
},
|
},
|
||||||
Wired: true,
|
Wired: true,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
Name: "assets",
|
||||||
|
Bin: "crucible-assets",
|
||||||
|
Summary: "compile/convert/upscale NWN assets + mdl/dupe integrity",
|
||||||
|
Commands: []Command{
|
||||||
|
{Name: "compile", Summary: "compile ASCII .mdl models to binary in place", Usage: "crucible assets compile [--nwn INSTALL] [--non-recursive] <dir>..."},
|
||||||
|
{Name: "convert", Summary: "convert textures to/from NWN DDS (flips vertically)", Usage: "crucible assets convert [--to dds|png|tga] [--backend PATH] [--non-recursive] <dir>..."},
|
||||||
|
{Name: "upscale", Summary: "upscale textures through an installed backend", Usage: "crucible assets upscale [--scale N] [--backend PATH] [--non-recursive] <dir>..."},
|
||||||
|
{Name: "check-mdl", Summary: "report uncompiled ASCII .mdl and model-name mismatches", Usage: "crucible assets check-mdl <path>..."},
|
||||||
|
{Name: "fix-mdl", Summary: "lowercase .mdl names and rewrite model identity to match", Usage: "crucible assets fix-mdl [--dry-run] <path>..."},
|
||||||
|
{Name: "check-dupes", Summary: "report runtime-name (basename) collisions across dirs", Usage: "crucible assets check-dupes <dir>..."},
|
||||||
|
{Name: "clean-dupes", Summary: "delete clean-tree files whose basename collides with primary", Usage: "crucible assets clean-dupes [--dry-run] <primary> <clean>"},
|
||||||
|
},
|
||||||
|
Wired: true,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
Name: "hak",
|
Name: "hak",
|
||||||
Bin: "crucible-hak",
|
Bin: "crucible-hak",
|
||||||
@@ -375,11 +391,16 @@ func runBuilder(name string, args []string, out, errw io.Writer) int {
|
|||||||
return exitOK
|
return exitOK
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if b.Name == "depot" && b.Wired {
|
if b.Wired {
|
||||||
// depot parses its own subcommand (status/push/verify/get/pull) and
|
// depot and assets are self-contained builders: they parse their own
|
||||||
// has its own richer exit contract (0/1/2/64/70), so it bypasses the
|
// subcommands and own their exit contract, bypassing the
|
||||||
// b.Commands/delegateLegacy routing entirely.
|
// b.Commands/delegateLegacy legacy routing entirely.
|
||||||
|
switch b.Name {
|
||||||
|
case "depot":
|
||||||
return depot.Run(args, out, errw, os.Getenv)
|
return depot.Run(args, out, errw, os.Getenv)
|
||||||
|
case "assets":
|
||||||
|
return assets.Run(args, out, errw, os.Getenv)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if !b.Wired {
|
if !b.Wired {
|
||||||
// No migrated logic yet (depot): fail closed, never fake an artifact.
|
// No migrated logic yet (depot): fail closed, never fake an artifact.
|
||||||
|
|||||||
@@ -151,6 +151,7 @@ func TestBuilderHelpIsOK(t *testing.T) {
|
|||||||
func TestCanonicalCommandSurface(t *testing.T) {
|
func TestCanonicalCommandSurface(t *testing.T) {
|
||||||
want := map[string][]string{
|
want := map[string][]string{
|
||||||
"depot": {"status", "push", "verify", "get", "pull"},
|
"depot": {"status", "push", "verify", "get", "pull"},
|
||||||
|
"assets": {"compile", "convert", "upscale", "check-mdl", "fix-mdl", "check-dupes", "clean-dupes"},
|
||||||
"hak": {"build", "manifest"},
|
"hak": {"build", "manifest"},
|
||||||
"module": {"build", "extract", "validate", "compare", "manifest"},
|
"module": {"build", "extract", "validate", "compare", "manifest"},
|
||||||
"topdata": {"validate", "build", "package", "compare", "convert"},
|
"topdata": {"validate", "build", "package", "compare", "convert"},
|
||||||
@@ -172,10 +173,10 @@ func TestRegistryCommandNamesAndAliasesAreUnambiguous(t *testing.T) {
|
|||||||
for _, builder := range Registry {
|
for _, builder := range Registry {
|
||||||
seen := map[string]bool{}
|
seen := map[string]bool{}
|
||||||
for _, command := range builder.Commands {
|
for _, command := range builder.Commands {
|
||||||
// depot parses its own subcommands and bypasses AppCommand routing
|
// depot and assets parse their own subcommands and bypass AppCommand
|
||||||
// entirely (see the depot special-case in runBuilder), so its
|
// routing entirely (see the self-contained-builder branch in
|
||||||
// Commands carry no AppCommand.
|
// runBuilder), so their Commands carry no AppCommand.
|
||||||
requireAppCommand := builder.Name != "depot"
|
requireAppCommand := builder.Name != "depot" && builder.Name != "assets"
|
||||||
if command.Name == "" || command.Summary == "" || command.Usage == "" || (requireAppCommand && command.AppCommand == "") {
|
if command.Name == "" || command.Summary == "" || command.Usage == "" || (requireAppCommand && command.AppCommand == "") {
|
||||||
t.Errorf("%s has incomplete command metadata: %#v", builder.Name, command)
|
t.Errorf("%s has incomplete command metadata: %#v", builder.Name, command)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ bin=bin
|
|||||||
|
|
||||||
# Keep in sync with internal/dispatch.Registry (Wired flag).
|
# Keep in sync with internal/dispatch.Registry (Wired flag).
|
||||||
unwired=()
|
unwired=()
|
||||||
wired=(depot hak module topdata wiki)
|
wired=(assets depot hak module topdata wiki)
|
||||||
|
|
||||||
exit_of() { set +e; "$@" >/dev/null 2>&1; local c=$?; set -e; echo "${c}"; }
|
exit_of() { set +e; "$@" >/dev/null 2>&1; local c=$?; set -e; echo "${c}"; }
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user