CARGO = cargo
MATURIN = uv run maturin
PYTHON = python3
PYTEST = pytest
RUST_TARGET = target/release/tarzi
PYTHON_PACKAGE = target/wheels/*.whl
PYTHON_TEST_DIR = tests/python
PYTHON_MODULES = examples python
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-python
build-python:
$(MATURIN) build --release
.PHONY: install
install: build-rust build-python
cp $(RUST_TARGET) /usr/local/bin/tarzi
pip install $(PYTHON_PACKAGE)
.PHONY: install-dev
install-dev:
uv sync --extra dev
.PHONY: test
test: test-unit test-integration
.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-unit-python
test-unit-python: install-dev
uv run -m pytest -m unit -v
.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-integration-python
test-integration-python: install-dev
uv run -m pytest -m integration -v
.PHONY: format
format: install-dev
$(CARGO) fmt
@uv run autoflake --in-place --recursive --remove-all-unused-imports --remove-unused-variables $(PYTHON_MODULES) || echo "autoflake not found, skipping Python auto-cleanup"
@uv run isort $(PYTHON_MODULES) || echo "isort not found, skipping Python import sorting"
@uv run black $(PYTHON_MODULES) || echo "black not found, skipping Python formatting"
.PHONY: lint
lint: install-dev
$(CARGO) clippy --all-targets --all-features -- -D warnings
@uv run ruff check $(PYTHON_MODULES) || echo "ruff not found, skipping Python linting"
.PHONY: check
check: install-dev lint
$(CARGO) fmt -- --check
@uv run black --check $(PYTHON_MODULES) || echo "black not found, skipping Python format check"
@uv run isort --check-only $(PYTHON_MODULES) || echo "isort not found, skipping Python import check"
$(CARGO) check
.PHONY: autofix
autofix: install-dev format
$(CARGO) clippy --fix --allow-dirty --allow-staged --all-targets --all-features -- -D warnings
@uv run ruff check --fix $(PYTHON_MODULES) || echo "ruff not found, skipping Python lint fixes"
.PHONY: clean
clean:
rm -rf target/
rm -rf .venv/
rm -rf __pycache__/
rm -rf *.egg-info/
$(CARGO) clean
rm -rf target/wheels/
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-build
doc-build:
$(CARGO) doc --no-deps
@cd docs && make html
@echo "$(GREEN)Documentation built: docs/_build/html/index.html$(RESET)"
.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: version
version:
@echo "$(BLUE)Current version:$(RESET)"
@echo "Workspace (Cargo.toml): $(shell grep '^version = ' Cargo.toml | cut -d'"' -f2)"
@echo "Python (pyproject.toml): $(shell grep '^version = ' 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)"/' pyproject.toml
@rm -f pyproject.toml.bak
@echo "$(GREEN)✅ Updated 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: setup-drivers
setup-drivers:
@echo "$(BLUE)Installing WebDriver dependencies...$(RESET)"
@if command -v brew >/dev/null 2>&1; then \
echo "$(GREEN)Installing ChromeDriver and GeckoDriver via brew...$(RESET)"; \
brew install --cask chromedriver || echo "$(RED)Failed to install chromedriver$(RESET)"; \
brew install geckodriver || echo "$(RED)Failed to install geckodriver$(RESET)"; \
echo "$(GREEN)✅ WebDriver dependencies installed$(RESET)"; \
else \
echo "$(RED)❌ Homebrew not found. Please install drivers manually:$(RESET)"; \
echo " - ChromeDriver: https://chromedriver.chromium.org/"; \
echo " - GeckoDriver: https://github.com/mozilla/geckodriver/releases"; \
echo " - Or install Homebrew: https://brew.sh/"; \
exit 1; \
fi
.PHONY: setup-full
setup-full: setup setup-drivers setup-docs
.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: check test build
.PHONY: run-examples
run-examples: run-examples-rust run-examples-python
.PHONY: run-examples-rust
run-examples-rust:
@echo "$(BLUE)Running Rust examples...$(RESET)"
@for example in basic_usage browser_driver_usage search_engines sogou_weixin_search simple_usage; do \
echo "$(GREEN)Running example: $$example$(RESET)"; \
$(CARGO) run --example $$example || echo "$(RED)Example $$example failed$(RESET)"; \
echo ""; \
done
@echo "$(GREEN)✅ All Rust examples completed$(RESET)"
.PHONY: run-examples-python
run-examples-python: install-dev
@echo "$(BLUE)Running Python examples...$(RESET)"
@for example in examples/basic_usage.py examples/search_engines.py; do \
if [ -f "$$example" ]; then \
echo "$(GREEN)Running example: $$example$(RESET)"; \
uv run python "$$example" || echo "$(RED)Example $$example failed$(RESET)"; \
echo ""; \
fi; \
done
@echo "$(GREEN)✅ All Python examples completed$(RESET)"