learning_ai_common_plat/scripts/docker-clean.sh

301 lines
6.9 KiB
Bash
Executable File

#!/usr/bin/env bash
# docker-clean.sh - Interactive Docker cleanup for the ByteLyst platform prototype.
set -euo pipefail
RED=$'\033[0;31m'
GREEN=$'\033[0;32m'
YELLOW=$'\033[1;33m'
CYAN=$'\033[0;36m'
BOLD=$'\033[1m'
DIM=$'\033[2m'
NC=$'\033[0m'
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
log() { echo -e "${CYAN}[docker-clean]${NC} $*"; }
ok() { echo -e "${GREEN}OK:${NC} $*"; }
warn() { echo -e "${YELLOW}WARN:${NC} $*"; }
err() { echo -e "${RED}ERROR:${NC} $*" >&2; }
require_docker() {
if ! command -v docker >/dev/null 2>&1; then
err "Docker CLI is not installed or not on PATH."
exit 1
fi
if ! docker info >/dev/null 2>&1; then
err "Docker daemon is not reachable. Start Docker Desktop or your Docker daemon and try again."
exit 1
fi
if ! docker compose version >/dev/null 2>&1; then
err "Docker Compose plugin is not available. Install/update Docker Desktop or the docker compose plugin."
exit 1
fi
}
run_cmd() {
echo -e "${DIM}$*${NC}"
"$@"
}
confirm() {
local prompt="$1"
read -r -p "$(echo -e "${BOLD}${prompt}${NC} [y/N] ")" answer
case "${answer:-}" in
y|Y|yes|YES) return 0 ;;
* ) return 1 ;;
esac
}
compose_status() {
log "Compose services in $REPO_ROOT"
cd "$REPO_ROOT"
run_cmd docker compose ps
echo ""
log "Docker disk usage"
run_cmd docker system df
}
stop_compose() {
log "Stopping compose services"
cd "$REPO_ROOT"
run_cmd docker compose stop
}
down_compose() {
log "Removing compose containers and networks"
cd "$REPO_ROOT"
run_cmd docker compose down --remove-orphans
}
down_compose_with_volumes() {
cd "$REPO_ROOT"
run_cmd docker compose down --remove-orphans --volumes
}
safe_prune() {
log "Pruning stopped containers, unused networks, dangling images, and build cache"
run_cmd docker container prune --force
run_cmd docker network prune --force
run_cmd docker image prune --force
run_cmd docker builder prune --force
}
unused_image_prune() {
run_cmd docker image prune --all --force
run_cmd docker builder prune --all --force
}
full_prune() {
run_cmd docker system prune --all --volumes --force
}
builder_prune() {
log "Pruning Docker builder cache"
run_cmd docker builder prune --all --force
}
show_menu() {
cat <<EOF
${BOLD}Docker Cleanup Menu${NC}
Repo: $REPO_ROOT
${BOLD}1${NC}) Status only
Show compose services and Docker disk usage.
${BOLD}2${NC}) Stop compose services
Keeps containers, networks, volumes, and images.
${BOLD}3${NC}) Remove compose containers and networks
Runs compose down with orphan cleanup. Keeps repo volumes.
${BOLD}4${NC}) Remove compose containers, networks, and repo compose volumes
Deletes prototype state for this repo's compose project.
${BOLD}5${NC}) Safe global prune
Removes stopped containers, unused networks, dangling images, and build cache.
${BOLD}6${NC}) Deeper image/cache prune
Removes all unused images and build cache.
${BOLD}7${NC}) Full global Docker prune
Removes all unused Docker resources, including unused volumes.
${BOLD}8${NC}) Builder cache only
Removes Docker build cache.
${BOLD}q${NC}) Quit
EOF
}
describe_level() {
case "$1" in
1)
cat <<EOF
${BOLD}You selected: Status only${NC}
This will:
- Show this repo's Docker Compose services.
- Show Docker disk usage.
- Not stop, remove, or prune anything.
After this, everything will remain exactly as it is.
EOF
;;
2)
cat <<EOF
${BOLD}You selected: Stop compose services${NC}
This will:
- Stop containers from this repo's Docker Compose stack.
- Keep the containers, networks, images, and volumes.
- Preserve prototype data in Cosmos, Azurite, and Mailpit volumes.
After this, the stack will be stopped but can be resumed with:
./scripts/prototype-up.sh
EOF
;;
3)
cat <<EOF
${BOLD}You selected: Remove compose containers and networks${NC}
This will:
- Stop and remove this repo's compose containers.
- Remove compose networks and orphan containers.
- Keep repo compose volumes.
- Preserve prototype data in Cosmos, Azurite, and Mailpit volumes.
After this, containers will be recreated the next time you start the prototype.
EOF
;;
4)
cat <<EOF
${BOLD}You selected: Remove compose containers, networks, and repo compose volumes${NC}
This will:
- Stop and remove this repo's compose containers.
- Remove compose networks and orphan containers.
- Delete this repo's compose volumes.
- Delete prototype state stored in local Cosmos, Azurite, and Mailpit volumes.
After this, the next prototype start will recreate empty local backing services.
EOF
;;
5)
cat <<EOF
${BOLD}You selected: Safe global prune${NC}
This will:
- Remove all stopped Docker containers.
- Remove unused Docker networks.
- Remove dangling image layers.
- Remove unused Docker build cache.
- Keep named volumes.
- Keep images that are still tagged or used by containers.
After this, Docker should use less disk space while preserving volumes.
EOF
;;
6)
cat <<EOF
${BOLD}You selected: Deeper image/cache prune${NC}
This will:
- Remove all unused Docker images, not just dangling layers.
- Remove all unused Docker build cache.
- Keep images used by existing containers.
- Keep named volumes.
After this, future builds and starts may need to pull or rebuild images.
EOF
;;
7)
cat <<EOF
${BOLD}You selected: Full global Docker prune${NC}
This will:
- Remove stopped containers across Docker.
- Remove unused networks across Docker.
- Remove all unused images.
- Remove build cache.
- Remove all unused volumes, including volumes from other projects if Docker considers them unused.
After this, Docker disk usage should drop the most, but other local projects may need to recreate data volumes.
EOF
;;
8)
cat <<EOF
${BOLD}You selected: Builder cache only${NC}
This will:
- Remove Docker build cache.
- Keep containers, images, networks, and volumes.
After this, future Docker builds may be slower until the cache is rebuilt.
EOF
;;
q|Q)
exit 0
;;
*)
err "Unknown cleanup level: $1"
return 1
;;
esac
}
run_level() {
case "$1" in
1) compose_status ;;
2) stop_compose ;;
3) down_compose ;;
4) down_compose_with_volumes ;;
5) safe_prune ;;
6) unused_image_prune ;;
7) full_prune ;;
8) builder_prune ;;
q|Q) exit 0 ;;
*) err "Unknown cleanup level: $1"; exit 1 ;;
esac
}
if [[ $# -gt 0 ]]; then
warn "This script is interactive and does not accept CLI parameters. Ignoring: $*"
fi
show_menu
read -r -p "Select cleanup level: " LEVEL
describe_level "${LEVEL:-q}"
if [[ "${LEVEL:-q}" == "1" ]]; then
echo ""
require_docker
run_level "$LEVEL"
ok "Done."
exit 0
fi
echo ""
if ! confirm "Proceed with this cleanup?"; then
warn "Cancelled. No cleanup was performed."
exit 0
fi
echo ""
require_docker
run_level "${LEVEL:-q}"
ok "Done."