251 lines
7.7 KiB
Bash
Executable File
251 lines
7.7 KiB
Bash
Executable File
#!/bin/bash
|
|
# Efficient development container workflow - persistent container for debugging
|
|
|
|
set -euo pipefail
|
|
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
PROJECT_ROOT="$(dirname "$SCRIPT_DIR")"
|
|
|
|
# Container configuration
|
|
CONTAINER_NAME="zero-os-dev"
|
|
BUILDER_IMAGE="zero-os-builder:latest"
|
|
|
|
# Default to verbose, streaming logs for dev flows unless explicitly disabled
|
|
export DEBUG="${DEBUG:-1}"
|
|
|
|
# Source common functions
|
|
source "${SCRIPT_DIR}/lib/common.sh"
|
|
|
|
function show_usage() {
|
|
cat << EOF
|
|
Zero OS Development Container Manager
|
|
|
|
Usage: $0 [COMMAND]
|
|
|
|
Commands:
|
|
start Start persistent development container
|
|
stop Stop development container
|
|
shell Enter development container shell
|
|
build Run build in persistent container
|
|
clean Clean and restart container
|
|
status Show container status
|
|
logs Show container logs
|
|
|
|
Environment Variables:
|
|
DEBUG Enable debug output (default: 1 for dev)
|
|
|
|
Examples:
|
|
$0 start # Start persistent container
|
|
$0 shell # Enter container for debugging
|
|
$0 build # Run build in persistent container
|
|
EOF
|
|
}
|
|
|
|
function ensure_builder_image() {
|
|
section_header "Ensuring Builder Image"
|
|
# Check for existing image under common tags (short and localhost-qualified)
|
|
local candidates=("$BUILDER_IMAGE" "localhost/${BUILDER_IMAGE}")
|
|
for img in "${candidates[@]}"; do
|
|
if podman image exists "$img" 2>/dev/null; then
|
|
log_info "Found builder image: ${img}"
|
|
BUILDER_IMAGE="$img"
|
|
return 0
|
|
fi
|
|
done
|
|
log_warn "Builder image not found locally; building: ${BUILDER_IMAGE}"
|
|
safe_execute podman build -t "${BUILDER_IMAGE}" -f "${PROJECT_ROOT}/Dockerfile" "${PROJECT_ROOT}"
|
|
if podman image exists "$BUILDER_IMAGE" 2>/dev/null; then
|
|
log_info "Builder image built successfully: ${BUILDER_IMAGE}"
|
|
return 0
|
|
fi
|
|
# As a fallback, also tag with localhost to satisfy Podman short-name policy
|
|
local local_tag="localhost/${BUILDER_IMAGE}"
|
|
log_info "Tagging builder image as ${local_tag}"
|
|
safe_execute podman tag "${BUILDER_IMAGE}" "${local_tag}" || true
|
|
if podman image exists "$local_tag" 2>/dev/null; then
|
|
BUILDER_IMAGE="$local_tag"
|
|
fi
|
|
}
|
|
|
|
function dev_container_start() {
|
|
section_header "Starting Development Container"
|
|
|
|
# Ensure builder image exists (handles clean --all case and short-name policy)
|
|
ensure_builder_image
|
|
|
|
# Check if container already exists
|
|
if podman container exists "$CONTAINER_NAME" 2>/dev/null; then
|
|
if podman container inspect "$CONTAINER_NAME" --format '{{.State.Status}}' | grep -q "running"; then
|
|
log_info "Development container already running"
|
|
return 0
|
|
else
|
|
log_info "Starting existing development container"
|
|
safe_execute podman start "$CONTAINER_NAME"
|
|
return 0
|
|
fi
|
|
fi
|
|
|
|
log_info "Creating new development container: ${CONTAINER_NAME}"
|
|
|
|
# Create persistent container with all necessary mounts and environment
|
|
safe_execute podman run -d \
|
|
--name "$CONTAINER_NAME" \
|
|
--privileged \
|
|
-v "${PROJECT_ROOT}:/workspace" \
|
|
-w /workspace \
|
|
-e DEBUG=1 \
|
|
-e ALPINE_VERSION=3.22 \
|
|
-e KERNEL_VERSION=6.12.44 \
|
|
-e RUST_TARGET=x86_64-unknown-linux-musl \
|
|
-e OPTIMIZATION_LEVEL=max \
|
|
"$BUILDER_IMAGE" \
|
|
sleep infinity
|
|
|
|
log_info "Development container started successfully"
|
|
log_info "Container name: ${CONTAINER_NAME}"
|
|
log_info "Access with: $0 shell"
|
|
}
|
|
|
|
function dev_container_stop() {
|
|
section_header "Stopping Development Container"
|
|
|
|
if podman container exists "$CONTAINER_NAME" 2>/dev/null; then
|
|
log_info "Stopping development container: ${CONTAINER_NAME}"
|
|
safe_execute podman stop "$CONTAINER_NAME"
|
|
log_info "Development container stopped"
|
|
else
|
|
log_info "Development container not found"
|
|
fi
|
|
}
|
|
|
|
function dev_container_shell() {
|
|
section_header "Entering Development Container Shell"
|
|
|
|
if ! podman container exists "$CONTAINER_NAME" 2>/dev/null; then
|
|
log_info "Development container not found, starting..."
|
|
dev_container_start
|
|
fi
|
|
|
|
if ! podman container inspect "$CONTAINER_NAME" --format '{{.State.Status}}' | grep -q "running"; then
|
|
log_info "Starting stopped development container"
|
|
safe_execute podman start "$CONTAINER_NAME"
|
|
fi
|
|
|
|
log_info "Entering container shell (exit with 'exit' or Ctrl+D)"
|
|
# Use direct execution for interactive shell (don't use safe_execute)
|
|
exec podman exec -it "$CONTAINER_NAME" /bin/bash
|
|
}
|
|
|
|
function dev_container_build() {
|
|
section_header "Running Build in Development Container"
|
|
|
|
if ! podman container exists "$CONTAINER_NAME" 2>/dev/null; then
|
|
log_info "Development container not found, starting..."
|
|
dev_container_start
|
|
fi
|
|
|
|
if ! podman container inspect "$CONTAINER_NAME" --format '{{.State.Status}}' | grep -q "running"; then
|
|
log_info "Starting stopped development container"
|
|
safe_execute podman start "$CONTAINER_NAME"
|
|
fi
|
|
|
|
log_info "Running build in persistent container (real-time output)"
|
|
log_info "Command: podman exec $CONTAINER_NAME ./scripts/build.sh $*"
|
|
|
|
# Use direct execution to show real-time output (bypass safe_execute)
|
|
podman exec "$CONTAINER_NAME" ./scripts/build.sh "$@"
|
|
local exit_code=$?
|
|
|
|
if [[ $exit_code -eq 0 ]]; then
|
|
log_info "Build completed successfully in container"
|
|
else
|
|
log_error "Build failed in container with exit code: $exit_code"
|
|
fi
|
|
|
|
return $exit_code
|
|
}
|
|
|
|
function dev_container_clean() {
|
|
section_header "Cleaning Development Container"
|
|
|
|
if podman container exists "$CONTAINER_NAME" 2>/dev/null; then
|
|
log_info "Removing existing development container"
|
|
safe_execute podman rm -f "$CONTAINER_NAME"
|
|
fi
|
|
|
|
log_info "Starting fresh development container"
|
|
dev_container_start
|
|
}
|
|
|
|
function dev_container_status() {
|
|
section_header "Development Container Status"
|
|
|
|
if podman container exists "$CONTAINER_NAME" 2>/dev/null; then
|
|
local status=$(podman container inspect "$CONTAINER_NAME" --format '{{.State.Status}}')
|
|
local created=$(podman container inspect "$CONTAINER_NAME" --format '{{.Created}}')
|
|
|
|
log_info "Container: ${CONTAINER_NAME}"
|
|
log_info "Status: ${status}"
|
|
log_info "Created: ${created}"
|
|
|
|
if [[ "$status" == "running" ]]; then
|
|
log_info "✓ Ready for development"
|
|
else
|
|
log_info "⚠ Container stopped - use '$0 start' to start"
|
|
fi
|
|
else
|
|
log_info "Development container not found"
|
|
log_info "Use '$0 start' to create"
|
|
fi
|
|
}
|
|
|
|
function dev_container_logs() {
|
|
section_header "Development Container Logs"
|
|
|
|
if podman container exists "$CONTAINER_NAME" 2>/dev/null; then
|
|
safe_execute podman logs "$CONTAINER_NAME"
|
|
else
|
|
log_error "Development container not found"
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
# Main function
|
|
function main() {
|
|
local command="${1:-help}"
|
|
|
|
case "$command" in
|
|
start)
|
|
dev_container_start
|
|
;;
|
|
stop)
|
|
dev_container_stop
|
|
;;
|
|
shell)
|
|
dev_container_shell
|
|
;;
|
|
build)
|
|
shift
|
|
dev_container_build "$@"
|
|
;;
|
|
clean)
|
|
dev_container_clean
|
|
;;
|
|
status)
|
|
dev_container_status
|
|
;;
|
|
logs)
|
|
dev_container_logs
|
|
;;
|
|
help|--help|-h)
|
|
show_usage
|
|
;;
|
|
*)
|
|
log_error "Unknown command: $command"
|
|
show_usage
|
|
exit 1
|
|
;;
|
|
esac
|
|
}
|
|
|
|
main "$@" |