Files
Commonwealth-Online-Server/server/start.sh
T
andrew dab76146cf
Linux Compatibility / Ubuntu dedicated server (push) Canceled after 0s
Linux Compatibility / Arch Linux container (push) Canceled after 0s
Handle config path args in server startup
Updated server launch behavior to reliably treat JSON file arguments as config paths, including file-manager “Open with” cases. The CLI `serve` command now accepts an optional positional config path (equivalent to `--config`) and errors on conflicting values. `start.sh` and `start.bat` now parse config-related arguments more explicitly, validate required values, and always pass `--config` to avoid accidental positional forwarding. Added tests covering both positional and `--config` forms, plus README documentation for the new startup behavior.
2026-08-01 21:49:48 +12:00

213 lines
6.0 KiB
Bash

#!/usr/bin/env bash
set -Eeuo pipefail
SCRIPT_PATH="$(readlink -f -- "${BASH_SOURCE[0]}" 2>/dev/null || true)"
if [[ -z "${SCRIPT_PATH}" ]]; then
SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
else
SCRIPT_DIR="$(cd -- "$(dirname -- "${SCRIPT_PATH}")" && pwd)"
fi
cd -- "${SCRIPT_DIR}"
SERVER_DIR="${SCRIPT_DIR}"
VENV_DIR="${SERVER_DIR}/.venv"
REQUIREMENTS_FILE="${SERVER_DIR}/requirements-server.txt"
REQUIREMENTS_HASH_FILE="${VENV_DIR}/.requirements-server.sha256"
CONFIG_FILE="${SERVER_DIR}/commonwealth-server.json"
ENTRY_POINT="${SERVER_DIR}/consumer_server_cli.py"
UPDATE_DEPENDENCIES=0
SERVER_ARGS=()
ARGS=("$@")
ARG_INDEX=0
while [[ ${ARG_INDEX} -lt ${#ARGS[@]} ]]; do
arg="${ARGS[${ARG_INDEX}]}"
case "${arg}" in
--update-dependencies)
UPDATE_DEPENDENCIES=1
;;
--config|-c)
ARG_INDEX=$((ARG_INDEX + 1))
if [[ ${ARG_INDEX} -ge ${#ARGS[@]} ]]; then
echo "ERROR: ${arg} requires a config file path." >&2
exit 1
fi
CONFIG_FILE="${ARGS[${ARG_INDEX}]}"
;;
--config=*)
CONFIG_FILE="${arg#--config=}"
;;
--host|--port|-H|-p|--interactive|-i)
SERVER_ARGS+=("${arg}")
if [[ "${arg}" == "--host" || "${arg}" == "-H" || "${arg}" == "--port" || "${arg}" == "-p" ]]; then
ARG_INDEX=$((ARG_INDEX + 1))
if [[ ${ARG_INDEX} -ge ${#ARGS[@]} ]]; then
echo "ERROR: ${arg} requires a value." >&2
exit 1
fi
SERVER_ARGS+=("${ARGS[${ARG_INDEX}]}")
fi
;;
--host=*|--port=*)
SERVER_ARGS+=("${arg}")
;;
*.json)
# File managers / "Open with" often pass the config path as $1.
CONFIG_FILE="${arg}"
;;
-*)
echo "ERROR: Unknown option: ${arg}" >&2
echo "Supported: --update-dependencies, --config PATH, --host HOST, --port PORT, --interactive" >&2
exit 1
;;
*)
if [[ -f "${arg}" ]]; then
CONFIG_FILE="${arg}"
else
echo "ERROR: Unexpected argument: ${arg}" >&2
exit 1
fi
;;
esac
ARG_INDEX=$((ARG_INDEX + 1))
done
echo
echo "================================================================================"
echo " Commonwealth Online Server - Start Script"
echo "================================================================================"
echo
die() {
echo "ERROR: $*" >&2
exit 1
}
detect_python() {
local candidate
for candidate in python3 python; do
if command -v "${candidate}" >/dev/null 2>&1; then
if "${candidate}" -c 'import sys; raise SystemExit(0 if sys.version_info >= (3, 9) else 1)'; then
echo "${candidate}"
return 0
fi
fi
done
return 1
}
if [[ ! -f "${REQUIREMENTS_FILE}" ]]; then
die "Missing requirements file: ${REQUIREMENTS_FILE}"
fi
if [[ ! -f "${ENTRY_POINT}" ]]; then
die "Missing server entry point: ${ENTRY_POINT}"
fi
if ! BASE_PYTHON="$(detect_python)"; then
die "Python 3.9+ is required. Install python3 (and python3-venv on Debian/Ubuntu)."
fi
echo "Using system interpreter: ${BASE_PYTHON} ($("${BASE_PYTHON}" --version 2>&1))"
if [[ ! -x "${VENV_DIR}/bin/python" ]]; then
echo "Creating virtual environment at ${VENV_DIR}..."
if ! "${BASE_PYTHON}" -m venv "${VENV_DIR}"; then
die "Failed to create virtual environment. On Debian/Ubuntu install python3-venv."
fi
fi
VENV_PYTHON="${VENV_DIR}/bin/python"
if [[ ! -x "${VENV_PYTHON}" ]]; then
die "Virtual environment interpreter missing: ${VENV_PYTHON}"
fi
if ! "${VENV_PYTHON}" -c 'import sys; raise SystemExit(0 if sys.version_info >= (3, 9) else 1)'; then
die "Virtual environment Python is older than 3.9."
fi
hash_requirements() {
if command -v sha256sum >/dev/null 2>&1; then
sha256sum -- "${REQUIREMENTS_FILE}" | awk '{print $1}'
else
"${VENV_PYTHON}" - <<'PY'
from hashlib import sha256
from pathlib import Path
print(sha256(Path("requirements-server.txt").read_bytes()).hexdigest())
PY
fi
}
CURRENT_HASH="$(hash_requirements)"
STORED_HASH=""
if [[ -f "${REQUIREMENTS_HASH_FILE}" ]]; then
STORED_HASH="$(tr -d '[:space:]' < "${REQUIREMENTS_HASH_FILE}")"
fi
NEED_INSTALL=0
if [[ ! -f "${REQUIREMENTS_HASH_FILE}" ]]; then
NEED_INSTALL=1
elif [[ "${CURRENT_HASH}" != "${STORED_HASH}" ]]; then
NEED_INSTALL=1
elif [[ "${UPDATE_DEPENDENCIES}" -eq 1 ]]; then
NEED_INSTALL=1
fi
if [[ "${NEED_INSTALL}" -eq 1 ]]; then
echo "Installing dedicated-server dependencies into .venv..."
if ! "${VENV_PYTHON}" -m pip install --upgrade pip >/dev/null 2>&1; then
echo "WARNING: Could not upgrade pip quietly; continuing with existing pip."
fi
if ! "${VENV_PYTHON}" -m pip install -r "${REQUIREMENTS_FILE}"; then
die "Failed to install dependencies from ${REQUIREMENTS_FILE}."
fi
printf '%s\n' "${CURRENT_HASH}" > "${REQUIREMENTS_HASH_FILE}"
echo "Dependencies installed."
else
echo "Dependencies are up to date."
fi
echo
if [[ ! -f "${CONFIG_FILE}" ]]; then
echo "Generating default configuration file..."
if ! "${VENV_PYTHON}" -u "${ENTRY_POINT}" config init "${CONFIG_FILE}"; then
die "Failed to generate config file."
fi
echo
fi
INTERACTIVE_ARGS=()
if [[ -t 0 && -t 1 ]]; then
INTERACTIVE_ARGS+=(--interactive)
echo "Starting Commonwealth Online Server (interactive)..."
echo "Type help for commands. Type quit or press Ctrl+C to stop."
else
echo "Starting Commonwealth Online Server (non-interactive)..."
echo "Manage the server with: ${VENV_PYTHON} -u consumer_server_cli.py status"
fi
echo
# Resolve config to an absolute path after cd'ing into the server directory.
if [[ "${CONFIG_FILE}" != /* ]]; then
CONFIG_FILE="${SERVER_DIR}/${CONFIG_FILE}"
fi
CONFIG_FILE="$(cd -- "$(dirname -- "${CONFIG_FILE}")" && pwd)/$(basename -- "${CONFIG_FILE}")"
# Do not source .venv/bin/activate — invoke the venv interpreter directly.
# Always pass --config explicitly so a bare path is never a positional serve arg.
CMD=(
"${VENV_PYTHON}"
-u
"${ENTRY_POINT}"
serve
--config
"${CONFIG_FILE}"
)
if [[ ${#INTERACTIVE_ARGS[@]} -gt 0 ]]; then
CMD+=("${INTERACTIVE_ARGS[@]}")
fi
if [[ ${#SERVER_ARGS[@]} -gt 0 ]]; then
CMD+=("${SERVER_ARGS[@]}")
fi
exec "${CMD[@]}"