From 75e1d916d2a9dd23cc4cc5a0ae540e8c17c8d2b4 Mon Sep 17 00:00:00 2001 From: Job79 Date: Sun, 15 Mar 2026 15:54:31 +0100 Subject: [PATCH] refactor: simplify devc script --- containers/go/config.sh | 2 +- containers/infra/config.sh | 2 +- containers/php/config.sh | 2 +- devc.sh | 168 +++++++++++++++---------------------- 4 files changed, 71 insertions(+), 103 deletions(-) diff --git a/containers/go/config.sh b/containers/go/config.sh index a322442..5ad5c3b 100644 --- a/containers/go/config.sh +++ b/containers/go/config.sh @@ -1,2 +1,2 @@ #!/bin/bash -arg "-v $HOME/Documents/go:/home/user/Documents/go" +run_opts+=("-v" "$HOME/Documents/go:/home/user/Documents/go") diff --git a/containers/infra/config.sh b/containers/infra/config.sh index 6da152c..1179e77 100644 --- a/containers/infra/config.sh +++ b/containers/infra/config.sh @@ -1,2 +1,2 @@ #!/bin/bash -arg "-v $HOME/Documents/infra:/home/user/Documents/infra" +run_opts+=("-v" "$HOME/Documents/infra:/home/user/Documents/infra") diff --git a/containers/php/config.sh b/containers/php/config.sh index 4ab88f9..624524b 100644 --- a/containers/php/config.sh +++ b/containers/php/config.sh @@ -1,2 +1,2 @@ #!/bin/bash -arg "-v $HOME/Documents/php:/home/user/Documents/php" +run_opts+=("-v" "$HOME/Documents/php:/home/user/Documents/php") diff --git a/devc.sh b/devc.sh index c0d5938..892ec35 100755 --- a/devc.sh +++ b/devc.sh @@ -1,122 +1,90 @@ #!/bin/bash # =============================================== # -# devc.sh v2.0; job79, maurice # -# Dev container enter script. Handles setting up # -# different dev containers, resuming sessions and # -# automatic container updates. # +# devc.sh v2.1; job79, maurice # +# Dev container entry script. # # =============================================== # set -euo pipefail log() { printf '\e[%sm%s\e[0m %s\n' "${3:-36}" "${2:-○}" "$1"; } -arg() { echo -n " $@"; } - -# run_args returns the container run arguments required for -# starting a new container. -default_args() { - arg "--name $name" - arg "--hostname $name" - - # Pull newer container image if available. - arg "--pull=newer" - - # Use keep-id so the container user matches the host user. - arg "--userns=keep-id" - - # Add container to devc network. - arg "--net devc" - - # Disable selinux labeling so unix sockets can be mounted - # without problems. - [ -d /sys/fs/selinux ] && arg "--security-opt label=disable" - - # Mount the wayland socket. Required to get the system - # clipboard (wl-copy) and gui applications working. - [ -e "/run/user/$UID/wayland-0" ] && arg "-v /run/user/$UID/wayland-0:/run/user/1000/wayland-0" - - # Mount the ssh socket to get ssh working. - [ -e "$SSH_AUTH_SOCK" ] && arg "-v $SSH_AUTH_SOCK:/run/user/1000/ssh-auth-sock" - - # Make the user home dir a volume so it survives container - # restarts. Use copy to keep the files from the image. - arg "-v $name:/home/user:copy" - - # If there is custom configuration for the container, load - # it here. - config_file="$(dirname "$(realpath "$0")")/containers/$name/config.sh" - [ -f "$config_file" ] && source "${config_file}" +die() { + log "$1" 'x' 31 + exit 1 } -# param_args returns the container run arguments based on the -# arguments provided to this script. +# default_args configures standard container options. +default_args() { + run_opts+=( + "--name" "$name" + "--hostname" "$name" + "--pull=newer" # Update image. + "--userns=keep-id" # Map host user. + "--net=devc" # Shared network. + "-v" "$name:/home/user:copy" # Persistent home volume. + ) + + # Unix sockets require SELinux label disable. + [[ -d /sys/fs/selinux ]] && run_opts+=("--security-opt" "label=disable") + + # Desktop integration (Wayland, SSH). + [[ -e "/run/user/$UID/wayland-0" ]] && run_opts+=("-v" "/run/user/$UID/wayland-0:/run/user/1000/wayland-0") + [[ -e "${SSH_AUTH_SOCK:-}" ]] && run_opts+=("-v" "$SSH_AUTH_SOCK:/run/user/1000/ssh-auth-sock") + + # Load custom container config. + local config_file="$(dirname "$(realpath "$0")")/containers/$name/config.sh" + [[ -f "$config_file" ]] && source "${config_file}" +} + +# param_args parses CLI arguments into podman run options. param_args() { - while test $# -gt 0; do + while (($# > 0)); do case "$1" in - -gpu) # Enable gpu acceleration. - arg "--device /dev/dri" ;; - -host-spawn) # Enable spawning host commands from inside the container using host-spawn. - arg "-v /run/user/$UID/bus:/tmp/bus" - arg "-e HOST_HOME=$HOME" # Used to translate paths. + -gpu) run_opts+=("--device" "/dev/dri") ;; + -host-spawn) run_opts+=("-v" "/run/user/$UID/bus:/tmp/bus" "-e" "HOST_HOME=$HOME") ;; + -container-sock) run_opts+=("-v" "${XDG_RUNTIME_DIR:-/run/user/$UID}/podman/podman.sock:/var/run/docker.sock") ;; + -x11) + run_opts+=("-v" "/tmp/.X11-unix:/tmp/.X11-unix" "-v" "${XAUTHORITY:-$HOME/.Xauthority}:/run/user/1000/.Xauthority:ro") + run_opts+=("-e" "DISPLAY=${DISPLAY:-:0}" "-e" "XAUTHORITY=/run/user/1000/.Xauthority") ;; - -container-sock) # Mount container sock into the container. - case "$(basename "$engine")" in - podman) arg "-v /run/user/$UID/podman/podman.sock:/var/run/docker.sock" ;; - docker) arg "-v /var/run/docker.sock:/var/run/docker.sock" ;; - esac - ;; - -x11) # Enable X11 support. - arg "-v /tmp/.X11-unix:/tmp/.X11-unix" - arg "-v $XAUTHORITY:/run/user/1000/.Xauthority:ro" - arg "-e DISPLAY=$DISPLAY" - arg "-e XAUTHORITY=/run/user/1000/.Xauthority" - ;; - -mnt) # Mount directory. - arg "-w /mnt/ -v $2:/mnt/$([ ! -d "$2" ] && echo 'file')" + -mnt) + local type='' + [[ ! -d "$2" ]] && type='file' + run_opts+=("-w" "/mnt/" "-v" "$2:/mnt/$type") shift ;; - *) # Use unknown arguments as container arguments. - arg "$1" ;; + *) run_opts+=("$1") ;; esac shift done } -### MAIN ### -engine="$(command -v podman || command -v docker)" -[ -z "$engine" ] && echo "no container engine found" && exit 1 +main() { + local state_file="$HOME/.local/share/devc-previous-container" + local image="${1:-}" -# Get the devcontainer name from the first argument. If not -# provided, use the last used name when possible. -if [[ $# -gt 0 ]] && [[ ${1:-} != -* ]]; then - image="$1" - [[ "$image" != *:* ]] && image="$image:main" - echo "$image" >"$HOME/.local/share/devc-previous-container" - shift -elif [ -f "$HOME/.local/share/devc-previous-container" ]; then - image=$(<"$HOME/.local/share/devc-previous-container") -else - log "no container name specified" 'x' 31 - exit 1 -fi -name="${image%:*}" + # Resolve container name (CLI arg > Last used > Error). + if [[ $image && $image != -* ]]; then + shift + [[ $image == *:* ]] || image+=":main" + mkdir -p "${state_file%/*}" && echo "$image" >"$state_file" + elif [[ -f $state_file ]]; then + image=$(<$state_file) + else + die "no container name specified" + fi + local name="${image%:*}" -# Get container registry from the DEVC_REGISTRY env -# variable. -registry="${DEVC_REGISTRY:-}" -if [ -z "$registry" ]; then - log "registry unknown; set the DEVC_REGISTRY environment variable" 'x' 31 - exit 1 -fi + # Start/Restart if not running or if arguments change configuration. + if [[ -z "$(podman ps -q -f name="^$name$" -f status=running)" ]] || (($# > 0)); then + log "starting $image..." + [[ -n "${DEVC_REGISTRY:-}" ]] || die "registry unknown; set the DEVC_REGISTRY environment variable" -# Get container command from the DEVC_COMMAND env variable -# if set, else use bash -l. -DEVC_COMMAND="${DEVC_COMMAND:-bash -l}" + default_args + param_args "$@" -# When container is not running or arguments are provided, -# recreate it. -if [ "$($engine container inspect "$name" -f {{.State.Running}} 2>&1)" != 'true' ] || [[ $# -gt 0 ]]; then - log "starting $image..." - $engine network create --ignore "devc" 1>/dev/null - $engine container rm -f -t 0 "$name" 1>/dev/null - $engine run -td $(default_args) $(param_args $@) "$registry/$image" -fi + podman network create --ignore "devc" &>/dev/null + podman run --replace --stop-timeout 0 -td "${run_opts[@]}" "$DEVC_REGISTRY/$image" + fi -$engine exec --detach-keys "ctrl-@,ctrl-@" -it "$name" ${DEVC_COMMAND:-} + exec podman exec --detach-keys "ctrl-@,ctrl-@" -it "$name" ${DEVC_COMMAND:-bash -l} +} + +main "$@"