#!/usr/bin/env bash # shellcheck disable=SC1090,SC2004 podmanRunWrapper() { ######################## ###### FUNCTIONS ####### ######################## _printHelpAndExit() { if [[ -z $_debug ]]; then cat <<-'EOF' USAGE Argument mode: podmanRunWrapper -m MODE -o OPTIONS -i IMAGE [-n CONTAINER_NAME] [--help] [--debug] [COMMANDS [ARGS...]] Array mode (bash >= 4.3): podmanRunWrapper -a ARRAY EXAMPLE podmanRunWrapper -m ephemeral -o "-it -v $PWD:$PWD -w $PWD" -i "php:latest" -c "php ./script.php" ARRAY=( "-m" "ephemeral" "-o" "--rm -it -v $PWD:$PWD -w $PWD" "-i" "php:latest" "-c" "php ./script.php") podmanRunWrapper -a ARRAY COMMANDS COMMANDS to run in the container (e.g. the current active file, an external build script, a program residing in the container, etc.) Can be empty (run default container entrypoint) OPTIONS --mode, -m MODE MODE can be any of the following: 1. ephemeral 2. persistent 3. recreate-persistent --options, -o OPTIONS OPTIONS to pass directly to `podman run` or `podman exec` depending on the mode or container state --image, -i IMAGE IMAGE used to create the container --array, -a ARRAY Read arguments array named ARRAY (bash >= 4.3) This is useful to reduce parsing errors and recommended for build-wrapper plugins --optionsarray OPTIONS_ARRAY Read podman options from array named OPTIONS_ARRAY (bash >= 4.3) This is useful to reduce parsing errors and recommended for build-wrapper plugins --commandsarray COMMANDS_ARRAY Read container commands from array named COMMANDS_ARRAY (bash >= 4.3) This is useful to reduce parsing errors and recommended for build-wrapper plugins --name, -n CONTAINER_NAME Use the CONTAINER_NAME base to name containers (should be unique to each project) Default: Container name will be set based on a concatenation of the image and commands --selinuxfix A temporary hack to grant SELinux write access on $PWD until a better fix is found --debug, -d Print debugging --help, -h Print this help message and exit EOF fi # Exit using passed exit code [[ -z $1 ]] && exit 0 || exit "$1" } # Parse input _parseInput() { unset _mode _cmds_arr _opts_arr _options _prw_opts_arr _image _name _array _selinux_fix # Use getopt to print help if INPUT=$(getopt -o +m:o:i:x:n:a:dh -l mode:,options:,image:,name:,array:,optionsarray:,commandsarray:,selinuxfix,debug,help -- "$@"); then eval set -- "$INPUT" while true; do case "$1" in --mode|-m) shift _mode="$1" ;; --options|-o) shift _options+=("$1") ;; --image|-i) shift _image="$1" ;; --name|-n) shift _name="$1" ;; --array|-a) shift _array="$1" ;; --optionsarray) shift _opts_arr="$1" ;; --commandsarray) shift _cmds_arr="$1" ;; --selinuxfix) _selinux_fix="1" ;; --help|-h) _printHelpAndExit 0 ;; --debug|-d) export _debug="1" echo "Debugging on!" ;; --) shift break ;; esac shift done else echo "Incorrect options provided!" _printHelpAndExit 1 fi # If array mode, load and parse input array if [[ -n $_array ]]; then checkBashVersion local _n_array declare -n _n_array="$_array" _parseInput "${_n_array[@]}" return fi # Parse podman options from --optionsarray if [[ -n $_opts_arr ]]; then # namerefs are awesome declare -gn _prw_opts_arr="$_opts_arr" # If no array given, parse input from options elif [[ ${#_options[@]} -ge 1 ]]; then declare -ga _prw_opts_arr=("${_options[@]}") else echo "Must provide --options or the name of an existing --optionsarray" _printHelpAndExit 1 fi # Parse commands if [[ -n $_cmds_arr ]]; then declare -gn _prw_cmds_arr="$_cmds_arr" else # Create COMMANDS array from remaining arguments # shift getopt parameters away shift $((OPTIND - 1)) # create array declare -ga _prw_cmds_arr _prw_cmds_arr=("$@") if [[ ${#_prw_cmds_arr[@]} -lt 1 ]]; then debug "Running container without any commands" fi fi debug "_prw_opts_arr:" "${_prw_opts_arr[@]}" debug "_prw_cmds_arr:" "${_prw_cmds_arr[@]}" } _addCName() { # autogenerate _name if missing [[ -z $_name ]] && _name="${_image}${_prw_cmds_arr[*]}" # sanitize container name _name="${_name//_/}" && _name="${_name// /}" && \ _name="${_name//[^a-zA-Z0-9_]/}" && _name="${_name,,}" # append flag if [[ "$_mode" == "ephemeral" ]]; then _cname="prw-e-$_name" else _cname="prw-p-$_name" fi _prw_opts_arr+=("--name" "$_cname") } _removeContainer() { if podman container exists "$1"; then debug "podman rm -v -f $1" podman rm -v -f "$1" fi } _runContainer() { # Run _remove_container first to not run in existing container if podman container exists "$1"; then debug podman exec "$1" sh -c "${_prw_cmds_arr[@]}" podman exec "$1" sh -c "${_prw_cmds_arr[@]}" exit $? else debug "Command: podman run" "${_prw_opts_arr[@]}" "$_image" sh -c "${_prw_cmds_arr[@]}" podman run "${_prw_opts_arr[@]}" "$_image" "${_prw_cmds_arr[@]}" exit $? fi } ######################### ####### EXECUTE ######### ######################### __main() { # Get input _parseInput "$@" # Set container name _addCName # SELinux fix [[ -n $_selinux_fix ]] && fixPermissions "$PWD" # Execute podman if [[ "$_mode" =~ ^(ephemeral|recreate-persistent)$ ]]; then _removeContainer "$_cname" fi _runContainer "$_cname" } # Allow this function to be executed directly __main "$@" exit $? } # Allow script to be called directly if [[ "${BASH_SOURCE[0]}" == "$0" ]]; then _getBaseDir () { # Get base directory name of where this script resides # https://stackoverflow.com/questions/59895/how-to-get-the-source-directory-of-a-bash-script-from-within-the-script-itself#comment54598418_246128 _basedir=$(dirname "$(readlink -f "$0")") } _sourceFunctions () { # Get the location of this file _getBaseDir # Go up two directories ff="${_basedir%/*/*}/functions" # Source functions file if [[ -f "$ff" ]]; then source "$ff" else echo "Cannot find functions file: ${ff}" fi } _sourceFunctions podmanRunWrapper "$@" fi