SHELL := /usr/bin/env bash PYTHON ?= python3 VENV_DIR ?= .venv PIP := $(VENV_DIR)/bin/pip UVICORN := $(VENV_DIR)/bin/uvicorn .PHONY: help venv install env run start stop restart run-mock run-serial reset clean help: @echo "Targets:" @echo " venv - create virtual environment in $(VENV_DIR)" @echo " install - install Python dependencies" @echo " env - create .env from .env.example if missing" @echo " run - run API (uses .env)" @echo " start - start API in background (PID file: .uvicorn.pid)" @echo " stop - stop API using PID file" @echo " restart - stop then start API" @echo " run-mock - run API with APP_MODE=mock" @echo " run-serial - run API with APP_MODE=serial" @echo " reset - remove virtual environment and .env" venv: $(PYTHON) -m venv $(VENV_DIR) install: venv env $(PIP) install --upgrade pip $(PIP) install -r requirements.txt env: @bash -c 'set -euo pipefail; \ if [ ! -f .env ]; then \ cp .env.example .env; \ echo ".env created from .env.example"; \ else \ changed=0; \ while IFS= read -r line; do \ case "$$line" in \ ""|\#*) continue ;; \ esac; \ key="$${line%%=*}"; \ if ! grep -qE "^$${key}=" .env; then \ echo "$$line" >> .env; \ changed=1; \ fi; \ done < .env.example; \ if [ "$$changed" -eq 1 ]; then \ echo ".env updated with missing variables"; \ else \ echo ".env up to date"; \ fi; \ fi' run: bash -c 'set -a; [ -f .env ] && . ./.env; set +a; $(UVICORN) app.main:app --host "$${APP_HOST:-0.0.0.0}" --port "$${APP_PORT:-8000}"' start: @bash -c 'set -a; [ -f .env ] && . ./.env; set +a; \ if [ -f .uvicorn.pid ] && kill -0 "$$(cat .uvicorn.pid)" 2>/dev/null; then \ echo "API already running (PID $$(cat .uvicorn.pid))"; \ exit 0; \ fi; \ nohup $(UVICORN) app.main:app --host "$${APP_HOST:-0.0.0.0}" --port "$${APP_PORT:-8000}" >/dev/null 2>&1 & \ echo $$! > .uvicorn.pid; \ echo "API started (PID $$(cat .uvicorn.pid))"' stop: @bash -c 'set -euo pipefail; \ if [ ! -f .uvicorn.pid ]; then \ echo "No PID file (.uvicorn.pid)."; \ exit 0; \ fi; \ pid="$$(cat .uvicorn.pid)"; \ if kill -0 "$$pid" 2>/dev/null; then \ kill "$$pid"; \ echo "API stopped (PID $$pid)"; \ else \ echo "Process not running (PID $$pid)"; \ fi; \ rm -f .uvicorn.pid' restart: stop start run-mock: bash -c 'set -a; [ -f .env ] && . ./.env; set +a; APP_MODE=mock $(UVICORN) app.main:app --host "$${APP_HOST:-0.0.0.0}" --port "$${APP_PORT:-8000}"' run-serial: bash -c 'set -a; [ -f .env ] && . ./.env; set +a; APP_MODE=serial $(UVICORN) app.main:app --host "$${APP_HOST:-0.0.0.0}" --port "$${APP_PORT:-8000}"' reset: rm -rf $(VENV_DIR) rm -f .env .uvicorn.pid clean: reset