pyro-mcp/Makefile
Thales Maciel cc5f566bcc Speed up workspace tests and parallelize make test
make test was dominated by teardown-heavy workspace integration tests, not by coverage overhead. Service shutdown was treating zombie processes as live, which forced repeated timeout waits, and one shell test was leaving killpg monkeypatched during cleanup, which made shell close paths burn the full wait budget.\n\nTreat Linux zombie pids as stopped in the workspace manager so service teardown completes promptly. Restore the real killpg implementation before shell test cleanup so the shell close path no longer pays the artificial timeout. Also isolate sys.argv in the runtime-network-check main() test so parallel pytest flags do not leak into argparse-based tests.\n\nAdd pytest-xdist to the dev environment and run make test with pytest -n auto by default so available cores are used automatically during local iteration.\n\nValidation:\n- uv lock\n- targeted hot-spot pytest rerun after the fix dropped the worst tests from roughly 10-21s each to sub-second timings\n- UV_CACHE_DIR=.uv-cache make check\n- UV_CACHE_DIR=.uv-cache make dist-check
2026-03-13 13:04:59 -03:00

204 lines
11 KiB
Makefile

PYTHON ?= uv run python
UV_CACHE_DIR ?= .uv-cache
PYTEST_FLAGS ?= -n auto
OLLAMA_BASE_URL ?= http://localhost:11434/v1
OLLAMA_MODEL ?= llama3.2:3b
OLLAMA_DEMO_FLAGS ?=
RUNTIME_PLATFORM ?= linux-x86_64
RUNTIME_SOURCE_DIR ?= runtime_sources
RUNTIME_BUILD_DIR ?= build/runtime_bundle
RUNTIME_BUNDLE_DIR ?= src/pyro_mcp/runtime_bundle
RUNTIME_MATERIALIZED_DIR ?= build/runtime_sources
RUNTIME_OCI_LAYOUT_DIR ?= build/oci_layouts
RUNTIME_ENVIRONMENT ?= debian:12-base
RUNTIME_ENVIRONMENTS ?= debian:12-base debian:12 debian:12-build
PYPI_DIST_DIR ?= dist
TWINE_USERNAME ?= __token__
PYPI_REPOSITORY_URL ?=
USE_CASE_ENVIRONMENT ?= debian:12
USE_CASE_SMOKE_FLAGS ?=
.PHONY: help setup lint format typecheck test check dist-check pypi-publish demo network-demo doctor ollama ollama-demo run-server install-hooks smoke-use-cases smoke-cold-start-validation smoke-repro-fix-loop smoke-parallel-workspaces smoke-untrusted-inspection smoke-review-eval runtime-bundle runtime-binaries runtime-kernel runtime-rootfs runtime-agent runtime-validate runtime-manifest runtime-sync runtime-clean runtime-fetch-binaries runtime-build-kernel-real runtime-build-rootfs-real runtime-materialize runtime-export-environment-oci runtime-export-official-environments-oci runtime-publish-environment-oci runtime-publish-official-environments-oci runtime-boot-check runtime-network-check
help:
@printf '%s\n' \
'Available targets:' \
' help Show this help message' \
' setup Install project dependencies' \
' lint Run Ruff lint checks' \
' format Run Ruff formatter' \
' typecheck Run mypy' \
' test Run pytest in parallel when multiple cores are available' \
' check Run lint, typecheck, and tests' \
' dist-check Smoke-test the installed pyro CLI and environment UX' \
' pypi-publish Build, validate, and upload the package to PyPI' \
' demo Run the deterministic VM demo' \
' network-demo Run the deterministic VM demo with guest networking enabled' \
' doctor Show runtime and host diagnostics' \
' smoke-use-cases Run all real guest-backed workspace use-case smokes' \
' smoke-cold-start-validation Run the cold-start repo validation smoke' \
' smoke-repro-fix-loop Run the repro-plus-fix loop smoke' \
' smoke-parallel-workspaces Run the parallel isolated workspaces smoke' \
' smoke-untrusted-inspection Run the unsafe or untrusted inspection smoke' \
' smoke-review-eval Run the review and evaluation workflow smoke' \
' ollama-demo Run the network-enabled Ollama lifecycle demo' \
' run-server Run the MCP server' \
' install-hooks Install pre-commit hooks' \
' runtime-bundle Rebuild and sync the packaged runtime bundle' \
' runtime-binaries Stage runtime binaries into the build bundle' \
' runtime-kernel Stage kernel artifacts into the build bundle' \
' runtime-rootfs Stage rootfs artifacts into the build bundle' \
' runtime-agent Stage guest agent artifacts into the build bundle' \
' runtime-validate Validate runtime sources against the lockfile' \
' runtime-manifest Regenerate the runtime manifest in the build bundle' \
' runtime-sync Sync the built runtime bundle into src/' \
' runtime-fetch-binaries Materialize pinned upstream Firecracker binaries' \
' runtime-build-kernel-real Materialize the real guest kernel' \
' runtime-build-rootfs-real Materialize the real guest rootfs images' \
' runtime-materialize Run all real-source materialization steps' \
' runtime-export-environment-oci Export one environment as a local OCI layout' \
' runtime-export-official-environments-oci Export all official environments as OCI layouts' \
' runtime-publish-environment-oci Publish one exported OCI layout to its registry target' \
' runtime-publish-official-environments-oci Publish all official environments to their registry targets' \
' runtime-boot-check Validate direct Firecracker boot from the bundled runtime' \
' runtime-network-check Validate outbound guest networking from the bundled runtime' \
' runtime-clean Remove generated runtime build artifacts'
setup:
uv sync --dev
lint:
uv run ruff check .
format:
uv run ruff format .
typecheck:
uv run mypy
test:
uv run pytest $(PYTEST_FLAGS)
check: lint typecheck test
dist-check:
.venv/bin/pyro --version
.venv/bin/pyro --help >/dev/null
.venv/bin/pyro mcp --help >/dev/null
.venv/bin/pyro run --help >/dev/null
.venv/bin/pyro env list >/dev/null
.venv/bin/pyro env inspect debian:12 >/dev/null
.venv/bin/pyro doctor >/dev/null
pypi-publish:
@if [ -z "$$TWINE_PASSWORD" ]; then \
printf '%s\n' 'TWINE_PASSWORD is required; use a PyPI API token.' >&2; \
exit 1; \
fi
rm -rf "$(PYPI_DIST_DIR)"
uv build --out-dir "$(PYPI_DIST_DIR)"
uvx --from twine twine check "$(PYPI_DIST_DIR)"/*
@if [ -n "$(PYPI_REPOSITORY_URL)" ]; then \
TWINE_USERNAME="$(TWINE_USERNAME)" uvx --from twine twine upload --repository-url "$(PYPI_REPOSITORY_URL)" "$(PYPI_DIST_DIR)"/*; \
else \
TWINE_USERNAME="$(TWINE_USERNAME)" uvx --from twine twine upload "$(PYPI_DIST_DIR)"/*; \
fi
demo:
uv run pyro demo
network-demo:
uv run pyro demo --network
doctor:
uv run pyro doctor
smoke-use-cases:
uv run python scripts/workspace_use_case_smoke.py --scenario all --environment "$(USE_CASE_ENVIRONMENT)" $(USE_CASE_SMOKE_FLAGS)
smoke-cold-start-validation:
uv run python scripts/workspace_use_case_smoke.py --scenario cold-start-validation --environment "$(USE_CASE_ENVIRONMENT)" $(USE_CASE_SMOKE_FLAGS)
smoke-repro-fix-loop:
uv run python scripts/workspace_use_case_smoke.py --scenario repro-fix-loop --environment "$(USE_CASE_ENVIRONMENT)" $(USE_CASE_SMOKE_FLAGS)
smoke-parallel-workspaces:
uv run python scripts/workspace_use_case_smoke.py --scenario parallel-workspaces --environment "$(USE_CASE_ENVIRONMENT)" $(USE_CASE_SMOKE_FLAGS)
smoke-untrusted-inspection:
uv run python scripts/workspace_use_case_smoke.py --scenario untrusted-inspection --environment "$(USE_CASE_ENVIRONMENT)" $(USE_CASE_SMOKE_FLAGS)
smoke-review-eval:
uv run python scripts/workspace_use_case_smoke.py --scenario review-eval --environment "$(USE_CASE_ENVIRONMENT)" $(USE_CASE_SMOKE_FLAGS)
ollama: ollama-demo
ollama-demo:
uv run pyro demo ollama --base-url "$(OLLAMA_BASE_URL)" --model "$(OLLAMA_MODEL)" $(OLLAMA_DEMO_FLAGS)
run-server:
uv run pyro mcp serve
install-hooks:
uv run pre-commit install
runtime-binaries:
uv run python -m pyro_mcp.runtime_build stage-binaries --platform "$(RUNTIME_PLATFORM)" --source-dir "$(RUNTIME_SOURCE_DIR)" --build-dir "$(RUNTIME_BUILD_DIR)" --bundle-dir "$(RUNTIME_BUNDLE_DIR)" --materialized-dir "$(RUNTIME_MATERIALIZED_DIR)"
runtime-kernel:
uv run python -m pyro_mcp.runtime_build stage-kernel --platform "$(RUNTIME_PLATFORM)" --source-dir "$(RUNTIME_SOURCE_DIR)" --build-dir "$(RUNTIME_BUILD_DIR)" --bundle-dir "$(RUNTIME_BUNDLE_DIR)" --materialized-dir "$(RUNTIME_MATERIALIZED_DIR)"
runtime-rootfs:
uv run python -m pyro_mcp.runtime_build stage-rootfs --platform "$(RUNTIME_PLATFORM)" --source-dir "$(RUNTIME_SOURCE_DIR)" --build-dir "$(RUNTIME_BUILD_DIR)" --bundle-dir "$(RUNTIME_BUNDLE_DIR)" --materialized-dir "$(RUNTIME_MATERIALIZED_DIR)"
runtime-agent:
uv run python -m pyro_mcp.runtime_build stage-agent --platform "$(RUNTIME_PLATFORM)" --source-dir "$(RUNTIME_SOURCE_DIR)" --build-dir "$(RUNTIME_BUILD_DIR)" --bundle-dir "$(RUNTIME_BUNDLE_DIR)" --materialized-dir "$(RUNTIME_MATERIALIZED_DIR)"
runtime-validate:
uv run python -m pyro_mcp.runtime_build validate --platform "$(RUNTIME_PLATFORM)" --source-dir "$(RUNTIME_SOURCE_DIR)" --build-dir "$(RUNTIME_BUILD_DIR)" --bundle-dir "$(RUNTIME_BUNDLE_DIR)" --materialized-dir "$(RUNTIME_MATERIALIZED_DIR)"
runtime-manifest:
uv run python -m pyro_mcp.runtime_build manifest --platform "$(RUNTIME_PLATFORM)" --source-dir "$(RUNTIME_SOURCE_DIR)" --build-dir "$(RUNTIME_BUILD_DIR)" --bundle-dir "$(RUNTIME_BUNDLE_DIR)" --materialized-dir "$(RUNTIME_MATERIALIZED_DIR)"
runtime-sync:
uv run python -m pyro_mcp.runtime_build sync --platform "$(RUNTIME_PLATFORM)" --source-dir "$(RUNTIME_SOURCE_DIR)" --build-dir "$(RUNTIME_BUILD_DIR)" --bundle-dir "$(RUNTIME_BUNDLE_DIR)" --materialized-dir "$(RUNTIME_MATERIALIZED_DIR)"
runtime-bundle:
uv run python -m pyro_mcp.runtime_build bundle --platform "$(RUNTIME_PLATFORM)" --source-dir "$(RUNTIME_SOURCE_DIR)" --build-dir "$(RUNTIME_BUILD_DIR)" --bundle-dir "$(RUNTIME_BUNDLE_DIR)" --materialized-dir "$(RUNTIME_MATERIALIZED_DIR)"
runtime-fetch-binaries:
uv run python -m pyro_mcp.runtime_build fetch-binaries --platform "$(RUNTIME_PLATFORM)" --source-dir "$(RUNTIME_SOURCE_DIR)" --build-dir "$(RUNTIME_BUILD_DIR)" --bundle-dir "$(RUNTIME_BUNDLE_DIR)" --materialized-dir "$(RUNTIME_MATERIALIZED_DIR)"
runtime-build-kernel-real:
uv run python -m pyro_mcp.runtime_build build-kernel --platform "$(RUNTIME_PLATFORM)" --source-dir "$(RUNTIME_SOURCE_DIR)" --build-dir "$(RUNTIME_BUILD_DIR)" --bundle-dir "$(RUNTIME_BUNDLE_DIR)" --materialized-dir "$(RUNTIME_MATERIALIZED_DIR)"
runtime-build-rootfs-real:
uv run python -m pyro_mcp.runtime_build build-rootfs --platform "$(RUNTIME_PLATFORM)" --source-dir "$(RUNTIME_SOURCE_DIR)" --build-dir "$(RUNTIME_BUILD_DIR)" --bundle-dir "$(RUNTIME_BUNDLE_DIR)" --materialized-dir "$(RUNTIME_MATERIALIZED_DIR)"
runtime-materialize:
uv run python -m pyro_mcp.runtime_build materialize --platform "$(RUNTIME_PLATFORM)" --source-dir "$(RUNTIME_SOURCE_DIR)" --build-dir "$(RUNTIME_BUILD_DIR)" --bundle-dir "$(RUNTIME_BUNDLE_DIR)" --materialized-dir "$(RUNTIME_MATERIALIZED_DIR)"
runtime-export-environment-oci:
uv run python -m pyro_mcp.runtime_build export-environment-oci --platform "$(RUNTIME_PLATFORM)" --source-dir "$(RUNTIME_SOURCE_DIR)" --build-dir "$(RUNTIME_BUILD_DIR)" --bundle-dir "$(RUNTIME_BUNDLE_DIR)" --materialized-dir "$(RUNTIME_MATERIALIZED_DIR)" --environment "$(RUNTIME_ENVIRONMENT)" --output-dir "$(RUNTIME_OCI_LAYOUT_DIR)"
runtime-export-official-environments-oci:
@for environment in $(RUNTIME_ENVIRONMENTS); do \
$(MAKE) runtime-export-environment-oci RUNTIME_ENVIRONMENT="$$environment"; \
done
runtime-publish-environment-oci:
uv run python -m pyro_mcp.runtime_build publish-environment-oci --platform "$(RUNTIME_PLATFORM)" --source-dir "$(RUNTIME_SOURCE_DIR)" --build-dir "$(RUNTIME_BUILD_DIR)" --bundle-dir "$(RUNTIME_BUNDLE_DIR)" --materialized-dir "$(RUNTIME_MATERIALIZED_DIR)" --environment "$(RUNTIME_ENVIRONMENT)" --layout-root "$(RUNTIME_OCI_LAYOUT_DIR)"
runtime-publish-official-environments-oci:
@for environment in $(RUNTIME_ENVIRONMENTS); do \
$(MAKE) runtime-publish-environment-oci RUNTIME_ENVIRONMENT="$$environment"; \
done
runtime-boot-check:
uv run python -m pyro_mcp.runtime_boot_check
runtime-network-check:
uv run python -m pyro_mcp.runtime_network_check
runtime-clean:
rm -rf "$(RUNTIME_BUILD_DIR)" "$(RUNTIME_MATERIALIZED_DIR)"