Skip to content

Commit 955bfc2

Browse files
authored
Update README.md
1 parent 6be4cf3 commit 955bfc2

File tree

1 file changed

+195
-2
lines changed

1 file changed

+195
-2
lines changed

README.md

Lines changed: 195 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,196 @@
1-
# Netsuke
1+
# 🧵 Netsuke
22

3-
This is a generated project using [Copier](https://copier.readthedocs.io/).
3+
A modern, declarative build system compiler.
4+
YAML + Jinja in, Ninja out. Nothing more. Nothing less.
5+
6+
---
7+
8+
## What is Netsuke?
9+
10+
**Netsuke** is a friendly build system that compiles structured manifests into a Ninja build graph.
11+
It’s not a shell-script runner, a meta-task framework, or a domain-specific CI layer. It’s `make`—if `make` hadn’t been invented in 1977 by people allergic to quoting rules and joy.
12+
13+
### Key properties
14+
15+
- **Declarative**: Targets, rules, and dependencies described explicitly.
16+
- **Dynamic when needed**: Jinja templating for loops, macros, conditionals, file globbing.
17+
- **Static where required**: Always compiles to a reproducible, fully static dependency graph.
18+
- **Unopinionated**: No magic for C, Rust, Python, JavaScript, or any other blessed language.
19+
- **Safe**: All variable interpolation is securely shell-escaped by default.
20+
- **Fast**: Builds executed by [Ninja](https://ninja-build.org/), the fastest graph executor we know of.
21+
22+
---
23+
24+
## Quick Example
25+
26+
```yaml
27+
netsuke_version: "1.0"
28+
29+
vars:
30+
cc: clang
31+
cflags: -Wall -Werror
32+
33+
rules:
34+
- name: compile
35+
command: "{{ cc }} {{ cflags }} -c {{ ins }} -o {{ outs }}"
36+
37+
- name: link
38+
command: "{{ cc }} {{ cflags }} {{ ins }} -o {{ outs }}"
39+
40+
targets:
41+
- foreach: glob('src/*.c')
42+
name: "build/{{ item | basename | with_suffix('.o') }}"
43+
rule: compile
44+
sources: "{{ item }}"
45+
46+
- name: app
47+
rule: link
48+
sources: "{{ glob('src/*.c') | map('basename') | map('with_suffix', '.o') }}"
49+
````
50+
51+
Yes, it’s just YAML.
52+
Yes, that’s a Jinja `foreach`.
53+
No, you don’t need to define `.PHONY` or remember what `$@` means.
54+
This is 2025. You deserve better.
55+
56+
---
57+
58+
## Key Concepts
59+
60+
### 🔨 Rules
61+
62+
Rules are reusable command templates. Each one has exactly one of:
63+
64+
* `command:` — a single shell string
65+
* `script:` — a multi-line block
66+
* (or) can be declared inline on a target
67+
68+
```yaml
69+
rules:
70+
- name: rasterise
71+
script: |
72+
inkscape --export-png={{ ins }} {{ outs }}
73+
```
74+
75+
### 🎯 Targets
76+
77+
Targets are things you want to build.
78+
79+
```yaml
80+
- name: build/logo.png
81+
rule: rasterise
82+
sources: assets/logo.svg
83+
```
84+
85+
Targets can also define:
86+
87+
* `deps`: explicit dependencies
88+
* `order_only_deps`: e.g. `mkdir -p build`
89+
* `vars`: per-target variables
90+
91+
You may also use `command:` or `script:` instead of referencing a `rule`.
92+
93+
---
94+
95+
## 🧪 Phony Targets and Actions
96+
97+
Phony targets behave like Make’s `.PHONY`:
98+
99+
```yaml
100+
- name: clean
101+
phony: true
102+
always: true
103+
command: rm -rf build
104+
```
105+
106+
For cleaner structure, you may also define phony targets under an `actions:` block:
107+
108+
```yaml
109+
actions:
110+
- name: test
111+
command: pytest
112+
```
113+
114+
All `actions` are treated as `{ phony: true, always: false }` by default.
115+
116+
---
117+
118+
## 🧠 Templating
119+
120+
Netsuke uses [MiniJinja](https://docs.rs/minijinja) to render your manifest before parsing.
121+
122+
You can:
123+
124+
* Glob files: `{{ glob('src/**/*.c') }}`
125+
* Read environment vars: `{{ env('CC') }}`
126+
* Use filters: `{{ path | basename | with_suffix('.o') }}`
127+
* Define reusable macros:
128+
129+
```yaml
130+
macros:
131+
- signature: "shout(msg)"
132+
body: |
133+
echo "{{ msg | upper }}"
134+
```
135+
136+
Templating happens **before** parsing, so any valid output must be valid YAML.
137+
138+
---
139+
140+
## 🔐 Safety
141+
142+
Shell commands are automatically escaped.
143+
Interpolation into `command:` or `script:` will never yield a command injection vulnerability unless you explicitly ask for `| raw`.
144+
145+
```yaml
146+
command: "echo {{ dangerous_value }}" # Safe
147+
command: "echo {{ dangerous_value | raw }}" # Unsafe (your problem now)
148+
```
149+
150+
---
151+
152+
## 🔧 CLI
153+
154+
```shell
155+
netsuke [build] [target1 target2 ...]
156+
netsuke clean
157+
netsuke graph
158+
```
159+
160+
* `netsuke` alone builds the `defaults:` targets from your manifest
161+
* `netsuke graph` emits a Graphviz `.dot` of the build DAG
162+
* `netsuke clean` runs `ninja -t clean`
163+
164+
You can also pass:
165+
166+
* `--file` to use an alternate manifest
167+
* `--directory` to run in a different working dir
168+
* `-j N` to control parallelism (passed through to Ninja)
169+
170+
---
171+
172+
## 🚧 Status
173+
174+
Netsuke is **under active development**.
175+
It’s not finished, but it’s buildable, usable, and increasingly delightful.
176+
177+
Coming soon:
178+
179+
* `graph --html` for interactive DAGs
180+
* Extensible plugin system for filters/functions
181+
* Toolchain presets (`cargo`, `node`, etc.)
182+
183+
---
184+
185+
## Why “Netsuke”?
186+
187+
A **netsuke** is a small carved object used to fasten things securely to a belt.
188+
It’s not the sword. It’s not the pouch. It’s the thing that connects them.
189+
190+
That’s what this is: a tidy connector between your intent and the tool that gets it done.
191+
192+
---
193+
194+
## License
195+
196+
[ISC](https://opensource.org/licenses/ISC) — because you don't need a legal thesis to use a build tool.

0 commit comments

Comments
 (0)