diff --git a/Cargo.toml b/Cargo.toml index 82d7feb..0616757 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,8 +15,8 @@ log = "0.4" env_logger = "0.11" thiserror = "2.0" serde_json = "1.0" -indexmap = { version = "2.13", features = ["serde"] } -minijinja = { version = "2.18", features = [ +indexmap = { version = "2.14", features = ["serde"] } +minijinja = { version = "2.19", features = [ "builtins", "loop_controls", "loader", @@ -37,10 +37,13 @@ openssl = { version = "0.10", features = ["vendored"] } libz-sys = { version = "1.1", features = ["static"] } regex = "1.12" cruet = "1.0" +sha2 = "0.10" +hex = "0.4" +chrono = { version = "0.4", features = ["serde"] } +tempfile = "3.27" [dev-dependencies] dir-diff = "0.3" -tempfile = "3.27" test-log = { version = "0.2", features = ["trace", "color"] } testcontainers = { version = "0.27", features = ["blocking"] } reqwest = { version = "0.13", features = ["blocking", "json"] } diff --git a/README.md b/README.md index 691ebfe..446c5f3 100644 --- a/README.md +++ b/README.md @@ -21,6 +21,10 @@ - [Non-Interactive Mode](#non-interactive-mode) - [Conditional Questions](#conditional-questions) - [Debugging Templates](#debugging-templates) +- [Updating a Generated Project](#updating-a-generated-project) + - [How update works](#how-update-works) + - [Conflict Markers](#conflict-markers) + - [Keeping answers up to date](#keeping-answers-up-to-date) - [Hooks](#hooks) - [Customizing Hook Filenames](#customizing-hook-filenames) - [Customizing Hook Runners](#customizing-hook-runners) @@ -114,7 +118,7 @@ If a symlink points to a file it will be duplicated as a regular file. Symlinks As a quick start, you can run the following command to generate a project: ``` -baker examples/demo my-project +baker generate examples/demo my-project ``` Each component of this template is described in detail below. @@ -376,7 +380,7 @@ Default answers can be provided using the `--answers` option. ```bash # Alternatively, use --answers='{"name": "John"}' -echo '{"name": "John"}' | baker template my-project --answers=- +echo '{"name": "John"}' | baker generate template my-project --answers=- ``` ```yaml @@ -398,7 +402,7 @@ What is your name? [John]: For fully automated workflows like CI/CD pipelines, you can combine `--answers` with the `--non-interactive` flag to completely skip all prompts: ```bash -baker template my-project --answers='{"project_name": "Example Project"}' --non-interactive +baker generate template my-project --answers='{"project_name": "Example Project"}' --non-interactive ``` In `--non-interactive` mode, Baker determines whether to skip user prompts based on two factors: @@ -433,7 +437,7 @@ questions: And you run: ```bash -baker template my-project --answers='{"project_name": "Example"}' --non-interactive +baker generate template my-project --answers='{"project_name": "Example"}' --non-interactive ``` Baker will automatically use "Example" for `project_name`, "Anonymous" for `project_author` (from the default value), and `true` for `use_tests` (from the default value). @@ -479,7 +483,7 @@ questions: When you run the template, the `debug()` function will output the current context: ``` -baker example out +baker generate example out What is your name?: aaa Hello, aaa. What is your last name?: bbb State { @@ -512,6 +516,77 @@ State { This output provides a detailed view of the current context, including defined variables, their values, and available functions, helping you troubleshoot and debug your templates effectively. +## Updating a Generated Project + +When a template evolves after you have already generated a project from it, you can bring the +generated project up-to-date with `baker update` instead of regenerating from scratch. + +After every `baker generate` run, Baker writes a `.baker-generated.yaml` file into the output +directory. This file stores: + +- The template source (local path + SHA-256 content hash, or Git URL + commit SHA + optional tag) +- All answers collected during generation +- The generation timestamp + +### How update works + +1. Run `baker generate` as usual — this creates the project and the `.baker-generated.yaml` file. +2. Later, when the template has changed, `cd` into the generated project directory and run: + + ```bash + baker update + ``` + +3. Baker reads `.baker-generated.yaml`, re-fetches the template, and compares its hash (local) or + HEAD commit (git) with the stored value. +4. If nothing has changed it exits immediately — nothing to do. +5. If the template has changed, Baker re-renders every template file using the saved answers. + +### Conflict Markers + +Baker cannot know whether you have edited a generated file after generation. To be safe, whenever +the newly-rendered content of a file differs from what is on disk, Baker writes **git-style +conflict markers** into the file instead of silently overwriting it: + +``` +<<<<<<< current +Content that was on disk (possibly with your local edits) +======= +Newly rendered content from the updated template +>>>>>>> updated +``` + +Resolve each conflict as you would after a `git merge`, then remove the marker lines. If a file's +on-disk content is already identical to the newly-rendered content, Baker skips it silently. + +Binary files (non-text) that need updating are written alongside the original as +`.baker-updated` instead of overwriting or adding text markers. + +### Keeping answers up to date + +By default, `baker update` **reuses all answers** from `.baker-generated.yaml`. If the template +has added new questions since the last generation, Baker will prompt you for them interactively +(or use their defaults when `--non-interactive` is set). + +You can override individual answers at update time: + +```bash +# Override a single answer +baker update --answers='{"project_name": "NewName"}' + +# Load overrides from a file +baker update --answers-file=overrides.json +``` + +The `--generated-file` flag (or `generated_file_name` in `baker.yaml`) lets you customise the +name of the metadata file if you prefer something other than `.baker-generated.yaml`. + +```bash +baker generate my-template my-project --generated-file=.baker-meta.yaml +cd my-project +baker update --generated-file=.baker-meta.yaml +``` + ## Hooks Hooks are useful for performing routine tasks before (pre-hook) or after (post-hook) project generation. @@ -1233,7 +1308,8 @@ Baker provides a set of built-in filters and functions to enhance the flexibilit | 🟢 **Platform-specific hooks** | ✅ Use `{{platform.family}}/pre` etc. for OS-aware logic | ❌ | ⚠️ Limited via Rhai | ❌ | ❌ | ⚠️ Custom logic required | | 🟢 **CI/CD-friendly answers piping** | ✅ `--answers=-` or echo JSON into CLI | ❌ | ⚠️ Partial | ✅ Via pre-filled YAML | ⚠️ `--no-input` only | ❌ Manual scripting | | 🟢 **Lightweight & Fast** | ✅ Rust binary, no runtime dependencies | ✅ Rust binary | ✅ Rust binary | ❌ Requires Python | ❌ Requires Python | ❌ Requires Node.js | -| 🟢 **Simple CLI Interface** | ✅ `baker