diff --git a/embed/embed.go b/embed/embed.go new file mode 100644 index 0000000..0cae6e2 --- /dev/null +++ b/embed/embed.go @@ -0,0 +1,7 @@ +package embed + +import "embed" + +//go:embed templates/*.tmpl templates/**/* +var Templates embed.FS + diff --git a/templates/.envrc.tmpl b/embed/templates/.envrc.tmpl similarity index 100% rename from templates/.envrc.tmpl rename to embed/templates/.envrc.tmpl diff --git a/templates/README.md.tmpl b/embed/templates/README.md.tmpl similarity index 100% rename from templates/README.md.tmpl rename to embed/templates/README.md.tmpl diff --git a/templates/cmd/root.go.tmpl b/embed/templates/cmd/root.go.tmpl similarity index 100% rename from templates/cmd/root.go.tmpl rename to embed/templates/cmd/root.go.tmpl diff --git a/templates/cmd/version.go.tmpl b/embed/templates/cmd/version.go.tmpl similarity index 100% rename from templates/cmd/version.go.tmpl rename to embed/templates/cmd/version.go.tmpl diff --git a/templates/config/config.go.tmpl b/embed/templates/config/config.go.tmpl similarity index 98% rename from templates/config/config.go.tmpl rename to embed/templates/config/config.go.tmpl index 66e4d2c..7167440 100644 --- a/templates/config/config.go.tmpl +++ b/embed/templates/config/config.go.tmpl @@ -1,7 +1,6 @@ package config import ( - "fmt" "github.com/spf13/viper" "{{.ModName}}/internal/logger" ) diff --git a/templates/flake.nix.tmpl b/embed/templates/flake.nix.tmpl similarity index 100% rename from templates/flake.nix.tmpl rename to embed/templates/flake.nix.tmpl diff --git a/templates/go.mod.tmpl b/embed/templates/go.mod.tmpl similarity index 100% rename from templates/go.mod.tmpl rename to embed/templates/go.mod.tmpl diff --git a/templates/go.sum.tmpl b/embed/templates/go.sum.tmpl similarity index 100% rename from templates/go.sum.tmpl rename to embed/templates/go.sum.tmpl diff --git a/templates/internal/logger/logger.go.tmpl b/embed/templates/internal/logger/logger.go.tmpl similarity index 100% rename from templates/internal/logger/logger.go.tmpl rename to embed/templates/internal/logger/logger.go.tmpl diff --git a/templates/justfile.tmpl b/embed/templates/justfile.tmpl similarity index 100% rename from templates/justfile.tmpl rename to embed/templates/justfile.tmpl diff --git a/templates/main.go.tmpl b/embed/templates/main.go.tmpl similarity index 100% rename from templates/main.go.tmpl rename to embed/templates/main.go.tmpl diff --git a/templates/tui/model.go.tmpl b/embed/templates/tui/model.go.tmpl similarity index 100% rename from templates/tui/model.go.tmpl rename to embed/templates/tui/model.go.tmpl diff --git a/templates/tui/run.go.tmpl b/embed/templates/tui/run.go.tmpl similarity index 100% rename from templates/tui/run.go.tmpl rename to embed/templates/tui/run.go.tmpl diff --git a/templates/tui/update.go.tmpl b/embed/templates/tui/update.go.tmpl similarity index 100% rename from templates/tui/update.go.tmpl rename to embed/templates/tui/update.go.tmpl diff --git a/templates/tui/view.go.tmpl b/embed/templates/tui/view.go.tmpl similarity index 100% rename from templates/tui/view.go.tmpl rename to embed/templates/tui/view.go.tmpl diff --git a/flake.nix b/flake.nix index c47b7fe..81207eb 100644 --- a/flake.nix +++ b/flake.nix @@ -39,7 +39,7 @@ default = pkgs.callPackage ( { buildGoModule }: buildGoModule { - pname = "wand-templater"; + pname = "bubblewand"; version = "0.0.1"; src = builtins.path { name = "source"; diff --git a/internal/render/render.go b/internal/render/render.go index 4eea7c2..730a867 100644 --- a/internal/render/render.go +++ b/internal/render/render.go @@ -1,71 +1,100 @@ package render import ( - "os" - "path/filepath" - "strings" - "text/template" - "specCon18/bubblewand/internal/logger" + "io/fs" + "os" + "path/filepath" + "strings" + "text/template" + + "specCon18/bubblewand/embed" // Import embedded template files + "specCon18/bubblewand/internal/logger" // Import logger for logging output ) -// ProgramData holds user-supplied template values +// ProgramData holds user-supplied values for template substitution. type ProgramData struct { - ModName string - PackageName string - ProgramVersion string - ProgramDesc string - OutputDir string + ModName string // Module name + PackageName string // Go package name + ProgramVersion string // Version string + ProgramDesc string // Description of the program + OutputDir string // Target output directory for rendered files } -// RenderTemplates renders all .tmpl files from the templates/ directory into outputDir +// RenderTemplates renders embedded .tmpl files into outputDir func RenderTemplates(data ProgramData, outputDir string, verbose bool) error { - var renderedFiles int + var renderedFiles int // Count of successfully rendered files - err := filepath.Walk("templates", func(path string, info os.FileInfo, err error) error { - if err != nil { - return err - } - if info.IsDir() || !strings.HasSuffix(info.Name(), ".tmpl") { - return nil - } + // Walk through the embedded templates filesystem starting at "templates" + err := fs.WalkDir(embed.Templates, "templates", func(path string, d fs.DirEntry, err error) error { + if err != nil { + // Log and return error encountered while walking the filesystem + logger.Log.Errorf("Error walking path %q: %v", path, err) + return err + } - relPath, err := filepath.Rel("templates", path) - if err != nil { - return err - } - outputPath := filepath.Join(outputDir, strings.TrimSuffix(relPath, ".tmpl")) + // Skip directories and files that do not end with ".tmpl" + if d.IsDir() || !strings.HasSuffix(d.Name(), ".tmpl") { + return nil + } - if err := os.MkdirAll(filepath.Dir(outputPath), 0755); err != nil { - return err - } + // Strip the "templates/" prefix from path and remove ".tmpl" extension + relPath := strings.TrimPrefix(path, "templates/") + outputPath := filepath.Join(outputDir, strings.TrimSuffix(relPath, ".tmpl")) - tmpl, err := template.ParseFiles(path) - if err != nil { - return err - } + // Ensure the parent directory for the output file exists + if err := os.MkdirAll(filepath.Dir(outputPath), 0755); err != nil { + logger.Log.Errorf("Failed to create directory for %s: %v", outputPath, err) + return err + } - outFile, err := os.Create(outputPath) - if err != nil { - return err - } - defer outFile.Close() + // Read the embedded template file + tmplBytes, err := embed.Templates.ReadFile(path) + if err != nil { + logger.Log.Errorf("Failed to read template %s: %v", path, err) + return err + } - if verbose { - logger.Log.Infof("Rendering %s → %s", path, outputPath) - } + // Parse the template content + tmpl, err := template.New(d.Name()).Parse(string(tmplBytes)) + if err != nil { + logger.Log.Errorf("Failed to parse template %s: %v", path, err) + return err + } - renderedFiles++ - return tmpl.Execute(outFile, data) - }) + // Create the output file for writing the rendered content + outFile, err := os.Create(outputPath) + if err != nil { + logger.Log.Errorf("Failed to create output file %s: %v", outputPath, err) + return err + } + defer outFile.Close() - if err != nil { - return err - } + // Log the render operation if verbose mode is enabled + if verbose { + logger.Log.Infof("Rendering %s → %s", path, outputPath) + } - if !verbose && renderedFiles > 0 { - logger.Log.Info("Rendering templates") - } + // Execute the template using the provided data and write to file + if err := tmpl.Execute(outFile, data); err != nil { + logger.Log.Errorf("Failed to execute template %s: %v", path, err) + return err + } - return nil + renderedFiles++ + return nil + }) + + // If any error occurred during the walk/render process, log and return it + if err != nil { + logger.Log.Errorf("Template rendering failed: %v", err) + return err + } + + // If not verbose and at least one file was rendered, print a summary log + if !verbose && renderedFiles > 0 { + logger.Log.Info("Rendering templates") + } + + return nil // Success }