mirror of
https://github.com/johndoe6345789/metabuilder.git
synced 2026-04-24 13:54:57 +00:00
203 lines
6.4 KiB
Bash
Executable File
203 lines
6.4 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# Build Docker images for all MetaBuilder web applications.
|
|
# Uses multi-stage Dockerfiles — no local pre-building required.
|
|
#
|
|
# Usage:
|
|
# ./build-apps.sh Build missing app images (skip existing)
|
|
# ./build-apps.sh --force Rebuild all app images
|
|
# ./build-apps.sh workflowui Build specific app image
|
|
# ./build-apps.sh --sequential Build sequentially (less RAM)
|
|
|
|
set -e
|
|
|
|
RED='\033[0;31m'
|
|
GREEN='\033[0;32m'
|
|
YELLOW='\033[1;33m'
|
|
NC='\033[0m'
|
|
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
COMPOSE_FILE="$SCRIPT_DIR/docker-compose.stack.yml"
|
|
|
|
# Ensure base-node-deps exists — all frontend Dockerfiles depend on it.
|
|
# Other base images (apt, conan, pip, android-sdk) are only needed for
|
|
# C++ daemons, dev containers, and workflow plugins.
|
|
ensure_node_deps_base() {
|
|
if docker image inspect "metabuilder/base-node-deps:latest" &>/dev/null; then
|
|
echo -e "${GREEN}Base image metabuilder/base-node-deps:latest exists${NC}"
|
|
return 0
|
|
fi
|
|
|
|
echo -e "${YELLOW}Building metabuilder/base-node-deps (required by all Node.js frontends)...${NC}"
|
|
local REPO_ROOT
|
|
REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
|
docker build \
|
|
-f "$SCRIPT_DIR/base-images/Dockerfile.node-deps" \
|
|
-t metabuilder/base-node-deps:latest \
|
|
"$REPO_ROOT"
|
|
|
|
if [ $? -ne 0 ]; then
|
|
echo -e "${RED}Failed to build base-node-deps — cannot proceed with app builds${NC}"
|
|
exit 1
|
|
fi
|
|
echo -e "${GREEN}Built metabuilder/base-node-deps:latest${NC}"
|
|
}
|
|
|
|
# Check optional base images (warn only, don't block)
|
|
check_optional_bases() {
|
|
local missing=()
|
|
local bases=(
|
|
"metabuilder/base-apt:latest"
|
|
"metabuilder/base-conan-deps:latest"
|
|
"metabuilder/base-pip-deps:latest"
|
|
"metabuilder/base-android-sdk:latest"
|
|
)
|
|
for img in "${bases[@]}"; do
|
|
if ! docker image inspect "$img" &>/dev/null; then
|
|
missing+=("$img")
|
|
fi
|
|
done
|
|
if [ ${#missing[@]} -gt 0 ]; then
|
|
echo -e "${YELLOW}Optional base images not built (C++ daemons, dev container):${NC}"
|
|
for img in "${missing[@]}"; do
|
|
echo " - $img"
|
|
done
|
|
echo -e "${YELLOW}Build with:${NC} ./build-base-images.sh"
|
|
echo ""
|
|
fi
|
|
}
|
|
|
|
ensure_node_deps_base
|
|
check_optional_bases
|
|
|
|
PARALLEL=true
|
|
FORCE=false
|
|
TARGETS=()
|
|
|
|
for arg in "$@"; do
|
|
case "$arg" in
|
|
--sequential) PARALLEL=false ;;
|
|
--force) FORCE=true ;;
|
|
*) TARGETS+=("$arg") ;;
|
|
esac
|
|
done
|
|
|
|
# Note: media-daemon excluded — C++ source not yet complete (WIP: tv, radio, retro gaming)
|
|
ALL_APPS=(workflowui codegen pastebin postgres emailclient exploded-diagrams storybook frontend-app dbal)
|
|
|
|
# Map friendly name to docker compose service name
|
|
resolve_service() {
|
|
case "$1" in
|
|
workflowui) echo "workflowui" ;;
|
|
codegen) echo "codegen" ;;
|
|
pastebin) echo "pastebin" ;;
|
|
postgres) echo "postgres-dashboard" ;;
|
|
emailclient) echo "emailclient-app" ;;
|
|
exploded-diagrams) echo "exploded-diagrams" ;;
|
|
storybook) echo "storybook" ;;
|
|
frontend-app) echo "frontend-app" ;;
|
|
dbal) echo "dbal" ;;
|
|
*) echo "" ;;
|
|
esac
|
|
}
|
|
|
|
# If no targets specified, build all
|
|
if [ ${#TARGETS[@]} -eq 0 ]; then
|
|
TARGETS=("${ALL_APPS[@]}")
|
|
fi
|
|
|
|
# Resolve service names
|
|
SERVICES=()
|
|
for target in "${TARGETS[@]}"; do
|
|
service="$(resolve_service "$target")"
|
|
if [ -z "$service" ]; then
|
|
echo -e "${RED}Unknown target: $target${NC}"
|
|
echo "Available: ${ALL_APPS[*]}"
|
|
exit 1
|
|
fi
|
|
SERVICES+=("$service")
|
|
done
|
|
|
|
# Skip services whose images already exist (unless --force)
|
|
if [[ "$FORCE" != "true" ]]; then
|
|
NEEDS_BUILD=()
|
|
NEEDS_BUILD_NAMES=()
|
|
for i in "${!TARGETS[@]}"; do
|
|
target="${TARGETS[$i]}"
|
|
service="${SERVICES[$i]}"
|
|
img="deployment-${service}"
|
|
if docker image inspect "$img" &>/dev/null; then
|
|
echo -e "${GREEN}Skipping $target${NC} — image $img already exists (use --force to rebuild)"
|
|
else
|
|
NEEDS_BUILD_NAMES+=("$target")
|
|
NEEDS_BUILD+=("$service")
|
|
fi
|
|
done
|
|
if [ ${#NEEDS_BUILD[@]} -eq 0 ]; then
|
|
echo ""
|
|
echo -e "${GREEN}All app images already built! Use --force to rebuild.${NC}"
|
|
exit 0
|
|
fi
|
|
TARGETS=("${NEEDS_BUILD_NAMES[@]}")
|
|
SERVICES=("${NEEDS_BUILD[@]}")
|
|
fi
|
|
|
|
echo -e "${YELLOW}Building: ${TARGETS[*]}${NC}"
|
|
echo ""
|
|
|
|
# Pre-pull base images that app Dockerfiles depend on (with retry for flaky connections)
|
|
echo -e "${YELLOW}Pre-pulling base images for app builds...${NC}"
|
|
for img in "node:20-alpine" "node:22-alpine" "python:3.11-slim" "python:3.12-slim" "alpine:3.19"; do
|
|
if ! docker image inspect "$img" &>/dev/null; then
|
|
echo " Pulling $img..."
|
|
for i in 1 2 3 4 5; do
|
|
docker pull "$img" && break \
|
|
|| (echo " Retry $i/5..." && sleep $((i * 10)))
|
|
done
|
|
fi
|
|
done
|
|
echo ""
|
|
|
|
MAX_BUILD_ATTEMPTS=5
|
|
BUILD_ATTEMPT=0
|
|
BUILD_OK=false
|
|
|
|
while [ $BUILD_ATTEMPT -lt $MAX_BUILD_ATTEMPTS ]; do
|
|
BUILD_ATTEMPT=$((BUILD_ATTEMPT + 1))
|
|
[ $BUILD_ATTEMPT -gt 1 ] && echo -e "${YELLOW}Build attempt $BUILD_ATTEMPT/$MAX_BUILD_ATTEMPTS...${NC}"
|
|
|
|
if [ "$PARALLEL" = true ]; then
|
|
echo -e "${YELLOW}Parallel build (uses more RAM)...${NC}"
|
|
docker compose -f "$COMPOSE_FILE" build --parallel "${SERVICES[@]}" && BUILD_OK=true && break
|
|
else
|
|
# Build each service individually to avoid bandwidth contention
|
|
ALL_OK=true
|
|
for svc in "${SERVICES[@]}"; do
|
|
echo -e "${YELLOW}Building $svc...${NC}"
|
|
if ! docker compose -f "$COMPOSE_FILE" build "$svc"; then
|
|
echo -e "${RED}Failed: $svc${NC}"
|
|
ALL_OK=false
|
|
break
|
|
fi
|
|
echo -e "${GREEN}Done: $svc${NC}"
|
|
done
|
|
[ "$ALL_OK" = true ] && BUILD_OK=true && break
|
|
fi
|
|
|
|
if [ $BUILD_ATTEMPT -lt $MAX_BUILD_ATTEMPTS ]; then
|
|
WAIT=$(( BUILD_ATTEMPT * 10 ))
|
|
echo -e "${YELLOW}Build failed (attempt $BUILD_ATTEMPT/$MAX_BUILD_ATTEMPTS), retrying in ${WAIT}s...${NC}"
|
|
sleep $WAIT
|
|
fi
|
|
done
|
|
|
|
if [ "$BUILD_OK" != "true" ]; then
|
|
echo -e "${RED}Build failed after $MAX_BUILD_ATTEMPTS attempts${NC}"
|
|
exit 1
|
|
fi
|
|
|
|
echo ""
|
|
echo -e "${GREEN}Build complete!${NC}"
|
|
echo ""
|
|
echo "Start with: ./start-stack.sh"
|
|
echo "Or: docker compose -f $COMPOSE_FILE up -d ${SERVICES[*]}"
|