Tool: Polish Pass 1
In sow-tools, extract now behaves like a real sync by default: it overwrites changed extracted files, removes stale extracted files that no longer exist in the built archives, and normalizes extracted resource filenames to lowercase. I also made validation warn on uppercase resource filenames so mixed-case names like I_ELVENCHAIN are surfaced instead of quietly lingering. The extract command output now includes overwritten and removed counts too.
This commit is contained in:
@@ -76,6 +76,9 @@ func ValidateProject(p *project.Project) Report {
|
||||
resolver := newAssetGroupResolver(p)
|
||||
|
||||
for _, rel := range p.Inventory.SourceFiles {
|
||||
if hasUppercaseResourceName(rel) {
|
||||
report.add(rel, "resource filenames should be lowercase", SeverityWarning)
|
||||
}
|
||||
abs := filepath.Join(p.SourceDir(), filepath.FromSlash(rel))
|
||||
document, resref, extension, err := loadDocument(abs)
|
||||
if err != nil {
|
||||
@@ -90,7 +93,7 @@ func ValidateProject(p *project.Project) Report {
|
||||
Document: document,
|
||||
})
|
||||
|
||||
key := resref + "." + extension
|
||||
key := strings.ToLower(resref) + "." + extension
|
||||
if previous, exists := resourceIndex[key]; exists {
|
||||
report.add(rel, fmt.Sprintf("duplicate resource %s also defined by %s", key, previous), SeverityError)
|
||||
} else {
|
||||
@@ -101,7 +104,10 @@ func ValidateProject(p *project.Project) Report {
|
||||
}
|
||||
|
||||
for _, rel := range p.Inventory.ScriptFiles {
|
||||
base := strings.TrimSuffix(filepath.Base(rel), filepath.Ext(rel))
|
||||
if hasUppercaseResourceName(rel) {
|
||||
report.add(rel, "resource filenames should be lowercase", SeverityWarning)
|
||||
}
|
||||
base := strings.ToLower(strings.TrimSuffix(filepath.Base(rel), filepath.Ext(rel)))
|
||||
if previous, exists := scriptIndex[base]; exists {
|
||||
report.add(rel, fmt.Sprintf("duplicate script resource %s also defined by %s", base, previous), SeverityError)
|
||||
} else {
|
||||
@@ -110,9 +116,12 @@ func ValidateProject(p *project.Project) Report {
|
||||
}
|
||||
|
||||
for _, rel := range p.Inventory.AssetFiles {
|
||||
base := strings.TrimSuffix(filepath.Base(rel), filepath.Ext(rel))
|
||||
if hasUppercaseResourceName(rel) {
|
||||
report.add(rel, "resource filenames should be lowercase", SeverityWarning)
|
||||
}
|
||||
base := strings.ToLower(strings.TrimSuffix(filepath.Base(rel), filepath.Ext(rel)))
|
||||
extension := strings.TrimPrefix(strings.ToLower(filepath.Ext(rel)), ".")
|
||||
key := base + "." + extension
|
||||
key := strings.ToLower(base) + "." + extension
|
||||
if _, exists := assetIndex[key]; !exists {
|
||||
assetIndex[key] = rel
|
||||
}
|
||||
@@ -187,7 +196,7 @@ func loadDocument(path string) (gff.Document, string, string, error) {
|
||||
if extension == "" {
|
||||
return gff.Document{}, "", "", fmt.Errorf("missing resource extension before .json")
|
||||
}
|
||||
resref := strings.TrimSuffix(stem, "."+extension)
|
||||
resref := strings.ToLower(strings.TrimSuffix(stem, "."+extension))
|
||||
|
||||
var document gff.Document
|
||||
if err := json.Unmarshal(raw, &document); err != nil {
|
||||
@@ -250,25 +259,25 @@ func validateReferences(report *Report, document loadedDocument, resources, scri
|
||||
if isBuiltinScript(value) {
|
||||
return
|
||||
}
|
||||
if _, exists := scripts[value]; !exists {
|
||||
if _, exists := scripts[strings.ToLower(value)]; !exists {
|
||||
report.add(document.Path, fmt.Sprintf("missing script reference %q from field %q", value, field.Label), SeverityError)
|
||||
}
|
||||
case field.Label == "Conversation":
|
||||
key := value + ".dlg"
|
||||
key := strings.ToLower(value) + ".dlg"
|
||||
if _, exists := resources[key]; !exists {
|
||||
report.add(document.Path, fmt.Sprintf("missing dialog reference %q", key), SeverityError)
|
||||
}
|
||||
case field.Label == "Mod_Entry_Area":
|
||||
key := value + ".are"
|
||||
key := strings.ToLower(value) + ".are"
|
||||
if _, exists := resources[key]; !exists {
|
||||
report.add(document.Path, fmt.Sprintf("missing area reference %q", key), SeverityError)
|
||||
}
|
||||
case field.Label == "Model":
|
||||
if !hasAsset(value, []string{"mdl"}, assets) {
|
||||
if !hasAsset(strings.ToLower(value), []string{"mdl"}, assets) {
|
||||
report.add(document.Path, fmt.Sprintf("missing model asset for %q", value), SeverityError)
|
||||
}
|
||||
case field.Label == "Sound":
|
||||
if !hasAsset(value, []string{"wav"}, assets) {
|
||||
if !hasAsset(strings.ToLower(value), []string{"wav"}, assets) {
|
||||
report.add(document.Path, fmt.Sprintf("missing sound asset for %q", value), SeverityError)
|
||||
}
|
||||
}
|
||||
@@ -390,6 +399,11 @@ func walkFields(s gff.Struct, visit func(gff.Field)) {
|
||||
}
|
||||
}
|
||||
|
||||
func hasUppercaseResourceName(rel string) bool {
|
||||
base := filepath.Base(rel)
|
||||
return base != strings.ToLower(base)
|
||||
}
|
||||
|
||||
func fieldStringValue(value gff.Value) (string, bool) {
|
||||
switch typed := value.(type) {
|
||||
case gff.StringValue:
|
||||
|
||||
Reference in New Issue
Block a user