# --- Configuration --- IMAGE_NAME := audio-engine-hub TAG := latest # Default internal application port (exposed to Traefik) PORT := 8000 # Traefik's external entrypoints TRAEFIK_WEB_PORT := 80 TRAEFIK_DASHBOARD_PORT := 8080 # --- 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 @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 endef # Function to find next free host port for the app and ask user # This function will echo the chosen port if successful, or exit with an error. define check_app_port_free @local start_port=$(PORT); \ local found_port=$$start_port; \ local is_free=false; \ \ if ! ss -tulnp | grep ":$$start_port " > /dev/null; then \ echo "$$start_port"; \ exit 0; \ fi; \ \ echo "Port $$start_port is busy. Searching for a free port for the app..." >&2; \ while ! $$is_free; do \ if ! ss -tulnp | grep ":$$found_port " > /dev/null; then \ is_free=true; \ else \ ((found_port++)); \ if [ "$$found_port" -gt 65535 ]; then \ echo "ERROR: No free ports found up to 65535. Aborting." >&2; \ exit 1; \ fi; \ fi; \ done; \ \ echo "Port $$start_port is busy. I found port $$found_port to be free for the app." >&2; \ read -p "Do you want to use port $$found_port for the app? (y/N): " choice; \ case "$$choice" in \ y|Y ) \ echo "$$found_port"; \ ;; \ * ) \ echo "Operation cancelled by user." >&2; \ exit 1; \ ;; \ esac; endef # --- Docker Commands --- .PHONY: build build: @echo "Building Docker image: $(IMAGE_NAME):$(TAG)" docker build -t $(IMAGE_NAME):$(TAG) . .PHONY: run run: @export SELECTED_HOST_PORT=$$(bash -c 'func() { $(check_app_port_free) }; func') && \ echo "Using host port $$SELECTED_HOST_PORT for single app container" && \ docker run -d -p $$SELECTED_HOST_PORT:$(PORT) --name $(IMAGE_NAME) $(IMAGE_NAME):$(TAG) .PHONY: stop stop: @echo "Stopping Docker container: $(IMAGE_NAME)" docker stop $(IMAGE_NAME) || true docker rm $(IMAGE_NAME) || true .PHONY: logs logs: @echo "Showing logs for container: $(IMAGE_NAME)" docker logs -f $(IMAGE_NAME) .PHONY: shell shell: @echo "Accessing shell in container: $(IMAGE_NAME)" docker exec -it $(IMAGE_NAME) /bin/bash # --- Docker Compose Commands --- .PHONY: up up: $(call check_traefik_ports_free) # Check Traefik ports before starting @echo "Starting development environment with Docker Compose (Traefik enabled)..." docker-compose up --build -d .PHONY: down down: @echo "Stopping development environment with Docker Compose..." docker-compose down # --- Image Management --- .PHONY: tag tag: @echo "Tagging image $(IMAGE_NAME):$(TAG) as $(REGISTRY)/$(IMAGE_NAME):$(TAG)" docker tag $(IMAGE_NAME):$(TAG) $(REGISTRY)/$(IMAGE_NAME):$(TAG) .PHONY: push push: tag @echo "Pushing image $(REGISTRY)/$(IMAGE_NAME):$(TAG) to registry..." docker push $(REGISTRY)/$(IMAGE_NAME):$(TAG) .PHONY: test test: @echo "Running tests with coverage..." pytest --cov=. app/ tests/ # --- 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 with docker-compose (with Traefik)" @echo " down - Stop the dev environment with docker-compose" @echo " tag - Tag the image for a registry" @echo " push - Push the image to a registry (after tagging)" @echo " clean - Clean up unused containers and images" @echo " help - Show this help message" .DEFAULT_GOAL := help