Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions examples/book.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
netsuke_version: "1.0"

vars:
outdir: build/book

rules:
- name: build
command: "mkdir -p $(dirname {outs}) && pandoc {ins} -o {outs}"
description: Compile document

Comment on lines +7 to +10
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick (assertive)

Expose PDF engine selection
Permit authors to tweak the output engine without editing the rule. Pipe an optional pdf_engine var through to pandoc.

-    command: "mkdir -p $(dirname {outs}) && pandoc {ins} -o {outs}"
+    command: "mkdir -p $(dirname {outs}) && pandoc {ins} -o {outs} {{ pdf_engine | default('') }}"

Add to vars:

  pdf_engine: "--pdf-engine=xelatex"
🤖 Prompt for AI Agents
In examples/book.yml around lines 7 to 10, the pandoc command does not allow
selecting the PDF engine dynamically. Modify the command to include an optional
pdf_engine variable by adding it to the vars section as pdf_engine:
"--pdf-engine=xelatex" and update the command to append {pdf_engine} so authors
can specify the PDF engine without editing the rule directly.

targets:
- name: "{{ outdir }}/manuscript.pdf"
rule: build
sources: "{{ glob('chapters/*.md') }}"
Comment thread
leynos marked this conversation as resolved.

defaults:
- "{{ outdir }}/manuscript.pdf"
32 changes: 32 additions & 0 deletions examples/c_app.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
netsuke_version: "1.0"

vars:
cc: gcc
cflags: -Wall
objdir: build/obj

rules:
- name: compile
command: "mkdir -p $(dirname {outs}) && {{ cc }} {{ cflags }} -c {ins} -o {outs}"
description: Compile C source
- name: link
command: "{{ cc }} {{ cflags }} {ins} -o {outs}"
description: Link objects

# Target list generated from source files

targets: |
{% for src in glob('src/*.c') %}
- name: "{{ objdir }}/{{ src | basename | replace('.c', '.o') }}"
rule: compile
sources: "{{ src }}"
{% endfor %}
- name: app
Comment on lines +18 to +24
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

Verify that Netsuke re-parses the templated target list
Wrapping the Jinja loop inside a literal block (|) removes YAML-lint errors, but it also turns targets into a scalar string. Netsuke must post-process that string into real YAML; otherwise the build graph will be empty.

Run:

Ensure the runtime Jinja pass writes a second-stage YAML that Netsuke loads.


🏁 Script executed:

#!/bin/bash
# Expect: 'targets' key in the rendered YAML is an array, not a string.
grep -nA2 -B2 '^targets:' examples/c_app.yml

Length of output: 218


Run a Jinja render simulation to verify the targets type:


🏁 Script executed:

#!/bin/bash
set -e
pip install jinja2 pyyaml
python3 - << 'EOF'
import jinja2, yaml, glob
env = jinja2.Environment()
template = open('examples/c_app.yml').read()
rendered = env.from_string(template).render(objdir='build', glob=glob)
loaded = yaml.safe_load(rendered)
print(type(loaded['targets']).__name__)
EOF

Length of output: 1103


Register missing Jinja filters and re-run the YAML load simulation:


🏁 Script executed:

#!/bin/bash
set -e
pip install jinja2 pyyaml
python3 - << 'EOF'
import jinja2, yaml, glob, os
env = jinja2.Environment()
env.filters['basename'] = os.path.basename
env.filters['replace'] = lambda s, a, b: s.replace(a, b)
template = open('examples/c_app.yml').read()
rendered = env.from_string(template).render(objdir='build', glob=glob)
loaded = yaml.safe_load(rendered)
print(type(loaded.get('targets')).__name__)
EOF

Length of output: 873


Register glob.glob correctly and re-run the YAML load test:


🏁 Script executed:

#!/bin/bash
set -e
pip install jinja2 pyyaml
python3 - << 'EOF'
import jinja2, yaml, glob, os

# Load template from examples/
env = jinja2.Environment(loader=jinja2.FileSystemLoader('examples'))
env.globals['glob'] = glob.glob
env.filters['basename'] = os.path.basename
env.filters['replace'] = lambda s, a, b: s.replace(a, b)

