From 42fc32511e5a54f2da1538f633dbdafbdd523839 Mon Sep 17 00:00:00 2001 From: Merith Date: Sun, 22 Jun 2025 13:16:39 -0700 Subject: [PATCH] redo magefile --- go.mod | 12 +++- go.sum | 13 +++++ magefile.go | 154 ++++++++++++++++++++++++++-------------------------- 3 files changed, 99 insertions(+), 80 deletions(-) diff --git a/go.mod b/go.mod index fe9a557..c6c8524 100644 --- a/go.mod +++ b/go.mod @@ -1,5 +1,13 @@ -module DigitalStorageTweaks +module local go 1.24.3 -require github.com/magefile/mage v1.15.0 +require ( + github.com/magefile/mage v1.15.0 + github.com/xeipuuv/gojsonschema v1.2.0 +) + +require ( + github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f // indirect + github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect +) diff --git a/go.sum b/go.sum index 4ee1b87..5d71808 100644 --- a/go.sum +++ b/go.sum @@ -1,2 +1,15 @@ +github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/magefile/mage v1.15.0 h1:BvGheCMAsG3bWUDbZ8AyXXpCNwU9u5CB6sM+HNb9HYg= github.com/magefile/mage v1.15.0/go.mod h1:z5UZb/iS3GoOSn0JgWuiw7dxlurVYTu+/jHXqQg881A= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f h1:J9EGpcZtP0E/raorCMxlFGSTBrsSlaDGf3jU/qvAE2c= +github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= +github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0= +github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= +github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74= +github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= diff --git a/magefile.go b/magefile.go index 441c227..e8e7721 100644 --- a/magefile.go +++ b/magefile.go @@ -4,125 +4,123 @@ package main import ( - "bytes" "fmt" "io/ioutil" "os" "path/filepath" "unicode" + "unicode/utf8" "github.com/magefile/mage/mg" "github.com/magefile/mage/sh" + "github.com/xeipuuv/gojsonschema" ) const ( zipName = "DigitalStorageTweaks.zip" contentDir = "./ContentLib" pluginFile = "./DigitalStorageTweaks.uplugin" - targetDirs = "Windows WindowsServer LinuxServer" ) -var Default = Package +// Default target +var Default = Build -// Package creates the distribution zip file +// Build runs the full pipeline +func Build() { + mg.SerialDeps(Validate, Package) +} + +// Package creates the distribution zip func Package() error { - mg.Deps(SanitizeContent) - defer Clean(false) // Clean temp dirs but keep zip + fmt.Println("Packaging files...") - fmt.Println("Creating target directories...") + // Create target directories for _, dir := range []string{"Windows", "WindowsServer", "LinuxServer"} { if err := os.MkdirAll(dir, 0755); err != nil { - return fmt.Errorf("failed to create directory %s: %v", dir, err) + return fmt.Errorf("creating %s: %w", dir, err) } - - fmt.Printf("Copying files to %s...\n", dir) if err := sh.Run("cp", "-r", contentDir, pluginFile, dir+"/"); err != nil { - return fmt.Errorf("failed to copy files to %s: %v", dir, err) + return fmt.Errorf("copying to %s: %w", dir, err) } } - fmt.Println("Creating zip archive...") - return sh.Run("7z", "a", "-r", zipName, "Windows/", "LinuxServer/", "WindowsServer/") + // Create zip + if err := sh.Run("7z", "a", "-r", zipName, "Windows/", "LinuxServer/", "WindowsServer/"); err != nil { + return fmt.Errorf("creating zip: %w", err) + } + + // Clean temp dirs + return Clean("Windows", "WindowsServer", "LinuxServer") } -// Clean removes generated artifacts -func Clean(includeZip bool) error { - fmt.Println("Cleaning artifacts...") - paths := []string{"Windows", "WindowsServer", "LinuxServer"} - if includeZip { - paths = append(paths, zipName) - } - for _, path := range paths { - if err := sh.Rm(path); err != nil { - return err - } - } - return nil -} +// Validate checks all content files +func Validate() error { + fmt.Println("Validating files...") -// SanitizeContent cleans all text files of non-ASCII and ensures CRLF line endings -func SanitizeContent() error { - fmt.Println("Sanitizing content files...") - - // Process plugin file - if err := sanitizeFile(pluginFile); err != nil { - return fmt.Errorf("plugin file sanitization failed: %v", err) + // Check plugin file + if err := checkFile(pluginFile); err != nil { + return fmt.Errorf("plugin file: %w", err) } - // Process content directory + // Check content directory return filepath.Walk(contentDir, func(path string, info os.FileInfo, err error) error { if err != nil || info.IsDir() { return err } - - // Skip binary files - switch filepath.Ext(path) { - case ".png", ".jpg", ".jpeg", ".bmp", ".gif", ".dds", ".tga", ".psd", ".fbx", ".uasset", ".umap": - return nil - default: - return sanitizeFile(path) - } + return checkFile(path) }) } -func sanitizeFile(path string) error { - content, err := ioutil.ReadFile(path) +func checkFile(path string) error { + // Skip binary files + switch filepath.Ext(path) { + case ".png", ".jpg", ".jpeg", ".bmp", ".gif", ".dds", ".tga", ".psd", ".fbx", ".uasset", ".umap": + return nil + case ".json": + return validateJSON(path) + default: + return validateEncoding(path) + } +} + +func validateJSON(path string) error { + schemaLoader := gojsonschema.NewReferenceLoader("https://raw.githubusercontent.com/budak7273/ContentLib_Documentation/main/JsonSchemas/CL_Recipe.json") + documentLoader := gojsonschema.NewReferenceLoader("file:///" + filepath.ToSlash(path)) + + result, err := gojsonschema.Validate(schemaLoader, documentLoader) if err != nil { - return fmt.Errorf("failed to read %s: %v", path, err) + return fmt.Errorf("schema validation failed: %w", err) } - // First fix any encoding issues by converting to valid UTF-8 - content = bytes.ToValidUTF8(content, []byte{}) - - // Remove non-ASCII characters but preserve standard whitespace - cleanContent := bytes.Map(func(r rune) rune { - switch { - case r > unicode.MaxASCII: - return -1 // Remove non-ASCII - case r == '\t', r == '\n', r == '\r': - return r // Keep standard whitespace - case r < 32 || r == 127: - return -1 // Remove control characters - default: - return r // Keep regular ASCII - } - }, content) - - // Normalize line endings to CRLF - cleanContent = bytes.ReplaceAll(cleanContent, []byte("\r\n"), []byte("\n")) - cleanContent = bytes.ReplaceAll(cleanContent, []byte("\n"), []byte("\r\n")) - - // Only write back if changes were made - if !bytes.Equal(content, cleanContent) { - fmt.Printf("Sanitizing %s\n", path) - fileInfo, err := os.Stat(path) - if err != nil { - return fmt.Errorf("failed to get file info for %s: %v", path, err) - } - if err := ioutil.WriteFile(path, cleanContent, fileInfo.Mode()); err != nil { - return fmt.Errorf("failed to write %s: %v", path, err) - } + if !result.Valid() { + return fmt.Errorf("invalid JSON schema: %v", result.Errors()) + } + return nil +} + +func validateEncoding(path string) error { + content, err := ioutil.ReadFile(path) + if err != nil { + return err + } + + // Check for non-ASCII + for i := 0; i < len(content); i++ { + if content[i] > unicode.MaxASCII { + r, _ := utf8.DecodeRune(content[i:]) + return fmt.Errorf("non-ASCII character %U at position %d", r, i) + } + } + return nil +} + +// Clean removes all build artifacts +func Clean(list ...string) error { + fmt.Println("Cleaning up...") + for _, f := range list { + if err := os.RemoveAll(f); err != nil { + return fmt.Errorf("failed to remove %s: %w", f, err) + } } - return nil }