Skip to content

Instantly share code, notes, and snippets.

@stoerr
Last active January 1, 2025 10:58
Show Gist options
  • Save stoerr/10207ffbb46e640c57ed3603ed4e8a4d to your computer and use it in GitHub Desktop.
Save stoerr/10207ffbb46e640c57ed3603ed4e8a4d to your computer and use it in GitHub Desktop.
Helper script that lets you choose and execute configurable directory specific command lines you need to execute again and again. Compare https://www.stoerr.net/blog/deployScript
#!/usr/bin/env bash
# requires bash > 4, so no /bin/bash on MacOS
function usage() {
cat <<EOF
Usage: $0 [-h] [-l] [-v] [tag]
Execute a deployment or other command selected from the configured commands for the directory.
The script looks for files called .deploycmds in the current directory and the parent directories up to $HOME.
Those files can contain a tagged list of commands for different deployment / command types. E.g.
9090 mvn -P local clean install # deploy on local machine
test mvn -P test clean install # deploy on test server
The tag (9090, test in this case) can be used to select the deployment type.
If no tag is given, the first deployment type is used.
If the command is empty, the tag is deleted from the list - that can be used to remove inherited entries.
The .deploycmds file in the current directory has precedence over the ones in the parent directories.
-h prints this help message.
-l lists the available deployment types and exits,
-s prints a short list of available deployment types and exits,
-v prints all .deploycmds files relevant to this directory and the commands they contain and exits,
-c prints a script that can be used for bash command line completion and exits: use e.g. as eval "\$($(basename $0) -c)"
EOF
exit 1
}
# unofficially -s for bash completion: just outputs the keys
while getopts ":hlsvch?" opt; do
case ${opt} in
h )
usage
;;
l )
dolist=true
;;
v )
verbose=true
;;
s )
shortlist=true
;;
c )
completion=true
;;
\? )
echo "Invalid option: $OPTARG" 1>&2
usage
;;
esac
done
shift $((OPTIND -1))
# if -c was given, print the completion script and exit
if [[ "$completion" == "true" ]]; then
scriptname=$(basename $0)
cat <<EOF
# Script for bash Command line completion for ${scriptname}
# Use e.g. as eval "\$(${scriptname} -c)"
_${scriptname}_completions() {
# Get the current word (the one being typed)
local cur="\${COMP_WORDS[COMP_CWORD]}"
# List of available options
local opts=\$(${scriptname} -s)
# Generate completion options based on what has been typed so far
COMPREPLY=( \$(compgen -W "\$opts" -- "\$cur") )
}
# Register it for cmd and deploy if they are in the path
type ${scriptname} &>/dev/null && complete -F _${scriptname}_completions cmd
EOF
exit 0
fi
# collect all deploycmds files in the array in backwards order
deploycmdfiles=()
dir=$(pwd)
while [[ "$dir" != "$HOME" && -n "$dir" ]]; do
if [[ -f "$dir/.deploycmds" ]]; then
deploycmdfiles=("$dir/.deploycmds" "${deploycmdfiles[@]}")
fi
dir=$(dirname "$dir")
done
if [[ -f "$HOME/.deploycmds" ]]; then
deploycmdfiles=("$HOME/.deploycmds" "${deploycmdfiles[@]}")
fi
# read the deploycmds files into an associative array
declare -A deployCommands
for file in "${deploycmdfiles[@]}"; do
unset defaultTagInThisFile
while read -r line; do
if [[ -n "$line" && "$line" != \#* ]]; then
tag=${line%% *}
cmd=${line#* }
if [[ -z "$cmd" || "$cmd" == "$tag" ]]; then
unset deployCommands[$tag]
continue
fi
deployCommands[$tag]="$cmd"
# set first tag as default
if [[ -z "$defaultTagInThisFile" ]]; then
defaultTagInThisFile="$tag"
fi
if [[ "$verbose" == "true" ]]; then
echo "$(realpath --relative-base=$HOME $file): $tag: $cmd"
fi
fi
done < "$file"
defaultTag="$defaultTagInThisFile"
done
if [[ "$verbose" == "true" ]]; then
echo
fi
# if -l was given, print the commands and exit
if [[ "$dolist" == "true" ]]; then
echo "Available commands (default $defaultTag):"
for tag in "${!deployCommands[@]}"; do
echo "$tag: ${deployCommands[$tag]}"
done
exit 0
fi
if [[ "$shortlist" == "true" ]]; then
for tag in "${!deployCommands[@]}"; do
echo -n "$tag "
done
echo
exit 0
fi
if [[ "$verbose" == "true" ]]; then
exit 0
fi
# if no tag is given, use the default tag
if [[ -z "$1" ]]; then
tag="$defaultTag"
else
tag="$1"
fi
# if the tag is not in the array, print an error message
if [[ -z "${deployCommands[$tag]}" ]]; then
echo "No deployment type '$tag' found."
echo "Available deployment types:"
for tag in "${!deployCommands[@]}"; do
echo "$tag : ${deployCommands[$tag]}"
done
exit 1
fi
# execute the command
cmd="${deployCommands[$tag]}"
echo "Executing $cmd"
exec bash -c "$cmd"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment