Last active
January 1, 2025 10:58
-
-
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
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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