Skip to content

Instantly share code, notes, and snippets.

@xrstf
Created March 17, 2024 23:14
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save xrstf/35955652b4862c9dc7cc71ec4b2cc8dd to your computer and use it in GitHub Desktop.
Save xrstf/35955652b4862c9dc7cc71ec4b2cc8dd to your computer and use it in GitHub Desktop.
Drum!
#!/usr/bin/env bash
#
# Drum!
#
# Cause the repeated "docker run --rm -it" always sounds
# like "drumit" in my head.
#
# This script makes it easy to start a container.
#
# Just running `drum` on its own starts a container using
# the DEFAULT_IMAGE below.
#
# -u assume the same UID/GID in the container as on your host
# -U create an image based on given image but with
# your user/group added to it, then assuming that
# user (a more extreme version of -u)
# -m mount the current directory into the container;
# by default to /tmp, unless you are inside your GOPATH,
# then you working directory is mounted to the /go/...
# equivalent in the container
# -M like -m, but explicitly specify the mount path
# -w sets the working directory to the mount path
# -W like -w, but explicitly specify the working directory
# -p pull the image before doing anything
# -v be more verbose
#
set -euo pipefail
# in case no image was provided, assume this one
# (set to empty value to disable defaulting)
DEFAULT_IMAGE=ubuntu:latest
userMode=none # none, assume (-u), ensure (-U)
chdir=false
workDir=
mount=false
mountPath=
pull=false
verbose=false
################################
# CLI parsing magic
# thanks to https://stackoverflow.com/a/14203146
################################
usage() {
echo "Usage: drum [-u|-U] [-m|-M MOUNT_TO] [-w|-W WORKDIR] IMAGE [-- COMMAND]"
}
# Reset in case getopts has been used previously in the shell
OPTIND=1
while getopts "huUwW:mM:pv" opt; do
case "$opt" in
h)
usage
exit
;;
u)
userMode=assume
;;
U)
userMode=ensure
;;
w)
chdir=true
workDir=
;;
W)
chdir=true
workDir=$OPTARG
;;
m)
mount=true
mountPath=
;;
M)
mount=true
mountPath=$OPTARG
;;
p)
pull=true
;;
v)
verbose=true
;;
esac
done
shift $((OPTIND-1))
[ "${1:-}" = "--" ] && shift
image="${1:-}"
if [ -z "$image" ]; then
image="$DEFAULT_IMAGE"
if [ -z "$image" ]; then
echo "Error: No image given."
usage
exit 2
fi
else
shift
fi
# echo "userMode=$userMode,workDir='$workDir',mount=$mount,image='$image',pull=$pull,verbose=$verbose,args=$@"
################################
# you can open your eyes again
################################
if $pull; then
if $verbose; then
(set -x; docker pull "$image")
else
docker pull --quiet "$image"
fi
fi
runArgs=(
--rm
--interactive
--tty
)
if [ $userMode == ensure ]; then
tmpdir="$(mktemp -d)"
cleanup() {
rm -rf -- "$tmpdir"
}
trap "cleanup" EXIT SIGINT
uid=$(id -u)
gid=$(id -g)
me=$(id -un)
dockerfile="$tmpdir/Dockerfile"
cat <<EOF > "$dockerfile"
FROM $image
RUN addgroup --gid $gid $me
RUN adduser --uid $uid --gid $gid --gecos "" $me
EOF
imageName="drum-$image"
if $verbose; then
(set -x; docker build --tag "$imageName" "$tmpdir")
else
docker build --tag "$imageName" "$tmpdir" 2>/dev/null
fi
image="$imageName"
# re-use the code below
userMode=assume
fi
if [ $userMode == assume ]; then
uid=$(id -u)
gid=$(id -g)
runArgs+=(--user "$uid:$gid")
fi
if $mount; then
here="$(realpath .)"
if [[ "$mountPath" == "" ]]; then
here="$(realpath .)"
gopath="$(go env GOPATH)"
gopathRel="${here##$gopath}"
if [[ "$gopathRel" != "$here" ]]; then
mountPath="/go$gopathRel"
else
mountPath="${workDir:-/tmp}"
fi
# echo "Defaulted mount path to $mountPath."
fi
runArgs+=(--volume "$here:$mountPath")
# unless an explicit workdir was given, mounting the pwd should set
# the workdir to the mount path
if [[ "$workDir" == "" ]]; then
chdir=true
workDir="$mountPath"
fi
fi
if $chdir; then
if [[ "$workDir" == "" ]]; then
echo "Error: Could not determine working directory."
usage
exit 1
fi
runArgs+=(--workdir "$workDir")
fi
# echo "args: ${runArgs[*]}"
if $verbose; then
(set -x; exec docker run "${runArgs[@]}" "$image" "$@")
else
exec docker run "${runArgs[@]}" "$image" "$@"
fi
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment