-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathMakefile
More file actions
366 lines (292 loc) · 15.6 KB
/
Makefile
File metadata and controls
366 lines (292 loc) · 15.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
SF := rust/target/release/seedfaker
MANIFEST := rust/Cargo.toml
RUN := docker compose run --rm dev
# Resolve cargo: use PATH, then ~/.cargo/bin
CARGO := $(shell command -v cargo 2>/dev/null || echo "$$HOME/.cargo/bin/cargo")
define check_docker
@docker info > /dev/null 2>&1 || { echo "Error: Docker is not running. Start Docker Desktop or use LOCAL=1 make $(1)"; exit 1; }
endef
# macOS needs dynamic_lookup for PyO3 extension modules
UNAME_S := $(shell uname -s)
ifeq ($(UNAME_S),Darwin)
PYO3_RUSTFLAGS := RUSTFLAGS="-C link-arg=-undefined -C link-arg=dynamic_lookup"
endif
# ═══════════════════════════════════════════════════════════════════
# Workflow — all execution inside Docker by default
# ═══════════════════════════════════════════════════════════════════
#
# make dev build all + install to host
# make test full test suite (rust + npm + pip + mcp + cross)
# make pre-commit dev + fmt + lint + test + codegen + verify
# make pre-release pre-commit + regen + examples
#
# LOCAL=1 make dev run without Docker (requires local toolchain)
# make setup-local check/install local toolchain
dev:
ifdef LOCAL
$(MAKE) _dev
@bash tools/system-install.sh
else
$(call check_docker,dev)
$(RUN) make _dev
endif
test:
ifdef LOCAL
$(MAKE) _test
else
$(call check_docker,test)
$(RUN) make _test
endif
pre-commit:
ifdef LOCAL
$(MAKE) _pre-commit
else
$(call check_docker,pre-commit)
$(RUN) make _pre-commit
endif
pre-release:
ifdef LOCAL
$(MAKE) _pre-release
else
$(call check_docker,pre-release)
$(RUN) make _pre-release
endif
# ═══════════════════════════════════════════════════════════════════
# Internal targets (executed inside Docker or locally with LOCAL=1)
# ═══════════════════════════════════════════════════════════════════
_dev: build
_test: build test-rust test-npm test-pip test-mcp test-examples test-cross
_pre-commit: _dev fmt lint _test audit fields bindings types verify
_pre-release: _pre-commit regen field-examples size
# ═══════════════════════════════════════════════════════════════════
# Install
# ═══════════════════════════════════════════════════════════════════
system-install:
@bash tools/system-install.sh
# ═══════════════════════════════════════════════════════════════════
# Docker
# ═══════════════════════════════════════════════════════════════════
docker-build:
docker compose build
docker-clean:
-docker compose down -v 2>/dev/null
-docker rmi seedfaker-dev 2>/dev/null
docker-shell:
$(RUN) bash
docker-image:
docker build -t seedfaker/cli .
# ═══════════════════════════════════════════════════════════════════
# Build
# ═══════════════════════════════════════════════════════════════════
build-cli:
$(CARGO) build --release --manifest-path $(MANIFEST) -p seedfaker
build-napi: build-cli
$(CARGO) build --release --manifest-path $(MANIFEST) -p seedfaker-napi
@rm -f packages/npm/seedfaker_napi.node
@cp rust/target/release/libseedfaker_napi.dylib packages/npm/seedfaker_napi.node 2>/dev/null || \
cp rust/target/release/libseedfaker_napi.so packages/npm/seedfaker_napi.node 2>/dev/null || \
{ echo "ERROR: libseedfaker_napi not found in target/release"; exit 1; }
@file packages/npm/seedfaker_napi.node | grep -q "$(shell uname -m)" || \
{ echo "WARNING: .node file architecture mismatch"; file packages/npm/seedfaker_napi.node; }
build-pyo3: build-cli
$(PYO3_RUSTFLAGS) $(CARGO) build --release --manifest-path $(MANIFEST) -p seedfaker-python
@rm -f packages/pip/seedfaker/_seedfaker.abi3.so
@cp rust/target/release/lib_seedfaker.dylib packages/pip/seedfaker/_seedfaker.abi3.so 2>/dev/null || \
cp rust/target/release/lib_seedfaker.so packages/pip/seedfaker/_seedfaker.abi3.so 2>/dev/null || \
{ echo "ERROR: lib_seedfaker not found in target/release"; exit 1; }
@file packages/pip/seedfaker/_seedfaker.abi3.so | grep -q "$(shell uname -m)" || \
{ echo "WARNING: .so file architecture mismatch"; file packages/pip/seedfaker/_seedfaker.abi3.so; }
build-ffi: build-cli
$(CARGO) build --release --manifest-path $(MANIFEST) -p seedfaker-ffi
WASM_PACK := $(shell command -v wasm-pack 2>/dev/null || echo "$$HOME/.cargo/bin/wasm-pack")
build-wasm:
@test -f $(WASM_PACK) || { echo "wasm-pack not found. Install: cargo install wasm-pack"; exit 1; }
PATH="$$HOME/.cargo/bin:$$PATH" $(WASM_PACK) build rust/wasm --target web --out-dir ../../packages/wasm/web --out-name seedfaker_wasm
PATH="$$HOME/.cargo/bin:$$PATH" $(WASM_PACK) build rust/wasm --target bundler --out-dir ../../packages/wasm/bundler --out-name seedfaker_wasm
build: build-cli build-napi build-pyo3 build-ffi
@$(SF) --version
# ═══════════════════════════════════════════════════════════════════
# Quality
# ═══════════════════════════════════════════════════════════════════
test-rust:
$(PYO3_RUSTFLAGS) $(CARGO) test --manifest-path $(MANIFEST) --workspace
test-npm:
@bash tools/test-npm.sh
test-pip:
@bash tools/test-pip.sh
test-mcp:
@bash tools/test-mcp.sh $(SF)
test-examples:
@bash tools/test-examples.sh
test-cross:
@bash tools/test-cross.sh
test-release:
@bash tools/test-release.sh $(P)
PY_FILES := packages/pip/seedfaker/ tools/*.py benchmarks/python/*.py examples/python/*.py
JS_FILES := packages/npm/index.js packages/npm/index.d.ts packages/npm-cli/bin/seedfaker.js
TOML_FILES := rust/Cargo.toml rust/*/Cargo.toml packages/pip/pyproject.toml
SH_FILES := benchmarks/*.sh .github/scripts/*.sh tools/*.sh examples/*.sh
fmt:
$(CARGO) fmt --manifest-path $(MANIFEST) --all
prettier --write $(JS_FILES) '**/*.json' '**/*.yml' '**/*.yaml' '*.md' 'docs/**/*.md' --log-level warn
ruff format $(PY_FILES)
ruff check --fix --exit-zero $(PY_FILES)
taplo fmt $(TOML_FILES)
@gofmt -w examples/go/main.go packages/go/seedfaker.go 2>/dev/null || true
lint:
$(PYO3_RUSTFLAGS) $(CARGO) clippy --manifest-path $(MANIFEST) --workspace -- -D warnings
eslint packages/npm/index.js
ruff check $(PY_FILES)
prettier --check $(JS_FILES) '**/*.json' '**/*.yml' '**/*.yaml' '*.md' 'docs/**/*.md' --log-level warn
taplo lint $(TOML_FILES)
shellcheck -S error $(SH_FILES)
verify: verify-types
@bash tools/verify-docs.sh
# ═══════════════════════════════════════════════════════════════════
# Codegen
# ═══════════════════════════════════════════════════════════════════
field-gen:
python3 tools/gen-fields.py
fields:
@bash tools/gen-field-reference.sh
bindings:
@test -f $(SF) || { echo "Run 'make build' first."; exit 1; }
@$(SF) --list-json | python3 tools/gen-bindings.py
types: types-ts types-py types-go types-php
@echo "All types generated."
types-ts:
@python3 tools/gen-ts-types.py
@cp build/types/npm/index.d.ts packages/npm/index.d.ts
@pnpm exec prettier --write packages/npm/index.d.ts --log-level warn
types-py:
@python3 tools/gen-py-types.py
@ruff format build/types/pip/__init__.pyi --quiet
@cp build/types/pip/__init__.pyi packages/pip/seedfaker/__init__.pyi
types-go:
@python3 tools/gen-go-types.py
@cp build/types/go/opts_gen.go packages/go/opts_gen.go
types-php:
@python3 tools/gen-php-types.py
verify-types:
@python3 tools/gen-ts-types.py
@pnpm exec prettier --stdin-filepath x.d.ts < build/types/npm/index.d.ts > build/types/npm/.verify-a.tmp 2>/dev/null
@pnpm exec prettier --stdin-filepath x.d.ts < packages/npm/index.d.ts > build/types/npm/.verify-b.tmp 2>/dev/null
@diff -q build/types/npm/.verify-a.tmp build/types/npm/.verify-b.tmp || { echo "STALE: packages/npm/index.d.ts — run 'make types'"; exit 1; }
@python3 tools/gen-py-types.py
@ruff format build/types/pip/__init__.pyi --quiet
@diff -q build/types/pip/__init__.pyi packages/pip/seedfaker/__init__.pyi || { echo "STALE: packages/pip/seedfaker/__init__.pyi — run 'make types'"; exit 1; }
@python3 tools/gen-go-types.py
@diff -q build/types/go/opts_gen.go packages/go/opts_gen.go || { echo "STALE: packages/go/opts_gen.go — run 'make types'"; exit 1; }
@echo "Type files up to date."
regen: fields bindings types update-snapshots stamp-fingerprint
update-snapshots:
@test -f $(SF) || { echo "Run 'make build' first."; exit 1; }
@bash tools/update-snapshots.sh
stamp-fingerprint:
@test -f $(SF) || { echo "Run 'make build' first."; exit 1; }
@bash tools/stamp-fingerprint.sh
field-examples:
@test -f $(SF) || { echo "Run 'make build' first."; exit 1; }
@SEEDFAKER="$(CURDIR)/$(SF)" bash examples/context/generate.sh
@for spec in app-json auth chaos email llm-prompt medical nginx payment pii-leak postgres stacktrace syslog user-table; do \
$(SF) run "$$spec" -n 5 --seed spec-example --until 2025 > "examples/presets/$$spec.txt"; \
done
@echo "examples/context/ and examples/presets/ updated."
# ═══════════════════════════════════════════════════════════════════
# Bench
# ═══════════════════════════════════════════════════════════════════
bench: bench-fast bench-fields
bench-fast:
@test -f $(SF) || { echo "Run 'make build' first."; exit 1; }
@bash benchmarks/fast.sh
bench-fields: build-cli
@bash benchmarks/fields.sh
bench-full: build-cli
@SEEDFAKER="$(CURDIR)/$(SF)" BENCH_RUNS="$(or $(BENCH_RUNS),5)" \
BENCH_SKIP_PYTHON="$(BENCH_SKIP_PYTHON)" BENCH_SKIP_NODE="$(BENCH_SKIP_NODE)" \
bash benchmarks/full.sh
uniqueness: build-cli
@MAX=$(or $(MAX),1000000) bash benchmarks/uniqueness.sh
determinism: build-cli
@bash benchmarks/determinism.sh
audit:
@bash tools/audit.sh
# ═══════════════════════════════════════════════════════════════════
# Examples
# ═══════════════════════════════════════════════════════════════════
examples: field-examples
@test -f $(SF) || { echo "Run 'make build' first."; exit 1; }
@SEEDFAKER="$(CURDIR)/$(SF)" bash examples/run-all.sh --no-docker
examples-docker:
@test -f $(SF) || { echo "Run 'make build' first."; exit 1; }
@SEEDFAKER="$(CURDIR)/$(SF)" bash examples/run-all.sh
# ═══════════════════════════════════════════════════════════════════
# Release
# ═══════════════════════════════════════════════════════════════════
bump:
@test -n "$(VERSION)" || { echo "Usage: make bump VERSION=0.1.0-alpha.2"; exit 1; }
@bash tools/bump-version.sh $(VERSION)
release:
@test -n "$(VERSION)" || { echo "Usage: make release VERSION=0.1.0"; exit 1; }
git tag -a "v$(VERSION)" -m "Release v$(VERSION)"
git push origin "v$(VERSION)"
size:
@echo "CLI binary:"
@test -f $(SF) && ls -lh $(SF) | awk '{print " " $$5 " " $$NF}' || echo " not built"
@echo "NAPI module:"
@test -f packages/npm/seedfaker_napi.node && ls -lh packages/npm/seedfaker_napi.node | awk '{print " " $$5}' || echo " not built"
@echo "PyO3 module:"
@test -f packages/pip/seedfaker/_seedfaker.abi3.so && ls -lh packages/pip/seedfaker/_seedfaker.abi3.so | awk '{print " " $$5}' || echo " not built"
clean:
-$(CARGO) clean --manifest-path $(MANIFEST) 2>/dev/null
-rm -f packages/npm/seedfaker_napi.node packages/pip/seedfaker/_seedfaker.abi3.so packages/pip/seedfaker/_seedfaker.so
# ═══════════════════════════════════════════════════════════════════
help:
@echo "Workflow (all run in Docker by default):"
@echo " dev Build all + install to host"
@echo " test Rust + npm + pip + MCP + cross-determinism"
@echo " pre-commit dev + fmt + lint + test + codegen + verify"
@echo " pre-release pre-commit + regen + examples"
@echo ""
@echo " LOCAL=1 make dev Run without Docker (local toolchain)"
@echo ""
@echo "Install:"
@echo " system-install Install pre-built artifacts to host"
@echo ""
@echo "Post-release:"
@echo " test-release P=\"npm-cli pip\" Verify published packages (brew cargo npm-lib npm-cli wasm pip php ruby go)"
@echo ""
@echo "Docker:"
@echo " docker-build Build dev image"
@echo " docker-shell Open shell in dev container"
@echo " docker-image Build production image"
@echo " docker-clean Remove dev containers and volumes"
@echo ""
@echo "Build:"
@echo " build CLI + NAPI + PyO3 + FFI"
@echo " build-wasm WASM (requires wasm-pack)"
@echo ""
@echo "Quality:"
@echo " fmt Format all"
@echo " lint Lint all"
@echo " verify Check generated files"
@echo " audit cargo deny + pnpm audit"
@echo ""
@echo "Codegen:"
@echo " regen fields + bindings + types + snapshots + fingerprint"
@echo ""
@echo "Release:"
@echo " bump VERSION=X Bump version across all packages"
@echo " release VERSION=X Tag + push (triggers release workflow)"
@echo ""
@echo "Bench:"
@echo " bench Quick: CLI tier + per-field"
@echo " bench-full All + competitor comparisons"
.PHONY: dev test pre-commit pre-release \
_dev _test _pre-commit _pre-release \
system-install build-wasm docker-build docker-clean docker-shell docker-image \
build-cli build-napi build-pyo3 build-ffi build \
test-rust test-npm test-pip test-mcp test-examples test-cross test-release fmt lint verify \
field-gen fields bindings regen update-snapshots stamp-fingerprint field-examples \
bench bench-fast bench-fields bench-full uniqueness determinism audit \
examples examples-docker bump release size clean help