From 7c7eb4dcc006488ccce5a339aa1bc2200b340b81 Mon Sep 17 00:00:00 2001 From: vickydotbat Date: Thu, 2 Apr 2026 20:41:48 +0200 Subject: [PATCH] User-Friendliness --- internal/app/app.go | 48 +++++++++++++++++++++++++++++++------- internal/pipeline/build.go | 36 +++++++++++++++++++++++++++- 2 files changed, 74 insertions(+), 10 deletions(-) diff --git a/internal/app/app.go b/internal/app/app.go index f5467be..7da076a 100644 --- a/internal/app/app.go +++ b/internal/app/app.go @@ -6,6 +6,7 @@ import ( "io" "os" "path/filepath" + "slices" "strings" "gitea.westgate.pw/ShadowsOverWestgate/sow-tools/internal/pipeline" @@ -133,7 +134,9 @@ func runBuildModule(ctx context) error { return err } - result, err := pipeline.BuildModule(p) + result, err := pipeline.BuildModuleWithProgress(p, func(message string) { + fmt.Fprintf(ctx.stdout, "[build-module] %s\n", message) + }) if err != nil { return err } @@ -150,7 +153,9 @@ func runBuildHAKs(ctx context) error { return err } - result, err := pipeline.BuildHAKs(p) + result, err := pipeline.BuildHAKsWithProgress(p, func(message string) { + fmt.Fprintf(ctx.stdout, "[build-haks] %s\n", message) + }) if err != nil { return err } @@ -195,10 +200,9 @@ func runValidate(ctx context) error { validationReport := validator.ValidateProject(p) if validationReport.HasErrors() { + emitValidationWarnings(ctx.stderr, validationReport.Diagnostics) for _, diagnostic := range validationReport.Diagnostics { if diagnostic.Severity == validator.SeverityWarning { - fprintfTarget := ctx.stderr - fmt.Fprintf(fprintfTarget, "warning: %s: %s\n", diagnostic.Path, diagnostic.Message) continue } fmt.Fprintf(ctx.stderr, "error: %s: %s\n", diagnostic.Path, diagnostic.Message) @@ -206,11 +210,7 @@ func runValidate(ctx context) error { return fmt.Errorf("validation failed with %d error(s)", validationReport.ErrorCount()) } - for _, diagnostic := range validationReport.Diagnostics { - if diagnostic.Severity == validator.SeverityWarning { - fmt.Fprintf(ctx.stderr, "warning: %s: %s\n", diagnostic.Path, diagnostic.Message) - } - } + emitValidationWarnings(ctx.stderr, validationReport.Diagnostics) inventoryReport := p.Inventory.Report() fmt.Fprintf(ctx.stdout, "project: %s\n", p.Config.Module.Name) @@ -226,6 +226,36 @@ func runValidate(ctx context) error { return nil } +func emitValidationWarnings(w io.Writer, diagnostics []validator.Diagnostic) { + const lowercaseWarning = "resource filenames should be lowercase" + + lowercasePaths := make([]string, 0) + for _, diagnostic := range diagnostics { + if diagnostic.Severity != validator.SeverityWarning { + continue + } + if diagnostic.Message == lowercaseWarning { + lowercasePaths = append(lowercasePaths, diagnostic.Path) + continue + } + fmt.Fprintf(w, "warning: %s: %s\n", diagnostic.Path, diagnostic.Message) + } + + if len(lowercasePaths) == 0 { + return + } + slices.Sort(lowercasePaths) + examples := lowercasePaths + if len(examples) > 5 { + examples = examples[:5] + } + message := strings.Join(examples, ", ") + if len(lowercasePaths) > len(examples) { + message += fmt.Sprintf(", and %d more", len(lowercasePaths)-len(examples)) + } + fmt.Fprintf(w, "warning: %d resource filenames are not lowercase: %s\n", len(lowercasePaths), message) +} + func runCompare(ctx context) error { p, err := loadProject(ctx.cwd) if err != nil { diff --git a/internal/pipeline/build.go b/internal/pipeline/build.go index b951427..115f446 100644 --- a/internal/pipeline/build.go +++ b/internal/pipeline/build.go @@ -52,6 +52,8 @@ type hakChunk struct { Size int64 } +type ProgressFunc func(string) + func Build(p *project.Project) (BuildResult, error) { moduleResult, err := BuildModule(p) if err != nil { @@ -68,15 +70,26 @@ func Build(p *project.Project) (BuildResult, error) { } func BuildModule(p *project.Project) (BuildResult, error) { + return buildModule(p, nil) +} + +func BuildModuleWithProgress(p *project.Project, progress ProgressFunc) (BuildResult, error) { + return buildModule(p, progress) +} + +func buildModule(p *project.Project, progress ProgressFunc) (BuildResult, error) { + progressf(progress, "Validating project...") if err := validateForBuild(p); err != nil { return BuildResult{}, err } + progressf(progress, "Collecting module resources...") moduleResources, err := collectModuleResources(p, nil) if err != nil { return BuildResult{}, err } + progressf(progress, "Writing module archive...") outputPath := filepath.Join(p.BuildDir(), p.Config.Module.ResRef+".mod") output, err := os.Create(outputPath) if err != nil { @@ -95,14 +108,25 @@ func BuildModule(p *project.Project) (BuildResult, error) { } func BuildHAKs(p *project.Project) (BuildResult, error) { + return buildHAKs(p, nil) +} + +func BuildHAKsWithProgress(p *project.Project, progress ProgressFunc) (BuildResult, error) { + return buildHAKs(p, progress) +} + +func buildHAKs(p *project.Project, progress ProgressFunc) (BuildResult, error) { + progressf(progress, "Validating project...") if err := validateForBuild(p); err != nil { return BuildResult{}, err } + progressf(progress, "Collecting asset resources...") assetResources, err := collectAssetResources(p) if err != nil { return BuildResult{}, err } + progressf(progress, "Cleaning previous generated HAKs...") if err := cleanupGeneratedHAKs(p.BuildDir(), p.Config.Module.ResRef); err != nil { return BuildResult{}, err } @@ -112,10 +136,12 @@ func BuildHAKs(p *project.Project) (BuildResult, error) { return result, nil } + progressf(progress, "Planning HAK chunks...") chunks, err := planHAKChunks(p, assetResources) if err != nil { return BuildResult{}, err } + progressf(progress, "Resolving module HAK order...") moduleHakOrder, err := resolveModuleHAKOrder(p, chunks) if err != nil { return BuildResult{}, err @@ -125,7 +151,8 @@ func BuildHAKs(p *project.Project) (BuildResult, error) { ModuleHAKs: moduleHakOrder, HAKs: make([]BuildManifestHAK, 0, len(chunks)), } - for _, chunk := range chunks { + for index, chunk := range chunks { + progressf(progress, fmt.Sprintf("Writing HAK %d/%d: %s (%d assets)", index+1, len(chunks), chunk.Name, len(chunk.Assets))) hakPath := filepath.Join(p.BuildDir(), chunk.Name+".hak") hakOutput, err := os.Create(hakPath) if err != nil { @@ -154,6 +181,7 @@ func BuildHAKs(p *project.Project) (BuildResult, error) { }) } + progressf(progress, "Writing HAK manifest...") manifestPath := filepath.Join(p.BuildDir(), "haks.json") manifestBytes, err := json.MarshalIndent(manifest, "", " ") if err != nil { @@ -167,6 +195,12 @@ func BuildHAKs(p *project.Project) (BuildResult, error) { return result, nil } +func progressf(progress ProgressFunc, message string) { + if progress != nil { + progress(message) + } +} + func collectModuleResources(p *project.Project, moduleHakOrder []string) ([]erf.Resource, error) { var moduleResources []erf.Resource