104 lines
2.8 KiB
Go
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
|
|
}
|