-
Notifications
You must be signed in to change notification settings - Fork 0
feat(docker): auto delegate scripts to docker #41
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 7 commits
6f11ff5
6da5660
02a4a75
19e1a83
af84b8b
0c73143
438b2d8
afcefe3
eaa9ccd
6784943
ef14844
a7aed48
3eb176b
fa11cb4
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -36,7 +36,7 @@ build/ | |
| install/ | ||
|
|
||
| # Doxygen | ||
| html/ | ||
| docs/generated/ | ||
|
|
||
| # Testing | ||
| Testing/ | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,92 @@ | ||
| #!/usr/bin/env bash | ||
|
|
||
| ############################################################################### | ||
| # Container delegation for project scripts | ||
| # | ||
| # When a script is invoked outside the container, this module re-executes it | ||
| # inside a disposable Docker container (docker run --rm) and exits. | ||
| # If already inside the container, it returns immediately and the calling | ||
| # script continues as normal. | ||
| # | ||
| # How it works: | ||
| # | ||
| # Host shell Container shell | ||
| # ---------- ---------------- | ||
| # ./scripts/build.sh | ||
| # source env.sh | ||
| # source docker/exec.sh | ||
| # delegate_to_container | ||
| # docker run --rm ... build.sh --> ./scripts/build.sh | ||
| # exit $? source env.sh | ||
| # source docker/exec.sh | ||
| # delegate_to_container | ||
| # sees /.dockerenv | ||
| # return 0 | ||
| # cmake ... | ||
| # make ... | ||
| # <-- exits (container destroyed) | ||
| # | ||
| # The host starts a subprocess (docker run) that runs the SAME script from | ||
| # scratch. The second invocation detects /.dockerenv, skips delegation, | ||
| # and executes the real work. The host waits for the exit code and forwards it. | ||
| # The container is destroyed automatically after the script finishes (--rm). | ||
| # | ||
| # Requires env.sh to be sourced first (for logging helpers and PROJECT_ROOT). | ||
| # | ||
| # Usage (from any project script, after sourcing env.sh): | ||
| # source "$SCRIPT_DIR/docker/exec.sh" | ||
| # delegate_to_container "$@" | ||
| ############################################################################### | ||
|
|
||
| IMAGE_NAME="cpp-dev:latest" | ||
| CONTAINER_WORKDIR="/workspaces/${PROJECT_NAME}" | ||
|
|
||
| delegate_to_container() { | ||
| # Already inside the container -- nothing to do | ||
| if [ -f /.dockerenv ]; then | ||
| return 0 | ||
| fi | ||
|
|
||
| # Resolve the calling script path relative to project root (portable) | ||
| local caller_script="${BASH_SOURCE[1]}" | ||
| local script_absolute | ||
| script_absolute="$(cd "$(dirname "$caller_script")" && pwd)/$(basename "$caller_script")" | ||
| local script_relative="${script_absolute#"$PROJECT_ROOT"/}" | ||
|
|
||
| if [ "$script_relative" = "$script_absolute" ]; then | ||
| log_error "Script '${caller_script}' is not under PROJECT_ROOT '${PROJECT_ROOT}'." | ||
| return 1 | ||
| fi | ||
|
|
||
| # Preflight: verify Docker is installed and the daemon is reachable | ||
| if ! command -v docker &> /dev/null; then | ||
| log_error "Docker is not installed. Please install Docker to use container delegation." | ||
| return 1 | ||
| fi | ||
|
|
||
| if ! docker version &> /dev/null; then | ||
| log_error "Docker daemon is not reachable. Is the Docker service running?" | ||
| return 1 | ||
| fi | ||
|
|
||
| log_docker "Running outside container -- delegating to Docker..." | ||
|
|
||
| # Build the image if it does not exist yet | ||
| if ! docker image inspect "$IMAGE_NAME" &> /dev/null; then | ||
| log_docker "Image '${IMAGE_NAME}' not found. Building it first..." | ||
| "${PROJECT_ROOT}/scripts/docker/build_image.sh" | ||
| fi | ||
|
|
||
| # Run the script inside a disposable container | ||
| docker run --rm \ | ||
| --hostname cpp-devcontainer \ | ||
| --env "HOST_UID=$(id -u)" \ | ||
| --env "HOST_GID=$(id -g)" \ | ||
| --env TERM=xterm-256color \ | ||
| --volume "$PROJECT_ROOT:${CONTAINER_WORKDIR}" \ | ||
| --workdir "${CONTAINER_WORKDIR}" \ | ||
| "$IMAGE_NAME" \ | ||
| bash "${CONTAINER_WORKDIR}/${script_relative}" "$@" | ||
|
|
||
| exit $? | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,67 @@ | ||
| #!/usr/bin/env bash | ||
|
|
||
| ############################################################################### | ||
| # Environment setup for all project scripts | ||
| # | ||
| # Provides: | ||
| # - Colored output and logging helpers | ||
| # - Project path resolution | ||
| # | ||
| # Usage (source from other scripts): | ||
| # SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" | ||
| # source "$SCRIPT_DIR/env.sh" | ||
| ############################################################################### | ||
|
|
||
| # ============================================================================== | ||
| # Color definitions (disabled when output is not a terminal) | ||
| # ============================================================================== | ||
| if [ -t 1 ]; then | ||
| RED='\033[0;31m' | ||
| GREEN='\033[0;32m' | ||
| YELLOW='\033[0;33m' | ||
| BLUE='\033[0;34m' | ||
| CYAN='\033[0;36m' | ||
| BOLD='\033[1m' | ||
| RESET='\033[0m' | ||
| else | ||
| RED='' | ||
| GREEN='' | ||
| YELLOW='' | ||
| BLUE='' | ||
| CYAN='' | ||
| BOLD='' | ||
| RESET='' | ||
| fi | ||
|
|
||
| # ============================================================================== | ||
| # Logging helpers | ||
| # | ||
| # - printf is used instead of echo -e for portable escape handling | ||
| # - log_warn and log_error write to stderr so pipelines stay clean | ||
| # ============================================================================== | ||
| log_info() { printf '%b %s\n' "${GREEN}[INFO]${RESET}" "$*"; } | ||
| log_warn() { printf '%b %s\n' "${YELLOW}[WARN]${RESET}" "$*" >&2; } | ||
| log_error() { printf '%b %s\n' "${RED}[ERROR]${RESET}" "$*" >&2; } | ||
| log_step() { printf '%b %s\n' "${CYAN}[STEP]${RESET}" "$*"; } | ||
| log_docker() { printf '%b %s\n' "${BLUE}[CONTAINER]${RESET}" "$*"; } | ||
|
|
||
| # ============================================================================== | ||
| # Project paths | ||
| # | ||
| # SCRIPT_DIR must be set by the calling script before sourcing env.sh. | ||
| # ============================================================================== | ||
| if [ -z "${SCRIPT_DIR:-}" ]; then | ||
| log_error "SCRIPT_DIR is not set. Please set SCRIPT_DIR before sourcing env.sh." | ||
| return 1 | ||
| fi | ||
|
Comment on lines
+60
to
+63
|
||
|
|
||
| if [ ! -d "$SCRIPT_DIR" ]; then | ||
| log_error "SCRIPT_DIR '$SCRIPT_DIR' does not exist or is not a directory." | ||
| return 1 | ||
| fi | ||
|
|
||
| if ! PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"; then | ||
| log_error "Failed to determine PROJECT_ROOT from SCRIPT_DIR '$SCRIPT_DIR'." | ||
| return 1 | ||
| fi | ||
| PROJECT_NAME="$(basename "$PROJECT_ROOT")" | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -5,22 +5,27 @@ set -e | |
| # Format all C++ source/header files using clang-format | ||
| # | ||
| # Formats all C++ files in the project according to .clang-format config. | ||
| # When run outside the container, delegates execution to Docker automatically. | ||
| # | ||
| # Usage: | ||
| # ./scripts/format.sh - Format files in-place | ||
| # ./scripts/format.sh --check - Check formatting without modifying files | ||
| ############################################################################### | ||
|
|
||
| SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" | ||
| PROJECT_ROOT="$(dirname "$SCRIPT_DIR")" | ||
| source "$SCRIPT_DIR/env.sh" | ||
| source "$SCRIPT_DIR/docker/exec.sh" | ||
| delegate_to_container "$@" | ||
|
|
||
| # Check if --check flag is passed | ||
| # --------------------------------------------------------------------------- | ||
| # Format | ||
| # --------------------------------------------------------------------------- | ||
| CHECK_MODE=false | ||
| if [[ "$1" == "--check" ]]; then | ||
| CHECK_MODE=true | ||
| echo "[INFO] Running clang-format in check mode (no modifications)..." | ||
| log_info "Running clang-format in check mode (no modifications)..." | ||
| else | ||
| echo "[INFO] Running clang-format on source files..." | ||
| log_info "Running clang-format on source files..." | ||
| fi | ||
|
|
||
| EXTENSIONS=("*.cpp" "*.hpp" "*.cc" "*.h" "*.cxx" "*.hxx") | ||
|
|
@@ -32,17 +37,17 @@ for ext in "${EXTENSIONS[@]}"; do | |
| for f in $FILES; do | ||
| FOUND=true | ||
| if $CHECK_MODE; then | ||
| echo "Checking $f" | ||
| log_step "Checking $f" | ||
| clang-format --dry-run --Werror "$f" | ||
|
||
| else | ||
| echo "Formatting $f" | ||
| log_step "Formatting $f" | ||
| clang-format -i "$f" | ||
|
||
| fi | ||
| done | ||
| done | ||
|
|
||
| if ! $FOUND; then | ||
| echo "[INFO] No files found to format." | ||
| log_warn "No files found to format." | ||
| else | ||
| echo "[INFO] clang-format complete." | ||
| log_info "clang-format complete." | ||
| fi | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When Docker isn't installed or the daemon isn't reachable, the first failing
docker ...invocation will surface as a low-level error. Adding an explicit preflight check (e.g.,command -v dockerand a lightweightdocker info/docker versionprobe) would let you emit a clearerlog_errorand exit early.