Files
computer-playbook/scripts/make/parallel.sh
T
kevinveenbirkenbachandClaude Opus 4.7 12a56e449d refactor(env): move env/default.env to repo-root default.env and drop env/
With env.development and env/ci.env both gone, env/default.env was the
last inhabitant of the directory. Hoisting it to the repo root removes
the empty-shell indirection: the SPOT is now [default.env](default.env),
sitting next to .env (its generated companion) and other repo-root
configuration artefacts like compose.yml, Dockerfile, and Makefile.

Path updates land in:
- generator: cli/meta/env/__main__.py (REPO_ROOT / "default.env")
- workflow: .github/workflows/test-install-make.yml (awk reads from
  default.env, error message updated in lockstep)
- lint tests: test_used_keys_declared.py and test_infinito_prefix.py
  switched from globbing env/*.env to targeting default.env directly;
  test_default_env_keys_handled.py points at the new path
- drift test: test_inventory_vars_file_spot.py whitelist + STATIC_ENV
- smoke test: tests/integration/meta/env/test_dotenv_generator.py
  STATIC_ENV + every docstring/error message

Doc-string and prose references in utils/env/*, scripts/*,
cli/administration/deploy/development/{common,coredns}.py,
Makefile, Dockerfile, and every doc page that mentioned env/default.env
are rewritten in the same pass so future readers see one path.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-21 16:22:33 +02:00

116 lines
2.8 KiB
Bash
Executable File

#!/usr/bin/env bash
# Generic parallel-make wrapper. Takes one or more make targets as
# args, runs each as its own background `make` invocation (capped at
# INFINITO_WORKER_CPU concurrent workers), and at the end prints a
# per-target wall-clock breakdown plus the overall elapsed time.
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
REPO_ROOT="$(cd "${SCRIPT_DIR}/../.." && pwd)"
cd "${REPO_ROOT}"
if [[ $# -eq 0 ]]; then
echo "scripts/make/parallel.sh: at least one make target required" >&2 # nocheck: self-path-reference
exit 2
fi
# shellcheck source=scripts/meta/env/load.sh
source scripts/meta/env/load.sh
: "${INFINITO_WORKER_CPU:?INFINITO_WORKER_CPU must be set (provided by default.env via the env loader)}"
n_targets=$#
if ((n_targets < INFINITO_WORKER_CPU)); then
jobs="${n_targets}"
else
jobs="${INFINITO_WORKER_CPU}"
fi
format_duration() {
local seconds="$1"
printf '%dm %02ds' "$((seconds / 60))" "$((seconds % 60))"
}
echo
echo "🚀 parallel make dispatch"
echo " 📋 targets: $*"
echo " ⚙️ jobs: ${jobs} (cpu cap: ${INFINITO_WORKER_CPU})"
echo
tmpdir="$(mktemp -d)"
trap 'rm -rf "${tmpdir}"' EXIT
declare -A pid_to_target=()
declare -A target_start=()
declare -A target_dur=()
declare -A target_rc=()
declare -A target_log=()
start_ts="$(date +%s)"
# Concurrency throttle: launch up to ${jobs} children at a time. When
# the active count hits the cap, drain via wait -n before spawning more.
active=0
to_launch=("$@")
launch_idx=0
drain_one() {
local pid=""
local rc=0
# `|| rc=$?` keeps set -e happy when a child exited non-zero.
wait -n -p pid || rc=$?
local tgt="${pid_to_target[${pid}]}"
target_rc["${tgt}"]="${rc}"
target_dur["${tgt}"]=$(($(date +%s) - target_start["${tgt}"]))
if ((rc == 0)); then
echo "✅ ${tgt} ($(format_duration "${target_dur[${tgt}]}"))"
else
echo "❌ ${tgt} ($(format_duration "${target_dur[${tgt}]}")) exit=${rc}"
fi
cat "${target_log[${tgt}]}"
active=$((active - 1))
}
for tgt in "${to_launch[@]}"; do
while ((active >= jobs)); do
drain_one
done
log="${tmpdir}/${launch_idx}.log"
target_log["${tgt}"]="${log}"
target_start["${tgt}"]="$(date +%s)"
(make -- "${tgt}") >"${log}" 2>&1 &
pid_to_target[$!]="${tgt}"
active=$((active + 1))
launch_idx=$((launch_idx + 1))
done
while ((active > 0)); do
drain_one
done
total=$(($(date +%s) - start_ts))
echo
echo "📊 per-target wall-clock:"
overall_rc=0
for tgt in "$@"; do
rc="${target_rc[${tgt}]}"
if ((rc == 0)); then
status="✅"
else
status="❌"
overall_rc="${rc}"
fi
printf ' %s %-30s %s\n' "${status}" "${tgt}" "$(format_duration "${target_dur[${tgt}]}")"
done
echo
if ((overall_rc == 0)); then
echo "✨ total $(format_duration "${total}") 🎉"
else
echo "💥 total $(format_duration "${total}") (exit=${overall_rc})"
fi
echo
exit "${overall_rc}"