SHELL := /bin/bash # --- Configuration --- IMAGE_NAME := audio-engine-hub TAG := latest REGISTRY := git.wlkns.org USERNAME := stephan # Default internal application port PORT := 8000 # --- Port Checking Functions --- # Function to check if required Traefik ports are free # Exits if any are busy, does not suggest alternatives. define check_traefik_ports_free check_traefik_ports_free_func() { \ echo "Checking if Traefik ports ($(TRAEFIK_WEB_PORT), $(TRAEFIK_DASHBOARD_PORT)) are free..." >&2; \ local busy_ports=""; \ if ss -tulnp | grep ":$(TRAEFIK_WEB_PORT) " > /dev/null; then \ busy_ports="$$busy_ports $(TRAEFIK_WEB_PORT)"; \ fi; \ if ss -tulnp | grep ":$(TRAEFIK_DASHBOARD_PORT) " > /dev/null; then \ busy_ports="$$busy_ports $(TRAEFIK_DASHBOARD_PORT)"; \ fi; \ if [ -n "$$busy_ports" ]; then \ echo "ERROR: The following Traefik ports are already in use: $$busy_ports. Please free them or stop Traefik if already running." >&2; \ exit 1; \ fi; \ echo "Traefik ports are free." >&2; \ } ; \ check_traefik_ports_free_func endef # --- Docker Commands --- .PHONY: build build: @echo "Building Docker image: $(IMAGE_NAME):$(TAG)" docker build -t $(IMAGE_NAME):$(TAG) . .PHONY: run run: @APP_PORT=$$(bash -c 'port=$${PORT:-8000}; while ss -tulnp | grep -q :$$port; do echo "Port $$port is busy. Checking next..." >&2; ((port++)); done; echo $$port'); \ echo "Using host port $$APP_PORT for single app container" && \ docker run -d -p $$APP_PORT:$(PORT) --name $(IMAGE_NAME) $(IMAGE_NAME):$(TAG) .PHONY: stop stop: @echo "Stopping Docker containers..." docker compose stop || true docker compose rm -f || true docker stop $(IMAGE_NAME) || true docker rm $(IMAGE_NAME) || true .PHONY: logs logs: @echo "Showing logs for container: $(if $(CONTAINER),$(CONTAINER),$(IMAGE_NAME)_app)" docker logs -f $(if $(CONTAINER),$(CONTAINER),$(IMAGE_NAME)_app) .PHONY: shell shell: @echo "Accessing shell in container: $(if $(CONTAINER),$(CONTAINER),$(IMAGE_NAME)_app)" docker exec -it $(if $(CONTAINER),$(CONTAINER),$(IMAGE_NAME)_app) /bin/bash # --- Docker Compose Commands --- .PHONY: up up: @echo "Starting development environment by pulling image from registry..." export IMAGE_NAME=$(IMAGE_NAME) && \ export REGISTRY=$(REGISTRY) && \ export USERNAME=$(USERNAME) && \ export TAG=$(TAG) && \ docker compose up -d .PHONY: dev-up dev-up: @APP_PORT=$$(bash -c 'port=$${PORT:-8000}; while ss -tulnp | grep -q :$$port; do echo "Port $$port is busy. Checking next..." >&2; ((port++)); done; echo $$port'); \ echo "Starting development environment (local build) on port $$APP_PORT..."; \ export IMAGE_NAME=$(IMAGE_NAME) && \ export REGISTRY=$(REGISTRY) && \ export USERNAME=$(USERNAME) && \ export TAG=$(TAG) && \ APP_PORT=$$APP_PORT docker compose up --build -d .PHONY: down down: @echo "Stopping development environment with Docker Compose..." export IMAGE_NAME=$(IMAGE_NAME) && \ export REGISTRY=$(REGISTRY) && \ export USERNAME=$(USERNAME) && \ export TAG=$(TAG) && \ docker compose down # --- Image Management --- .PHONY: pull pull: @echo "Pulling image $(REGISTRY)/$(USERNAME)/$(IMAGE_NAME):$(TAG) from registry..." docker pull $(REGISTRY)/$(USERNAME)/$(IMAGE_NAME):$(TAG) .PHONY: tag tag: @echo "Tagging image $(IMAGE_NAME):$(TAG) as $(REGISTRY)/$(USERNAME)/$(IMAGE_NAME):$(TAG)" docker tag $(IMAGE_NAME):$(TAG) $(REGISTRY)/$(USERNAME)/$(IMAGE_NAME):$(TAG) .PHONY: push push: build tag @echo "Pushing image $(REGISTRY)/$(USERNAME)/$(IMAGE_NAME):$(TAG) to registry..." docker push $(REGISTRY)/$(USERNAME)/$(IMAGE_NAME):$(TAG) .PHONY: test test: @if [ -d ".venv" ]; then \ echo "Activating virtual environment..."; \ . .venv/bin/activate; \ fi; \ export PYTHONPATH=$(PWD); \ echo "Running tests with coverage..." && \ pytest --cov=. app/ tests/ .PHONY: health-check health-check: @echo "Running health check on running container..." @CONTAINER_ID=$$(docker compose ps -q app); \ if [ -z "$$CONTAINER_ID" ]; then \ echo "ERROR: App container is not running. Please run 'make up' first." >&2; \ exit 1; \ fi; \ HOST_PORT=$$(docker port $$CONTAINER_ID 8000 | cut -d: -f2); \ if [ -z "$$HOST_PORT" ]; then \ echo "ERROR: Could not determine host port for the app container." >&2; \ exit 1; \ fi; \ echo "App container is running on port $$HOST_PORT."; \ echo "Waiting for app to initialize..."; \ sleep 2; \ curl -s http://localhost:$$HOST_PORT/health | ./scripts/health_check.py # --- Cleanup --- .PHONY: clean clean: @echo "Cleaning up stopped containers and dangling images..." docker container prune -f docker image prune -f .PHONY: help help: @echo "Available commands:" @echo " build - Build the Docker image" @echo " run - Run the Docker container (single app, no Traefik)" @echo " stop - Stop and remove the Docker container" @echo " logs - Follow the logs of the container" @echo " shell - Get a shell inside the running container" @echo " up - Start the dev environment by pulling image from registry" @echo " dev-up - Start the dev environment by building image locally" @echo " down - Stop the dev environment with docker-compose" @echo " pull - Pull the Docker image from the registry" @echo " tag - Tag the image for a registry" @echo " push - Push the image to a registry (after tagging)" @echo " test - Run the pytest test suite" @echo " health-check - Run a sanity check on the deployed container" @echo " clean - Clean up unused containers and images" @echo " help - Show this help message" .DEFAULT_GOAL := help