CARGO = cargo
MATURIN = maturin
PYTHON = python3
PYTEST = pytest
RUST_TARGET = target/release/tarzi
PYTHON_PACKAGE = target/wheels/*.whl
PYTHON_TEST_DIR = tests/python
PYTHON_MODULES = examples python
ENABLE_INTEGRATION_TESTS ?= false
BLUE = \033[34m
GREEN = \033[32m
RED = \033[31m
RESET = \033[0m
.PHONY: help
help:
@echo "Available commands:"
@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-20s\033[0m %s\n", $$1, $$2}'
.PHONY: build
build: build-rust build-python
.PHONY: build-rust
build-rust:
$(CARGO) build --release
.PHONY: build-debug
build-debug:
$(CARGO) build
.PHONY: build-python
build-python:
$(MATURIN) build --release
.PHONY: install
install: install-rust install-python
.PHONY: install-rust
install-rust: build-rust
cp $(RUST_TARGET) /usr/local/bin/tarzi
.PHONY: install-python
install-python: build-python
pip install $(PYTHON_PACKAGE)
.PHONY: install-python-dev
install-python-dev:
$(MATURIN) develop --release
.PHONY: test
test: test-rust test-python
.PHONY: test-rust
test-rust: test-unit-rust
ifeq ($(ENABLE_INTEGRATION_TESTS),true)
@echo "$(GREEN)Running Rust integration tests (enabled)$(RESET)"
$(CARGO) test --test '*' --features test-helpers
else
@echo "$(BLUE)Skipping Rust integration tests (disabled by default)$(RESET)"
@echo "$(BLUE)Set ENABLE_INTEGRATION_TESTS=true to enable them$(RESET)"
endif
.PHONY: test-unit
test-unit: test-unit-rust test-unit-python
.PHONY: test-unit-rust
test-unit-rust:
$(CARGO) test --lib --features test-helpers
.PHONY: test-integration
test-integration: test-integration-rust test-integration-python
.PHONY: test-integration-rust
test-integration-rust:
$(CARGO) test --test '*' --features test-helpers
.PHONY: test-python
test-python: test-unit-python
ifeq ($(ENABLE_INTEGRATION_TESTS),true)
@echo "$(GREEN)Running Python integration tests (enabled)$(RESET)"
pip install -e .[test]
cd $(PYTHON_TEST_DIR) && $(PYTEST) integration/ -m integration
else
@echo "$(BLUE)Skipping Python integration tests (disabled by default)$(RESET)"
@echo "$(BLUE)Set ENABLE_INTEGRATION_TESTS=true to enable them$(RESET)"
endif
.PHONY: test-unit-python
test-unit-python: install-python-dev
pip install -e .[test]
cd $(PYTHON_TEST_DIR) && $(PYTEST) unit/ -m unit
.PHONY: test-integration-python
test-integration-python: install-python-dev
pip install -e .[test]
cd $(PYTHON_TEST_DIR) && $(PYTEST) integration/ -m integration
.PHONY: test-python-coverage
test-python-coverage: install-python-dev
pip install -e .[test]
cd $(PYTHON_TEST_DIR) && $(PYTEST) --cov=tarzi --cov-report=html --cov-report=term
.PHONY: test-with-integration
test-with-integration:
$(MAKE) test ENABLE_INTEGRATION_TESTS=true
.PHONY: test-rust-with-integration
test-rust-with-integration:
$(MAKE) test-rust ENABLE_INTEGRATION_TESTS=true
.PHONY: test-python-with-integration
test-python-with-integration:
$(MAKE) test-python ENABLE_INTEGRATION_TESTS=true
.PHONY: test-ci-mode
test-ci-mode:
@echo "$(BLUE)Running tests in CI mode (ENABLE_INTEGRATION_TESTS=$(ENABLE_INTEGRATION_TESTS))$(RESET)"
$(MAKE) test
.PHONY: format
format:
$(CARGO) fmt
@autoflake --in-place --recursive --remove-all-unused-imports --remove-unused-variables $(PYTHON_MODULES)
@isort $(PYTHON_MODULES)
@black $(PYTHON_MODULES)
.PHONY: format-check
format-check:
$(CARGO) fmt -- --check
@black --check $(PYTHON_MODULES)
@isort --check-only $(PYTHON_MODULES)
.PHONY: lint
lint: format-check
$(CARGO) clippy --all-targets --all-features -- -D warnings
@ruff check $(PYTHON_MODULES)
.PHONY: lint-fix
lint-fix:
$(CARGO) clippy --fix --allow-dirty --allow-staged --all-targets --all-features -- -D warnings
@ruff check --fix $(PYTHON_MODULES)
.PHONY: check
check: format-check lint
$(CARGO) check
.PHONY: autofix
autofix: lint-fix format
.PHONY: clean
clean: clean-rust clean-python
rm -rf target/
rm -rf .venv/
rm -rf __pycache__/
rm -rf *.egg-info/
.PHONY: clean-rust
clean-rust:
$(CARGO) clean
rm -rf target/wheels/
.PHONY: clean-python
clean-python:
rm -rf $(PYTHON_TEST_DIR)/.pytest_cache
rm -rf $(PYTHON_TEST_DIR)/htmlcov
rm -rf $(PYTHON_TEST_DIR)/.coverage
find $(PYTHON_TEST_DIR) -name "__pycache__" -type d -exec rm -rf {} +
find $(PYTHON_TEST_DIR) -name "*.pyc" -delete
.PHONY: doc
doc: doc-rust
$(CARGO) doc --no-deps --open
.PHONY: doc-rust
doc-rust:
$(CARGO) doc --no-deps --open
.PHONY: doc-build
doc-build: doc-build-rust
$(CARGO) doc --no-deps
.PHONY: doc-build-rust
doc-build-rust:
$(CARGO) doc --no-deps
.PHONY: docs-python
docs-python:
@cd docs && make html
@echo "$(GREEN)Documentation built: docs/_build/html/index.html$(RESET)"
.PHONY: docs-python-serve
docs-python-serve: docs-python
@echo "$(GREEN)Serving documentation at http://localhost:8000$(RESET)"
@cd docs/_build/html && python -m http.server 8000
.PHONY: docs-clean
docs-clean:
@rm -rf docs/_build/
.PHONY: release
release: release-rust release-python
.PHONY: release-rust
release-rust:
$(CARGO) build --release
.PHONY: release-python
release-python:
$(MATURIN) build --release
.PHONY: publish
publish: publish-rust
$(CARGO) publish
.PHONY: publish-rust
publish-rust:
$(CARGO) publish
.PHONY: publish-python
publish-python:
@if [ -z "$(shell ls -A target/wheels/ 2>/dev/null)" ]; then \
echo "$(RED)❌ No wheels found. Run 'make build-python' first.$(RESET)"; \
exit 1; \
fi
twine check $(PYTHON_PACKAGE)
twine upload $(PYTHON_PACKAGE)
@echo "$(GREEN)✅ Package published to PyPI$(RESET)"
.PHONY: publish-python-test
publish-python-test:
@if [ -z "$(shell ls -A target/wheels/ 2>/dev/null)" ]; then \
echo "$(RED)❌ No wheels found. Run 'make build-python' first.$(RESET)"; \
exit 1; \
fi
twine check $(PYTHON_PACKAGE)
twine upload --repository testpypi $(PYTHON_PACKAGE)
@echo "$(GREEN)✅ Package published to TestPyPI$(RESET)"
.PHONY: check-publish-prereqs
check-publish-prereqs:
@command -v twine >/dev/null 2>&1 || (echo "$(RED)❌ twine not found. Install with: pip install twine$(RESET)" && exit 1)
@python -c "import twine" 2>/dev/null || (echo "$(RED)❌ twine not available in Python. Install with: pip install twine$(RESET)" && exit 1)
@if [ -z "$${TWINE_USERNAME}" ] && [ -z "$${TWINE_PASSWORD}" ] && [ ! -f ~/.pypirc ]; then \
echo "$(RED)❌ PyPI credentials not found. Set TWINE_USERNAME/TWINE_PASSWORD or configure ~/.pypirc$(RESET)"; \
exit 1; \
fi
.PHONY: build-and-publish-python
build-and-publish-python: check-publish-prereqs build-python publish-python
.PHONY: build-and-publish-python-test
build-and-publish-python-test: check-publish-prereqs build-python publish-python-test
.PHONY: version
version:
@echo "$(BLUE)Current version:$(RESET)"
@echo "Workspace (Cargo.toml): $(shell grep '^version = ' Cargo.toml | cut -d'"' -f2)"
@echo "Tarzi Rust (tarzi/Cargo.toml): $(shell grep '^version = ' tarzi/Cargo.toml | cut -d'"' -f2)"
@echo "Python (pyproject.toml): $(shell grep '^version = ' pyproject.toml | cut -d'"' -f2)"
@echo "Tarzi Python (tarzi/pyproject.toml): $(shell grep '^version = ' tarzi/pyproject.toml | cut -d'"' -f2)"
.PHONY: version-update
version-update:
@if [ -z "$(VERSION)" ]; then \
echo "$(RED)❌ VERSION parameter is required. Usage: make version-update VERSION=1.2.3$(RESET)"; \
exit 1; \
fi
@echo "$(BLUE)Updating version to $(VERSION)...$(RESET)"
@ @sed -i.bak 's/^version = ".*"/version = "$(VERSION)"/' Cargo.toml
@rm -f Cargo.toml.bak
@echo "$(GREEN)✅ Updated workspace Cargo.toml$(RESET)"
@ @sed -i.bak 's/^version = ".*"/version = "$(VERSION)"/' tarzi/Cargo.toml
@rm -f tarzi/Cargo.toml.bak
@echo "$(GREEN)✅ Updated tarzi/Cargo.toml$(RESET)"
@ @sed -i.bak 's/^version = ".*"/version = "$(VERSION)"/' pyproject.toml
@rm -f pyproject.toml.bak
@echo "$(GREEN)✅ Updated pyproject.toml$(RESET)"
@ @sed -i.bak 's/^version = ".*"/version = "$(VERSION)"/' tarzi/pyproject.toml
@rm -f tarzi/pyproject.toml.bak
@echo "$(GREEN)✅ Updated tarzi/pyproject.toml$(RESET)"
@ @$(CARGO) update
@echo "$(GREEN)✅ Updated Cargo.lock$(RESET)"
@echo "$(GREEN)✅ Version updated to $(VERSION)$(RESET)"
.PHONY: setup
setup:
rustup update
$(CARGO) install cargo-outdated
pip install -e .[dev]
@echo "$(GREEN)✅ Development environment ready$(RESET)"
.PHONY: setup-docs
setup-docs:
pip install -r docs/requirements.txt
@echo "$(GREEN)✅ Documentation environment ready$(RESET)"
.PHONY: dev
dev:
$(CARGO) run -p tarzi
.PHONY: dev-release
dev-release:
$(CARGO) run --release -p tarzi
.PHONY: dev-check
dev-check: check test-unit
.PHONY: full-check
full-check: format-check lint test build