# Render and parse
template = env.get_template('c_app.yml').render(objdir='build')
data = yaml.safe_load(template)

# Output type of targets
print(type(data.get('targets')).__name__)
EOF

Length of output: 420


Ensure targets renders as a YAML sequence, not a string
The Jinja literal block (|) makes targets a single string (yaml.safe_load yields str). Netsuke must re-parse that block as YAML to build a graph. Remove the scalar indicator so Jinja emits a real sequence:

File: examples/c_app.yml
Lines: 18–24

- targets: |
-  {% for src in glob('src/*.c') %}
-  - name: "{{ objdir }}/{{ src | basename | replace('.c', '.o') }}"
-    rule: compile
-    sources: "{{ src }}"
-  {% endfor %}
-  - name: app
+ targets:
+ {% for src in glob('src/*.c') %}
+   - name: "{{ objdir }}/{{ src | basename | replace('.c', '.o') }}"
+     rule: compile
+     sources: "{{ src }}"
+ {% endfor %}
+   - name: app
  • Drop the | after targets:
  • Unindent the loop so each - is part of the sequence

Run yaml.safe_load on the rendered output to confirm targets is a list, not a string.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
targets: |
{% for src in glob('src/*.c') %}
- name: "{{ objdir }}/{{ src | basename | replace('.c', '.o') }}"
rule: compile
sources: "{{ src }}"
{% endfor %}
- name: app
targets:
{% for src in glob('src/*.c') %}
- name: "{{ objdir }}/{{ src | basename | replace('.c', '.o') }}"
rule: compile
sources: "{{ src }}"
{% endfor %}
- name: app
🤖 Prompt for AI Agents
In examples/c_app.yml around lines 18 to 24, the `targets` key is followed by a
literal block indicator `|` causing the entire block to be parsed as a single
string instead of a YAML sequence. To fix this, remove the `|` after `targets:`
and unindent the Jinja for-loop so that each `-` is aligned as a list item under
`targets`. After making these changes, verify by running `yaml.safe_load` on the
rendered output to ensure `targets` is parsed as a list, not a string.

rule: link
sources:
{% for src in glob('src/*.c') %}
- "{{ objdir }}/{{ src | basename | replace('.c', '.o') }}"
{% endfor %}

defaults:
- app
29 changes: 29 additions & 0 deletions examples/photo_album.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
netsuke_version: "1.0"

vars:
style: "{{ env('DT_STYLE') | default('natural') }}"
Comment thread
sourcery-ai[bot] marked this conversation as resolved.
outdir: "build/jpg/{{ style }}"

rules:
- name: develop
command: "mkdir -p $(dirname {outs}) && darktable-cli {ins} {outs} --style {{ style }}"
description: Develop RAW image

- name: thumb
command: "mkdir -p $(dirname {outs}) && convert {ins} -resize 200x200^ -gravity center -extent 200x200 {outs}"
description: Create thumbnail

targets:
{% for raw in glob('photos/*.nef') %}
- name: "{{ outdir }}/{{ raw | basename | replace('.nef', '.jpg') }}"
rule: develop
sources: "{{ raw }}"
- name: "{{ outdir }}/thumbs/{{ raw | basename | replace('.nef', '.jpg') }}"
rule: thumb
sources: "{{ outdir }}/{{ raw | basename | replace('.nef', '.jpg') }}"
{% endfor %}

defaults:
{% for raw in glob('photos/*.nef') %}
- "{{ outdir }}/thumbs/{{ raw | basename | replace('.nef', '.jpg') }}"
{% endfor %}
33 changes: 33 additions & 0 deletions examples/python_package.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
netsuke_version: "1.0"

vars:
python: python3
venv: .venv

rules:
- name: setup
command: "{{ python }} -m venv {{ venv }}"
description: Create virtual environment
Comment on lines +9 to +10
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick (assertive)

Upgrade venv tooling during creation
Add --upgrade-deps to python -m venv so the virtual environment ships with the latest pip and setuptools, avoiding old-toolchain surprises.

