#!/usr/bin/env bash # ============================================ # Ports # ============================================ #function network::ports::in_use() { # local port="$1" # # if command -v lsof >/dev/null 2>&1; then # lsof -iTCP:"$port" -sTCP:LISTEN -t >/dev/null 2>&1 # else # netstat -an | grep -q ":$port " # fi #} function network::ports::in_use() { local port="$1" # Check Docker port bindings — reliable across platforms if command -v docker >/dev/null 2>&1; then docker ps --format '{{.Ports}}' | grep -q "0.0.0.0:${port}->" && return 0 docker ps --format '{{.Ports}}' | grep -q "\[::\]:${port}->" && return 0 fi # Fallback to netstat — handles both Unix and Windows output formats netstat -an 2>/dev/null | grep -qE ":${port}[^0-9].*LISTEN" && return 0 return 1 } function network::ports::resolve() { local value="$1" # auto:X → dynamic allocation if [[ "$value" == auto:* ]]; then local base="${value#auto:}" if ! [[ "$base" =~ ^[0-9]+$ ]]; then log::network_error "Invalid auto port syntax: $value" return 1 fi # fallback if malformed (optional safety) [[ -z "$base" ]] && base=8000 local p="$base" while network::ports::in_use "$p"; do ((p++)) done echo "$p" return fi # static port echo "$value" } function network::ports::resolve_many() { local var for var in "$@"; do local value="${!var}" local resolved resolved="$(network::ports::resolve "$value")" || return 1 printf -v "$var" "%s" "$resolved" done } function network::ports::persist() { local ports_file ports_file="$(ctx::artifact)/ports" cat > "$ports_file" <