VERSION := $(shell grep '^version' Cargo.toml | head -1 | sed 's/version = "\(.*\)"/\1/')
BINARY_NAMES := zinit zinit-server zinit-pid1
INSTALL_DIR := $(HOME)/hero/bin
OS := $(shell uname -s)
ifeq ($(OS),Linux)
DEFAULT_SOCKET := /run/zinit.sock
DEFAULT_CONFIG := /etc/zinit/services
else
DEFAULT_SOCKET := $(HOME)/hero/var/zinit.sock
DEFAULT_CONFIG := $(HOME)/hero/cfg/zinit
endif
SOCKET := $(or $(ZINIT_SOCKET),$(DEFAULT_SOCKET))
CONFIG_DIR := $(or $(ZINIT_CONFIG_DIR),$(DEFAULT_CONFIG))
LOG_LEVEL := $(or $(ZINIT_LOG_LEVEL),info)
.PHONY: help version status build run dev install installdev clean all \
check fmt fmt-check lint test test-all docs \
build-publish deps update-deps stop install-download publish-dry-run build-package
help:
@echo "zinit v$(VERSION)"
@echo ""
@grep -E '^[a-zA-Z_-]+:.*?## ' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf " %-20s %s\n", $$1, $$2}'
version:
@echo "zinit v$(VERSION)"
status:
@echo "=== Zinit Configuration ==="
@echo "Version: $(VERSION)"
@echo "Platform: $(OS)"
@echo "Install dir: $(INSTALL_DIR)"
@echo "Socket: $(SOCKET)"
@echo "Config dir: $(CONFIG_DIR)"
@echo "Log level: $(LOG_LEVEL)"
@echo ""
@echo "Installed binaries:"
@if [ -f "$(INSTALL_DIR)/zinit" ]; then echo " ✓ zinit"; else echo " ✗ zinit"; fi
@if [ -f "$(INSTALL_DIR)/zinit-server" ]; then echo " ✓ zinit-server"; else echo " ✗ zinit-server"; fi
@if [ -f "$(INSTALL_DIR)/zinit-pid1" ]; then echo " ✓ zinit-pid1"; else echo " ✗ zinit-pid1"; fi
@echo ""
@echo "Check PATH configuration:"
@if echo "$$PATH" | grep -q "$(INSTALL_DIR)"; then \
echo " ✓ $(INSTALL_DIR) is in PATH"; \
else \
echo " ✗ $(INSTALL_DIR) is NOT in PATH"; \
echo " Add to ~/.bashrc or ~/.zshrc:"; \
echo " export PATH=\"\$$HOME/hero/bin:\$$PATH\""; \
fi
build:
@echo "Building zinit v$(VERSION)..."
@cargo update
@cargo build --release --features full
@echo "✓ Build complete"
dev:
@echo "Starting zinit-server in development mode..."
@RUST_LOG=debug ZINIT_SOCKET="$(SOCKET)" ZINIT_CONFIG_DIR="$(CONFIG_DIR)" \
ZINIT_LOG_LEVEL=debug cargo run --release --bin zinit-server --features full
run: install stop
@echo "=== Starting zinit-server ==="
@echo " Socket: $(SOCKET)"
@echo " Config: $(CONFIG_DIR)"
@echo " Log level: $(LOG_LEVEL)"
@mkdir -p "$(INSTALL_DIR)" "$$(dirname "$(SOCKET)")" "$(CONFIG_DIR)"
@rm -f "$(SOCKET)" 2>/dev/null || true
@ZINIT_SOCKET="$(SOCKET)" \
ZINIT_CONFIG_DIR="$(CONFIG_DIR)" \
ZINIT_LOG_LEVEL="$(LOG_LEVEL)" \
"$(INSTALL_DIR)/zinit-server" > /tmp/zinit-server.log 2>&1 &
@echo "✓ Server started (PID: $$!)"
@echo " To stop: make stop"
@echo " To view logs: tail -f /tmp/zinit-server.log"
stop:
@echo -n "Stopping zinit-server... "
@pkill -f "zinit-server" 2>/dev/null || true
@sleep 0.5
@pkill -9 -f "zinit-server" 2>/dev/null || true
@echo "done"
check:
@cargo check --all-features
fmt:
@cargo fmt
fmt-check:
@cargo fmt --check
lint:
@cargo clippy --all-targets --all-features
test:
@cargo test --lib --features full -- --test-threads=1
test-all:
@cargo test --features full -- --test-threads=1
example:
@cargo run --example main --features client
docs:
@echo "Generating documentation..."
@cargo doc --no-deps --features full --release
@echo "✓ Documentation generated at target/doc/zinit/index.html"
install: build
@echo "Installing binaries to $(INSTALL_DIR)..."
@mkdir -p "$(INSTALL_DIR)"
@for binary in zinit zinit-server; do \
if [ -f "target/release/$$binary" ]; then \
rm -f "$(INSTALL_DIR)/$$binary"; \
cp "target/release/$$binary" "$(INSTALL_DIR)/"; \
chmod +x "$(INSTALL_DIR)/$$binary"; \
echo " ✓ $$binary"; \
fi \
done
@if [ "$(OS)" = "Linux" ] && [ -f "target/release/zinit-pid1" ]; then \
rm -f "$(INSTALL_DIR)/zinit-pid1"; \
cp "target/release/zinit-pid1" "$(INSTALL_DIR)/"; \
chmod +x "$(INSTALL_DIR)/zinit-pid1"; \
echo " ✓ zinit-pid1"; \
fi
@echo ""
@if ! echo "$$PATH" | grep -q "$(INSTALL_DIR)"; then \
echo "⚠ $(INSTALL_DIR) is not in your PATH"; \
echo "Add this to ~/.bashrc or ~/.zshrc:"; \
echo " export PATH=\"\$$HOME/hero/bin:\$$PATH\""; \
else \
echo "✓ Binaries ready in PATH"; \
fi
installdev:
@echo "Building and installing dev binaries to $(INSTALL_DIR)..."
@cargo build --features full
@mkdir -p "$(INSTALL_DIR)"
@for binary in zinit zinit-server; do \
if [ -f "target/debug/$$binary" ]; then \
rm -f "$(INSTALL_DIR)/$$binary"; \
cp "target/debug/$$binary" "$(INSTALL_DIR)/"; \
chmod +x "$(INSTALL_DIR)/$$binary"; \
echo " ✓ $$binary"; \
fi \
done
@if [ "$(OS)" = "Linux" ] && [ -f "target/debug/zinit-pid1" ]; then \
rm -f "$(INSTALL_DIR)/zinit-pid1"; \
cp "target/debug/zinit-pid1" "$(INSTALL_DIR)/"; \
chmod +x "$(INSTALL_DIR)/zinit-pid1"; \
echo " ✓ zinit-pid1"; \
fi
@echo "✓ Dev binaries installed to $(INSTALL_DIR)"
clean:
@echo "Cleaning build artifacts..."
@cargo clean
@echo "✓ Clean complete"
build-publish: clean fmt lint test build docs
@echo ""
@echo "=== Build & Publish Workflow Complete ==="
@echo "Version: $(VERSION)"
@echo "Platform: $(OS)"
@echo ""
@echo "Artifacts ready:"
@echo " Binaries: target/release/zinit*"
@echo " Docs: target/doc/zinit/index.html"
all: clean fmt-check lint test build
deps:
@cargo tree
update-deps:
@cargo update
@echo "✓ Dependencies updated"
install-download:
@echo "Installing zinit binaries from Forgejo package registry..."
@INSTALL_DIR="$(INSTALL_DIR)" \
SOCKET="$(SOCKET)" \
CONFIG_DIR="$(CONFIG_DIR)" \
bash -c '\
OS=$$(uname -s); \
ARCH=$$(uname -m); \
case "$$ARCH" in \
x86_64) ARCH=amd64 ;; \
aarch64|arm64) ARCH=arm64 ;; \
esac; \
PACKAGE_URL="https://forge.ourworld.tf/api/packages/geomind_code/generic/zinit/dev"; \
mkdir -p "$(INSTALL_DIR)"; \
for binary in zinit zinit-server; do \
BINARY_NAME="$${binary}-$$(echo $$OS | tr A-Z a-z)-$$ARCH"; \
echo "Downloading $$binary..."; \
if command -v curl &>/dev/null; then \
curl -L -f -o "$(INSTALL_DIR)/$${binary}" "$$PACKAGE_URL/$$BINARY_NAME" || exit 1; \
elif command -v wget &>/dev/null; then \
wget -O "$(INSTALL_DIR)/$${binary}" "$$PACKAGE_URL/$$BINARY_NAME" || exit 1; \
else \
echo "Error: Neither curl nor wget found"; \
exit 1; \
fi; \
chmod +x "$(INSTALL_DIR)/$${binary}"; \
echo "✓ Installed $$binary"; \
done; \
echo ""; \
echo "✓ Installation complete"; \
echo "Add to PATH: export PATH=\"$(INSTALL_DIR):$$PATH\""; \
'
publish-dry-run: clean fmt lint test build docs
@echo "Running crates.io publish dry-run..."
@cargo publish --dry-run
@echo ""
@echo "=== Publish dry-run complete ==="
@echo "Version: $(VERSION)"
@echo ""
@echo "To publish for real, run:"
@echo " cargo publish"
build-package:
@if [ -z "$$FORGEJO_TOKEN" ]; then \
echo "Error: FORGEJO_TOKEN is not set"; \
echo "Please set it with: export FORGEJO_TOKEN='your-token-here'"; \
exit 1; \
fi
@echo "Building package for distribution..."
@echo "Version: $(VERSION)"
@echo ""
@echo "Verifying Forgejo token..."
@if ! curl -sf -H "Authorization: token $$FORGEJO_TOKEN" "https://forge.ourworld.tf/api/v1/user" > /dev/null; then \
echo "Error: FORGEJO_TOKEN is invalid or expired"; \
exit 1; \
fi
@echo "Token verified"
@echo ""
@echo "Checking for forgejo-runner..."
@if ! command -v forgejo-runner &> /dev/null; then \
echo "Installing forgejo-runner..."; \
curl -sSL https://forge.ourworld.tf/api/packages/lhumina_research/generic/forgejo-runner/dev/install.sh | bash; \
else \
echo "forgejo-runner already installed"; \
fi
@echo ""
@echo "Running build workflow for $(OS)..."
ifeq ($(OS),Darwin)
@forgejo-runner exec \
-j build-macos \
-s FORGEJO_TOKEN="$$FORGEJO_TOKEN" \
--forgejo-instance "https://forge.ourworld.tf" \
--env VERSION="$(VERSION)" \
--env OWNER="geomind_code" \
-i "-self-hosted" \
-W .forgejo/workflows/build-macos.yaml
else
@forgejo-runner exec \
-j build-linux \
-s FORGEJO_TOKEN="$$FORGEJO_TOKEN" \
--forgejo-instance "https://forge.ourworld.tf" \
--env VERSION="$(VERSION)" \
--env OWNER="geomind_code" \
-i "-self-hosted" \
-W .forgejo/workflows/build-linux.yaml
endif
@echo ""
@echo "✓ Build complete. Pushing to remote..."
.DEFAULT_GOAL := help