-    command: "{{ python }} -m venv {{ venv }}"
+    command: "{{ python }} -m venv --upgrade-deps {{ venv }}"
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
command: "{{ python }} -m venv {{ venv }}"
description: Create virtual environment
command: "{{ python }} -m venv --upgrade-deps {{ venv }}"
description: Create virtual environment
🤖 Prompt for AI Agents
In examples/python_package.yml at lines 9 to 10, the command creating the
virtual environment should include the --upgrade-deps flag to ensure the latest
pip and setuptools are installed. Modify the command to add --upgrade-deps after
python -m venv so the environment uses up-to-date tooling and avoids issues with
outdated packages.

- name: install
command: "{{ venv }}/bin/pip install -e . -r requirements.txt"
description: Install package
- name: test
command: "{{ venv }}/bin/python -m pytest {{ ins | join(' ') }}"
description: Run tests

targets:
- name: venv
rule: setup
- name: deps
rule: install
sources: requirements.txt
deps:
- venv
- name: test-results
rule: test
sources: tests
deps:
- deps

defaults:
- test-results
21 changes: 21 additions & 0 deletions examples/svg_to_png.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
netsuke_version: "1.0"

vars:
outdir: build/png

rules:
- name: rasterise
command: "mkdir -p $(dirname {outs}) && inkscape {ins} --export-type=png --export-filename={outs}"
description: Convert SVG to PNG

targets:
{% for svg in glob('assets/svg/*.svg') %}
- name: "{{ outdir }}/{{ svg | basename | replace('.svg', '.png') }}"
rule: rasterise
sources: "{{ svg }}"
{% endfor %}

defaults:
{% for svg in glob('assets/svg/*.svg') %}
- "{{ outdir }}/{{ svg | basename | replace('.svg', '.png') }}"
{% endfor %}
Comment on lines +11 to +21
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Wrap Jinja loop to restore YAML validity
{% for svg … %} lines at 12-16 and 19-21 cause the same % token error. Encapsulate the loop in a literal block.

-targets:
-{% for svg in glob('assets/svg/*.svg') %}
+targets: |
+  {% for svg in glob('assets/svg/*.svg') %}
   - name: "{{ outdir }}/{{ svg | basename | replace('.svg', '.png') }}"
     rule: rasterise
     sources: "{{ svg }}"
-{% endfor %}
+  {% endfor %}

-defaults:
-{% for svg in glob('assets/svg/*.svg') %}
-  - "{{ outdir }}/{{ svg | basename | replace('.svg', '.png') }}"
-{% endfor %}
+defaults: |
+  {% for svg in glob('assets/svg/*.svg') %}
+  - "{{ outdir }}/{{ svg | basename | replace('.svg', '.png') }}"
+  {% endfor %}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
targets:
{% for svg in glob('assets/svg/*.svg') %}
- name: "{{ outdir }}/{{ svg | basename | replace('.svg', '.png') }}"
rule: rasterise
sources: "{{ svg }}"
{% endfor %}
defaults:
{% for svg in glob('assets/svg/*.svg') %}
- "{{ outdir }}/{{ svg | basename | replace('.svg', '.png') }}"
{% endfor %}
targets: |
{% for svg in glob('assets/svg/*.svg') %}
- name: "{{ outdir }}/{{ svg | basename | replace('.svg', '.png') }}"
rule: rasterise
sources: "{{ svg }}"
{% endfor %}
defaults: |
{% for svg in glob('assets/svg/*.svg') %}
- "{{ outdir }}/{{ svg | basename | replace('.svg', '.png') }}"
{% endfor %}
🧰 Tools
🪛 YAMLlint (1.37.1)

[error] 12-12: syntax error: found character '%' that cannot start any token

(syntax)

🤖 Prompt for AI Agents
In examples/svg_to_png.yml around lines 11 to 21, the Jinja for loops are
causing YAML parsing errors due to the unescaped % tokens. To fix this, wrap
each Jinja for loop block inside a YAML literal block (using | or >) to preserve
the Jinja syntax as a literal string and restore YAML validity. This will
prevent the YAML parser from misinterpreting the Jinja syntax.