feat: container management tools in tools/
Shell scripts for build, start, stop, restart, nuke, logs, status. Shared helpers in _common.sh (colours, compose detection, project root). Updated CHEATSHEET.md with new tool references. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -53,14 +53,21 @@ format = "json" # JSONL output (default: "text")
|
|||||||
## Container
|
## Container
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
make build # Build image (only for dep changes)
|
tools/build # Build image
|
||||||
make up # Start (podman-compose)
|
tools/build --no-cache # Rebuild from scratch
|
||||||
make down # Stop
|
tools/start # Start (builds if no image)
|
||||||
make logs # Follow logs
|
tools/stop # Stop and remove container
|
||||||
|
tools/restart # Stop + rebuild + start
|
||||||
|
tools/restart --no-cache # Full clean restart
|
||||||
|
tools/logs # Tail logs (default 30 lines)
|
||||||
|
tools/logs 100 # Tail last 100 lines
|
||||||
|
tools/status # Container, image, mount state
|
||||||
|
tools/nuke # Full teardown (container + image)
|
||||||
```
|
```
|
||||||
|
|
||||||
Code, plugins, config, and data are bind-mounted. No rebuild needed for
|
Code, plugins, config, and data are bind-mounted. No rebuild needed for
|
||||||
code changes -- restart the container or use `!reload` for plugins.
|
code changes -- restart the container or use `!reload` for plugins.
|
||||||
|
Rebuild only when `requirements.txt` or `Containerfile` change.
|
||||||
|
|
||||||
## Bot Commands
|
## Bot Commands
|
||||||
|
|
||||||
|
|||||||
38
tools/_common.sh
Normal file
38
tools/_common.sh
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Shared helpers for derp container tools.
|
||||||
|
# Sourced, not executed.
|
||||||
|
# shellcheck disable=SC2034
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[1]}")" && pwd)"
|
||||||
|
PROJECT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
|
||||||
|
|
||||||
|
# Compose command detection
|
||||||
|
if podman compose version &>/dev/null; then
|
||||||
|
COMPOSE="podman compose"
|
||||||
|
elif command -v podman-compose &>/dev/null; then
|
||||||
|
COMPOSE="podman-compose"
|
||||||
|
else
|
||||||
|
echo "error: podman compose or podman-compose required" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
CONTAINER_NAME="derp"
|
||||||
|
# podman-compose names images <project>_<service>
|
||||||
|
IMAGE_NAME="derp_derp"
|
||||||
|
|
||||||
|
# Colors (suppressed if NO_COLOR is set or stdout isn't a tty)
|
||||||
|
if [[ -z "${NO_COLOR:-}" ]] && [[ -t 1 ]]; then
|
||||||
|
GRN='\e[38;5;108m'
|
||||||
|
RED='\e[38;5;131m'
|
||||||
|
BLU='\e[38;5;110m'
|
||||||
|
DIM='\e[2m'
|
||||||
|
RST='\e[0m'
|
||||||
|
else
|
||||||
|
GRN='' RED='' BLU='' DIM='' RST=''
|
||||||
|
fi
|
||||||
|
|
||||||
|
info() { printf "${GRN}%s${RST} %s\n" "✓" "$*"; }
|
||||||
|
err() { printf "${RED}%s${RST} %s\n" "✗" "$*" >&2; }
|
||||||
|
dim() { printf "${DIM} %s${RST}\n" "$*"; }
|
||||||
21
tools/build
Executable file
21
tools/build
Executable file
@@ -0,0 +1,21 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Build or rebuild the derp container image.
|
||||||
|
# Usage: tools/build [--no-cache]
|
||||||
|
|
||||||
|
# shellcheck source=tools/_common.sh
|
||||||
|
source "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/_common.sh"
|
||||||
|
cd "$PROJECT_DIR" || exit 1
|
||||||
|
|
||||||
|
args=()
|
||||||
|
[[ "${1:-}" == "--no-cache" ]] && args+=(--no-cache)
|
||||||
|
|
||||||
|
dim "Building image..."
|
||||||
|
$COMPOSE build "${args[@]}"
|
||||||
|
|
||||||
|
size=$(podman image inspect "$IMAGE_NAME" --format '{{.Size}}' 2>/dev/null || true)
|
||||||
|
if [[ -n "$size" ]]; then
|
||||||
|
human=$(numfmt --to=iec-i --suffix=B "$size" 2>/dev/null || echo "${size} bytes")
|
||||||
|
info "Image built ($human)"
|
||||||
|
else
|
||||||
|
info "Image built"
|
||||||
|
fi
|
||||||
9
tools/logs
Executable file
9
tools/logs
Executable file
@@ -0,0 +1,9 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Tail container logs.
|
||||||
|
# Usage: tools/logs [N]
|
||||||
|
|
||||||
|
# shellcheck source=tools/_common.sh
|
||||||
|
source "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/_common.sh"
|
||||||
|
|
||||||
|
tail_n="${1:-30}"
|
||||||
|
podman logs -f --tail "$tail_n" "$CONTAINER_NAME"
|
||||||
26
tools/nuke
Executable file
26
tools/nuke
Executable file
@@ -0,0 +1,26 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Full teardown: stop container and remove image.
|
||||||
|
# Usage: tools/nuke
|
||||||
|
|
||||||
|
# shellcheck source=tools/_common.sh
|
||||||
|
source "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/_common.sh"
|
||||||
|
cd "$PROJECT_DIR" || exit 1
|
||||||
|
|
||||||
|
dim "Stopping container..."
|
||||||
|
$COMPOSE down 2>/dev/null || true
|
||||||
|
|
||||||
|
before=$(podman system df --format '{{.Size}}' 2>/dev/null | head -1 || true)
|
||||||
|
|
||||||
|
dim "Removing image..."
|
||||||
|
podman rmi "$IMAGE_NAME" 2>/dev/null || true
|
||||||
|
# Also remove any dangling derp images
|
||||||
|
podman images --filter "reference=*derp*" --format '{{.ID}}' 2>/dev/null | \
|
||||||
|
xargs -r podman rmi 2>/dev/null || true
|
||||||
|
|
||||||
|
after=$(podman system df --format '{{.Size}}' 2>/dev/null | head -1 || true)
|
||||||
|
|
||||||
|
if [[ -n "$before" && -n "$after" ]]; then
|
||||||
|
info "Teardown complete (images: $before -> $after)"
|
||||||
|
else
|
||||||
|
info "Teardown complete"
|
||||||
|
fi
|
||||||
15
tools/restart
Executable file
15
tools/restart
Executable file
@@ -0,0 +1,15 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Stop, rebuild, and start the derp container.
|
||||||
|
# Usage: tools/restart [--no-cache]
|
||||||
|
|
||||||
|
# shellcheck source=tools/_common.sh
|
||||||
|
source "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/_common.sh"
|
||||||
|
|
||||||
|
args=()
|
||||||
|
[[ "${1:-}" == "--no-cache" ]] && args+=("--no-cache")
|
||||||
|
|
||||||
|
"$SCRIPT_DIR/stop"
|
||||||
|
echo
|
||||||
|
"$SCRIPT_DIR/build" "${args[@]}"
|
||||||
|
echo
|
||||||
|
"$SCRIPT_DIR/start"
|
||||||
23
tools/start
Executable file
23
tools/start
Executable file
@@ -0,0 +1,23 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Start the derp container.
|
||||||
|
# Usage: tools/start
|
||||||
|
|
||||||
|
# shellcheck source=tools/_common.sh
|
||||||
|
source "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/_common.sh"
|
||||||
|
cd "$PROJECT_DIR" || exit 1
|
||||||
|
|
||||||
|
# Build first if no image exists
|
||||||
|
if ! podman image exists "$IMAGE_NAME" 2>/dev/null; then
|
||||||
|
dim "No image found, building..."
|
||||||
|
"$SCRIPT_DIR/build"
|
||||||
|
echo
|
||||||
|
fi
|
||||||
|
|
||||||
|
dim "Starting container..."
|
||||||
|
$COMPOSE up -d
|
||||||
|
|
||||||
|
sleep 3
|
||||||
|
dim "Recent logs:"
|
||||||
|
podman logs --tail 15 "$CONTAINER_NAME" 2>&1 || true
|
||||||
|
echo
|
||||||
|
info "Container started"
|
||||||
46
tools/status
Executable file
46
tools/status
Executable file
@@ -0,0 +1,46 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Show container and image state.
|
||||||
|
# Usage: tools/status
|
||||||
|
|
||||||
|
# shellcheck source=tools/_common.sh
|
||||||
|
source "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/_common.sh"
|
||||||
|
|
||||||
|
# -- Container ----------------------------------------------------------------
|
||||||
|
printf '%b%s%b\n' "$BLU" "Container" "$RST"
|
||||||
|
state=$(podman inspect "$CONTAINER_NAME" --format '{{.State.Status}}' 2>/dev/null || true)
|
||||||
|
if [[ -z "$state" ]]; then
|
||||||
|
dim "absent"
|
||||||
|
elif [[ "$state" == "running" ]]; then
|
||||||
|
uptime=$(podman inspect "$CONTAINER_NAME" --format '{{.State.StartedAt}}' 2>/dev/null || true)
|
||||||
|
info "running (since ${uptime%.*})"
|
||||||
|
else
|
||||||
|
info "$state"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo
|
||||||
|
|
||||||
|
# -- Image --------------------------------------------------------------------
|
||||||
|
printf '%b%s%b\n' "$BLU" "Image" "$RST"
|
||||||
|
if podman image exists "$IMAGE_NAME" 2>/dev/null; then
|
||||||
|
img_info=$(podman image inspect "$IMAGE_NAME" --format '{{.Created}} {{.Size}}' 2>/dev/null || true)
|
||||||
|
created="${img_info%% *}"
|
||||||
|
size="${img_info##* }"
|
||||||
|
human=$(numfmt --to=iec-i --suffix=B "$size" 2>/dev/null || echo "${size}B")
|
||||||
|
info "$IMAGE_NAME ($human, ${created%T*})"
|
||||||
|
else
|
||||||
|
dim "no image"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo
|
||||||
|
|
||||||
|
# -- Volumes ------------------------------------------------------------------
|
||||||
|
printf '%b%s%b\n' "$BLU" "Mounts" "$RST"
|
||||||
|
mounts=(src plugins config/derp.toml data secrets)
|
||||||
|
for m in "${mounts[@]}"; do
|
||||||
|
path="$PROJECT_DIR/$m"
|
||||||
|
if [[ -e "$path" ]]; then
|
||||||
|
info "$m"
|
||||||
|
else
|
||||||
|
err "$m (missing)"
|
||||||
|
fi
|
||||||
|
done
|
||||||
11
tools/stop
Executable file
11
tools/stop
Executable file
@@ -0,0 +1,11 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Stop and remove the derp container.
|
||||||
|
# Usage: tools/stop
|
||||||
|
|
||||||
|
# shellcheck source=tools/_common.sh
|
||||||
|
source "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/_common.sh"
|
||||||
|
cd "$PROJECT_DIR" || exit 1
|
||||||
|
|
||||||
|
dim "Stopping container..."
|
||||||
|
$COMPOSE down
|
||||||
|
info "Container stopped"
|
||||||
Reference in New Issue
Block a user