From b42f1476a1fea564e84f714713b09277761fc951 Mon Sep 17 00:00:00 2001 From: Leynos Date: Sat, 12 Jul 2025 19:00:55 +0100 Subject: [PATCH 1/3] Add phony and always target flags --- docs/netsuke-design.md | 42 ++++++++++++++++++++++++++++++++++++------ docs/roadmap.md | 3 +++ 2 files changed, 39 insertions(+), 6 deletions(-) diff --git a/docs/netsuke-design.md b/docs/netsuke-design.md index 711d696d..04938287 100644 --- a/docs/netsuke-design.md +++ b/docs/netsuke-design.md @@ -146,6 +146,12 @@ top-level keys. YAML `|` block style. Netsuke registers these macros in the template environment before rendering other sections. +- `phony`: When set to `true`, the target runs when explicitly requested even if + a file with the same name exists. The default value is `false`. + +- `always`: When set to `true`, the target runs on every invocation regardless + of timestamps or dependencies. The default value is `false`. + - `rules`: A list of rule definitions. Each rule is a reusable template for a command, analogous to a Ninja `rule` block.2 @@ -153,6 +159,9 @@ top-level keys. the sources it depends on, and the rule used to produce it. This corresponds to a Ninja `build` statement.3 +- `actions`: A secondary list of build targets. Any target placed here is + treated as `{ phony: true, always: false }` by default. + - `defaults`: An optional list of target names to be built when Netsuke is invoked without any specific targets on the command line. This maps directly to Ninja's `default` target statement.3 @@ -179,7 +188,9 @@ Each entry in the `rules` list is a mapping that defines a command template. ### 2.4 Defining `targets` Each entry in the `targets` list is a mapping that defines a build edge in the -dependency graph. +dependency graph. Targets may also be placed in an optional `actions` list. +Doing so is a shorthand for adding them to `targets` with `phony` set to `true` +and `always` left at its default `false`. - `name`: The primary output file or files for this build step. This can be a single string or a list of strings. @@ -302,6 +313,9 @@ pub struct NetsukeManifest { #[serde(default)] pub rules: Vec, + #[serde(default)] + pub actions: Vec, + pub targets: Vec, #[serde(default)] @@ -336,6 +350,12 @@ pub struct Target { #[serde(default)] pub vars: HashMap, + + #[serde(default)] + pub phony: bool, + + #[serde(default)] + pub always: bool, } /// An enum to handle fields that can be either a single string or a list of strings. @@ -632,6 +652,12 @@ pub struct BuildEdge { /// Dependencies that must be built first but do not trigger a rebuild on change. /// Maps to Ninja's '||' syntax. pub order_only_deps: Vec, + + /// Run this edge when requested even if the output file already exists. + pub phony: bool, + + /// Run this edge on every invocation regardless of timestamps. + pub always: bool, } ``` @@ -646,13 +672,15 @@ This transformation involves several steps: stored in the `BuildGraph`'s `actions` map, keyed by a hash of their contents to automatically deduplicate identical rules. -2. **Target Expansion:** Iterate through the `manifest.targets`. For each target - in the AST, resolve all strings into `PathBuf`s and resolve all dependency - names against other targets. +2. **Target Expansion:** Iterate through the `manifest.targets` and the optional + `manifest.actions`. Entries in `actions` are treated identically to targets + but with `phony` defaulting to `true`. For each item, resolve all strings + into `PathBuf`s and resolve all dependency names against other targets. 3. **Edge Creation:** For each AST target, create an `ir::BuildEdge` object. - This involves linking it to the appropriate `ir::Action` (by its ID), and - populating its input and output vectors. + This involves linking it to the appropriate `ir::Action` (by its ID), + transferring the `phony` and `always` flags, and populating its input and + output vectors. 4. **Graph Validation:** As the graph is constructed, perform validation checks. This includes ensuring that every rule referenced by a target exists in the @@ -693,6 +721,8 @@ structures to the Ninja file syntax. `ir::BuildEdge`, write a corresponding Ninja `build` statement. This involves formatting the lists of explicit outputs, implicit outputs, inputs, and order-only dependencies using the correct Ninja syntax (`:`, `|`, and `||`).7 + If `phony` is `true`, use Ninja's built-in `phony` rule. If `always` is + `true`, append the `-t run` invocation so the command executes every time. Code snippet diff --git a/docs/roadmap.md b/docs/roadmap.md index cfa2de1b..307cc1ba 100644 --- a/docs/roadmap.md +++ b/docs/roadmap.md @@ -19,6 +19,9 @@ compilation pipeline from parsing to execution. - [ ] Annotate the AST structs with `#[derive(Deserialize)]` and `#[serde(deny_unknown_fields)]` to enable parsing. + - [ ] Support `phony` and `always` boolean flags on targets and parse an + optional `actions` list that treats each entry as a `phony` target. + - [ ] Implement the YAML parsing logic using `serde_yaml` to deserialize a static `Netsuke.yml` file into the `NetsukeManifest` AST. From 23ed4573532e3f0c340626a304ffafecbdaf08c7 Mon Sep 17 00:00:00 2001 From: Leynos Date: Sat, 12 Jul 2025 19:06:03 +0100 Subject: [PATCH 2/3] Clarify phony and always target options --- docs/netsuke-design.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/netsuke-design.md b/docs/netsuke-design.md index 04938287..d3422c4d 100644 --- a/docs/netsuke-design.md +++ b/docs/netsuke-design.md @@ -146,12 +146,6 @@ top-level keys. YAML `|` block style. Netsuke registers these macros in the template environment before rendering other sections. -- `phony`: When set to `true`, the target runs when explicitly requested even if - a file with the same name exists. The default value is `false`. - -- `always`: When set to `true`, the target runs on every invocation regardless - of timestamps or dependencies. The default value is `false`. - - `rules`: A list of rule definitions. Each rule is a reusable template for a command, analogous to a Ninja `rule` block.2 @@ -221,6 +215,12 @@ and `always` left at its default `false`. YAML `|` block style. Netsuke registers these macros in the template environment before rendering other sections. +- `phony`: When set to `true`, the target runs when explicitly requested even if + a file with the same name exists. The default value is `false`. + +- `always`: When set to `true`, the target runs on every invocation regardless + of timestamps or dependencies. The default value is `false`. + ### 2.5 Generated Targets with `foreach` Large sets of similar outputs can clutter a manifest when written individually. From b652aa3ec8f4f3c63649cee6502163da310a3ec5 Mon Sep 17 00:00:00 2001 From: Leynos Date: Sat, 12 Jul 2025 20:19:34 +0100 Subject: [PATCH 3/3] Update phony docs --- docs/netsuke-design.md | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/docs/netsuke-design.md b/docs/netsuke-design.md index d3422c4d..bcbe3028 100644 --- a/docs/netsuke-design.md +++ b/docs/netsuke-design.md @@ -181,10 +181,8 @@ Each entry in the `rules` list is a mapping that defines a command template. ### 2.4 Defining `targets` -Each entry in the `targets` list is a mapping that defines a build edge in the -dependency graph. Targets may also be placed in an optional `actions` list. -Doing so is a shorthand for adding them to `targets` with `phony` set to `true` -and `always` left at its default `false`. +Each entry in `targets` defines a build edge; placing a target in the optional +`actions` list instead marks it as `phony: true` with `always` left `false`. - `name`: The primary output file or files for this build step. This can be a single string or a list of strings. @@ -351,9 +349,11 @@ pub struct Target { #[serde(default)] pub vars: HashMap, + /// Run this target when requested even if a file with the same name exists. #[serde(default)] pub phony: bool, + /// Run this target on every invocation regardless of timestamps. #[serde(default)] pub always: bool, } @@ -635,7 +635,9 @@ pub struct Action { } /// Represents a single build statement, analogous to a Ninja 'build' edge. -/// It connects a set of inputs to a set of outputs via an Action. +/// It connects a set of inputs to a set of outputs via an Action. The `phony` +/// and `always` flags control execution when outputs already exist or when +/// timestamps would normally skip the step. pub struct BuildEdge { /// The unique identifier of the Action used for this edge. pub action_id: String, @@ -721,8 +723,10 @@ structures to the Ninja file syntax. `ir::BuildEdge`, write a corresponding Ninja `build` statement. This involves formatting the lists of explicit outputs, implicit outputs, inputs, and order-only dependencies using the correct Ninja syntax (`:`, `|`, and `||`).7 - If `phony` is `true`, use Ninja's built-in `phony` rule. If `always` is - `true`, append the `-t run` invocation so the command executes every time. + Use Ninja's built-in `phony` rule when `phony` is `true`. For an `always` + edge, either generate a `phony` build with no outputs or emit a dummy output + marked `restat = 1` and depend on a permanently dirty target so the command + runs on each invocation. Code snippet