#!/usr/bin/env bash # Starts a Stalwart instance for local development and integration tests. # # By default it uses STALWART_PORT from the environment. When STALWART_PORT=0 # or STALWART_RANDOM_PORTS=1, three free random ports are chosen and written to # STALWART_TMPDIR/ports.env for other scripts to source. set -euo pipefail if [ "${STALWART_RANDOM_PORTS:-0}" = "1" ] || [ "${STALWART_PORT:-0}" = "0" ]; then command -v python3 >/dev/null || { echo "python3 not in PATH — cannot choose random Stalwart ports" exit 1 } read -r STALWART_PORT STALWART_IMAP_PORT STALWART_SMTP_PORT STALWART_SIEVE_PORT < <( python3 - <<'PY' import socket ports = [] for _ in range(4): sock = socket.socket() sock.bind(("127.0.0.1", 0)) ports.append(str(sock.getsockname()[1])) sock.close() print(" ".join(ports)) PY ) else : "${STALWART_PORT:?STALWART_PORT is not set — run this inside nix develop}" STALWART_IMAP_PORT="${STALWART_IMAP_PORT:-$((STALWART_PORT + 1))}" STALWART_SMTP_PORT="${STALWART_SMTP_PORT:-$((STALWART_PORT + 2))}" STALWART_SIEVE_PORT="${STALWART_SIEVE_PORT:-$((STALWART_PORT + 3))}" fi export STALWART_PORT STALWART_IMAP_PORT STALWART_SMTP_PORT STALWART_SIEVE_PORT export STALWART_URL="http://127.0.0.1:${STALWART_PORT}" TMPDIR="${STALWART_TMPDIR:-/tmp/stalwart-dev-${STALWART_PORT}}" mkdir -p "$TMPDIR" for port in "$STALWART_PORT" "$STALWART_IMAP_PORT" "$STALWART_SMTP_PORT" "$STALWART_SIEVE_PORT"; do ss -ltnH "sport = :$port" | grep -q . && { echo "Stalwart port $port is already in use" exit 1 } done cat >"${TMPDIR}/ports.env" </dev/null 2>&1; then RUNTIME="podman" elif command -v docker >/dev/null 2>&1; then RUNTIME="docker" else echo "No container runtime (podman or docker) found" >&2 exit 1 fi echo "Stalwart ports: JMAP=${STALWART_PORT} IMAP=${STALWART_IMAP_PORT} SMTP=${STALWART_SMTP_PORT} SIEVE=${STALWART_SIEVE_PORT}" >&2 echo "Stalwart is running in a container (${RUNTIME}). Press Ctrl+C to stop." >&2 echo "Connection info written to ${TMPDIR}/ports.env" >&2 REPO_ROOT="$(cd "$(dirname "$0")/.." && pwd)" # Run Stalwart in container, mapping the random host ports to the fixed container ports. # We mount the config.toml and use /tmp/stalwart for data (mapped to our local TMPDIR). exec "${RUNTIME}" run --rm -i \ -p "${STALWART_PORT}:8080" \ -p "${STALWART_IMAP_PORT}:1430" \ -p "${STALWART_SMTP_PORT}:1025" \ -p "${STALWART_SIEVE_PORT}:4190" \ -v "${REPO_ROOT}/stalwart-dev/config.toml:/etc/stalwart/config.toml:ro" \ -v "${TMPDIR}:/tmp/stalwart:rw" \ docker.io/stalwartlabs/stalwart:v0.14.1 \ stalwart --config /etc/stalwart/config.toml