Files
archvillainette 5ebef57160
build-binaries / build-binaries (push) Successful in 2m5s
test / test (push) Successful in 1m23s
assets builder tools (#39)
Reviewed-on: #39
Reviewed-by: xtul <mpiasecki720@protonmail.com>
2026-07-12 12:51:17 +00:00

104 lines
2.8 KiB
Go

package assets
import (
"flag"
"fmt"
"io"
"os"
"path/filepath"
"strings"
"git.westgate.pw/ShadowsOverWestgate/sow-tools/internal/assets/mdl"
)
// runFixMDL lowercases .mdl filenames and rewrites ASCII model identity to
// match each file's stem. Binary models are skipped (the engine owns those).
func runFixMDL(args []string, stdout, stderr io.Writer) int {
fs := flag.NewFlagSet("fix-mdl", flag.ContinueOnError)
fs.SetOutput(stderr)
dryRun := fs.Bool("dry-run", false, "report changes without touching disk")
nonRecursive := fs.Bool("non-recursive", false, "do not descend into subdirectories")
if err := fs.Parse(args); err != nil {
return exitUsage
}
paths := fs.Args()
if len(paths) == 0 {
fmt.Fprintln(stderr, "assets fix-mdl: usage: fix-mdl [--dry-run] <path>...")
return exitUsage
}
files, err := walk(paths, mdlExt, !*nonRecursive)
if err != nil {
fmt.Fprintln(stderr, "assets fix-mdl:", err)
return exitUsage
}
changed := 0
failed := false
for _, f := range files {
// 1. Lowercase the basename if needed.
//
// ponytail: 35k files are each read once here (CheckNames + the rewrite
// on candidates). The shell reference batched an awk pass to avoid
// per-file subprocess spawns; in Go a plain read is cheap, so the batch
// is not worth porting. If profiling ever shows this hot, parallelize
// the loop.
lower := f
if base := filepath.Base(f); base != strings.ToLower(base) {
lower = filepath.Join(filepath.Dir(f), strings.ToLower(base))
if _, err := os.Stat(lower); err == nil {
fmt.Fprintf(stderr, "assets fix-mdl: lowercase collision: %s -> %s\n", f, lower)
failed = true
continue
}
if *dryRun {
fmt.Fprintf(stdout, "would lowercase: %s -> %s\n", f, lower)
} else {
if err := os.Rename(f, lower); err != nil {
fmt.Fprintf(stderr, "assets fix-mdl: failed to lowercase %s: %v\n", f, err)
failed = true
continue
}
fmt.Fprintf(stdout, "lowercased: %s -> %s\n", f, lower)
}
changed++
}
// 2. Rewrite model identity if the (lowercased) file has a mismatch.
// In dry-run the on-disk file is still the original path.
readPath := lower
if *dryRun && lower != f {
readPath = f
}
data, err := os.ReadFile(readPath)
if err != nil {
fmt.Fprintln(stderr, "assets fix-mdl:", err)
failed = true
continue
}
out, wasChanged := mdl.FixNames(data, mdl.ExpectedName(lower))
if !wasChanged {
continue
}
if *dryRun {
fmt.Fprintf(stdout, "would fix: %s\n", lower)
} else {
if err := os.WriteFile(lower, out, 0o644); err != nil {
fmt.Fprintln(stderr, "assets fix-mdl:", err)
failed = true
continue
}
fmt.Fprintf(stdout, "fixed: %s\n", lower)
}
changed++
}
if changed == 0 {
fmt.Fprintln(stdout, "no broken mdl model names found")
}
if failed {
return exitFail
}
return exitOK
}