You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
759 lines
16 KiB
759 lines
16 KiB
#!/usr/bin/env bash
|
|
# This script was generated by bashly (https://github.com/DannyBen/bashly)
|
|
# Modifying it manually is not recommended
|
|
|
|
# :command.version_command
|
|
version_command() {
|
|
echo "$version"
|
|
}
|
|
|
|
# :command.usage
|
|
duhm_usage() {
|
|
if [[ -n $long_usage ]]; then
|
|
printf "duhm - Downgrade/Upgrade Hetzner Machines\n"
|
|
echo
|
|
else
|
|
printf "duhm - Downgrade/Upgrade Hetzner Machines\n"
|
|
echo
|
|
fi
|
|
|
|
printf "Usage:\n"
|
|
printf " duhm [command]\n"
|
|
printf " duhm [command] --help | -h\n"
|
|
printf " duhm --version | -v\n"
|
|
echo
|
|
# :command.usage_commands
|
|
printf "Commands:\n"
|
|
echo " upgrade Upgrade the server"
|
|
echo " downgrade Downgrade the server"
|
|
echo " poweron Power on the server"
|
|
echo " poweroff Power off the server"
|
|
echo
|
|
|
|
if [[ -n $long_usage ]]; then
|
|
printf "Options:\n"
|
|
# :command.usage_fixed_flags
|
|
echo " --help, -h"
|
|
printf " Show this help\n"
|
|
echo
|
|
echo " --version, -v"
|
|
printf " Show version number\n"
|
|
echo
|
|
|
|
fi
|
|
}
|
|
|
|
# :command.usage
|
|
duhm_upgrade_usage() {
|
|
if [[ -n $long_usage ]]; then
|
|
printf "duhm upgrade - Upgrade the server\n"
|
|
echo
|
|
else
|
|
printf "duhm upgrade - Upgrade the server\n"
|
|
echo
|
|
fi
|
|
|
|
printf "Shortcut: u\n"
|
|
echo
|
|
|
|
printf "Usage:\n"
|
|
printf " duhm upgrade FILENAME\n"
|
|
printf " duhm upgrade --help | -h\n"
|
|
echo
|
|
|
|
if [[ -n $long_usage ]]; then
|
|
printf "Options:\n"
|
|
# :command.usage_fixed_flags
|
|
echo " --help, -h"
|
|
printf " Show this help\n"
|
|
echo
|
|
|
|
# :command.usage_args
|
|
printf "Arguments:\n"
|
|
|
|
# :argument.usage
|
|
echo " FILENAME"
|
|
printf " The YAML file with VPS & SSH settings\n"
|
|
echo
|
|
|
|
# :command.usage_examples
|
|
printf "Examples:\n"
|
|
|
|
printf " duhm upgrade settings.yml\n"
|
|
echo
|
|
|
|
fi
|
|
}
|
|
|
|
# :command.usage
|
|
duhm_downgrade_usage() {
|
|
if [[ -n $long_usage ]]; then
|
|
printf "duhm downgrade - Downgrade the server\n"
|
|
echo
|
|
else
|
|
printf "duhm downgrade - Downgrade the server\n"
|
|
echo
|
|
fi
|
|
|
|
printf "Shortcut: d\n"
|
|
echo
|
|
|
|
printf "Usage:\n"
|
|
printf " duhm downgrade FILENAME\n"
|
|
printf " duhm downgrade --help | -h\n"
|
|
echo
|
|
|
|
if [[ -n $long_usage ]]; then
|
|
printf "Options:\n"
|
|
# :command.usage_fixed_flags
|
|
echo " --help, -h"
|
|
printf " Show this help\n"
|
|
echo
|
|
|
|
# :command.usage_args
|
|
printf "Arguments:\n"
|
|
|
|
# :argument.usage
|
|
echo " FILENAME"
|
|
printf " The YAML file with VPS & SSH settings\n"
|
|
echo
|
|
|
|
# :command.usage_examples
|
|
printf "Examples:\n"
|
|
|
|
printf " duhm downgrade settings.yml\n"
|
|
echo
|
|
|
|
fi
|
|
}
|
|
|
|
# :command.usage
|
|
duhm_poweron_usage() {
|
|
if [[ -n $long_usage ]]; then
|
|
printf "duhm poweron - Power on the server\n"
|
|
echo
|
|
else
|
|
printf "duhm poweron - Power on the server\n"
|
|
echo
|
|
fi
|
|
|
|
printf "Shortcut: true\n"
|
|
echo
|
|
|
|
printf "Usage:\n"
|
|
printf " duhm poweron FILENAME\n"
|
|
printf " duhm poweron --help | -h\n"
|
|
echo
|
|
|
|
if [[ -n $long_usage ]]; then
|
|
printf "Options:\n"
|
|
# :command.usage_fixed_flags
|
|
echo " --help, -h"
|
|
printf " Show this help\n"
|
|
echo
|
|
|
|
# :command.usage_args
|
|
printf "Arguments:\n"
|
|
|
|
# :argument.usage
|
|
echo " FILENAME"
|
|
printf " The YAML file with VPS & SSH settings\n"
|
|
echo
|
|
|
|
# :command.usage_examples
|
|
printf "Examples:\n"
|
|
|
|
printf " duhm poweron settings.yml\n"
|
|
echo
|
|
|
|
fi
|
|
}
|
|
|
|
# :command.usage
|
|
duhm_poweroff_usage() {
|
|
if [[ -n $long_usage ]]; then
|
|
printf "duhm poweroff - Power off the server\n"
|
|
echo
|
|
else
|
|
printf "duhm poweroff - Power off the server\n"
|
|
echo
|
|
fi
|
|
|
|
printf "Usage:\n"
|
|
printf " duhm poweroff FILENAME\n"
|
|
printf " duhm poweroff --help | -h\n"
|
|
echo
|
|
|
|
if [[ -n $long_usage ]]; then
|
|
printf "Options:\n"
|
|
# :command.usage_fixed_flags
|
|
echo " --help, -h"
|
|
printf " Show this help\n"
|
|
echo
|
|
|
|
# :command.usage_args
|
|
printf "Arguments:\n"
|
|
|
|
# :argument.usage
|
|
echo " FILENAME"
|
|
printf " The YAML file with VPS & SSH settings\n"
|
|
echo
|
|
|
|
# :command.usage_examples
|
|
printf "Examples:\n"
|
|
|
|
printf " duhm poweroff settings.yml\n"
|
|
echo
|
|
|
|
fi
|
|
}
|
|
|
|
# :command.inspect_args
|
|
inspect_args() {
|
|
echo args:
|
|
for k in "${!args[@]}"; do echo "- \${args[$k]} = ${args[$k]}"; done
|
|
}
|
|
|
|
# :command.user_lib
|
|
# :src/lib/yaml.sh
|
|
# ---
|
|
# YAML parser
|
|
# This file is a part of Bashly standard library
|
|
# Does not support arrays, only hashes
|
|
#
|
|
# Source: https://stackoverflow.com/a/21189044/413924
|
|
#
|
|
# Usage:
|
|
#
|
|
# yaml_load "settings.yml" # print variables
|
|
# yaml_load "settings.yml" "config_" # use prefix
|
|
# eval $(yaml_load "settings.yml") # create variables in scope
|
|
#
|
|
# ---
|
|
|
|
yaml_load() {
|
|
local prefix=$2
|
|
local s='[[:space:]]*' w='[a-zA-Z0-9_]*'
|
|
local fs
|
|
|
|
fs=$(echo @|tr @ '\034')
|
|
|
|
sed -ne "s|^\($s\):|\1|" \
|
|
-e "s|^\($s\)\($w\)$s:${s}[\"']\(.*\)[\"']$s\$|\1$fs\2$fs\3|p" \
|
|
-e "s|^\($s\)\($w\)$s:$s\(.*\)$s\$|\1$fs\2$fs\3|p" "$1" |
|
|
awk -F"$fs" '{
|
|
indent = length($1)/2;
|
|
vname[indent] = $2;
|
|
for (i in vname) {if (i > indent) {delete vname[i]}}
|
|
if (length($3) > 0) {
|
|
vn=""; for (i=0; i<indent; i++) {vn=(vn)(vname[i])("_")}
|
|
printf("%s%s%s=\"%s\"\n", "'"$prefix"'",vn, $2, $3);
|
|
}
|
|
}'
|
|
}
|
|
|
|
# :src/lib/colors.sh
|
|
# ---
|
|
# Color functions
|
|
# This file is a part of Bashly standard library
|
|
#
|
|
# Usage:
|
|
# Use any of the functions below to color or format a portion of a string.
|
|
#
|
|
# echo "before $(red this is red) after"
|
|
# echo "before $(green_bold this is green_bold) after"
|
|
#
|
|
# ---
|
|
|
|
red() { printf "\e[31m%b\e[0m\n" "$*"; }
|
|
green() { printf "\e[32m%b\e[0m\n" "$*"; }
|
|
yellow() { printf "\e[33m%b\e[0m\n" "$*"; }
|
|
blue() { printf "\e[34m%b\e[0m\n" "$*"; }
|
|
magenta() { printf "\e[35m%b\e[0m\n" "$*"; }
|
|
cyan() { printf "\e[36m%b\e[0m\n" "$*"; }
|
|
bold() { printf "\e[1m%b\e[0m\n" "$*"; }
|
|
underlined() { printf "\e[4m%b\e[0m\n" "$*"; }
|
|
red_bold() { printf "\e[1;31m%b\e[0m\n" "$*"; }
|
|
green_bold() { printf "\e[1;32m%b\e[0m\n" "$*"; }
|
|
yellow_bold() { printf "\e[1;33m%b\e[0m\n" "$*"; }
|
|
blue_bold() { printf "\e[1;34m%b\e[0m\n" "$*"; }
|
|
magenta_bold() { printf "\e[1;35m%b\e[0m\n" "$*"; }
|
|
cyan_bold() { printf "\e[1;36m%b\e[0m\n" "$*"; }
|
|
red_underlined() { printf "\e[4;31m%b\e[0m\n" "$*"; }
|
|
green_underlined() { printf "\e[4;32m%b\e[0m\n" "$*"; }
|
|
yellow_underlined() { printf "\e[4;33m%b\e[0m\n" "$*"; }
|
|
blue_underlined() { printf "\e[4;34m%b\e[0m\n" "$*"; }
|
|
magenta_underlined() { printf "\e[4;35m%b\e[0m\n" "$*"; }
|
|
cyan_underlined() { printf "\e[4;36m%b\e[0m\n" "$*"; }
|
|
|
|
# :command.command_functions
|
|
# :command.function
|
|
duhm_upgrade_command() {
|
|
# :src/upgrade_command.sh
|
|
echo "$(green_bold "Upgrading the Hetzner VPS")"
|
|
echo "$(green_bold "=========================")"
|
|
|
|
echo "$(blue_bold "Loading VPS settings...")"
|
|
filename=${args[filename]}
|
|
eval $(yaml_load "$filename")
|
|
|
|
echo "$(blue_bold "Executing the down commands on the VPS...")"
|
|
ssh $ssh_user@$ssh_host -p $ssh_port $commands_down
|
|
|
|
echo "$(blue_bold "Powering off the VPS...")"
|
|
hcloud server poweroff $vps_name
|
|
|
|
echo "$(blue_bold "Upgrading the VPS...")"
|
|
hcloud server change-type --keep-disk $vps_name $vps_type_upgrade
|
|
|
|
echo "$(blue_bold "Powering on the VPS...")"
|
|
hcloud server poweron $vps_name
|
|
|
|
echo "$(blue_bold "Waiting 15 seconds...")"
|
|
sleep 15
|
|
|
|
echo "$(blue_bold "Executing the up commands on the VPS...")"
|
|
ssh $ssh_user@$ssh_host -p $ssh_port $commands_up
|
|
|
|
echo "$(green_bold "Upgrade successful!")"
|
|
}
|
|
|
|
# :command.function
|
|
duhm_downgrade_command() {
|
|
# :src/downgrade_command.sh
|
|
echo "$(green_bold "Downgrading the Hetzner VPS")"
|
|
echo "$(green_bold "===========================")"
|
|
|
|
echo "$(blue_bold "Loading VPS settings...")"
|
|
filename=${args[filename]}
|
|
eval $(yaml_load "$filename")
|
|
|
|
echo "$(blue_bold "Executing the down commands on the VPS...")"
|
|
ssh $ssh_user@$ssh_host -p $ssh_port $commands_down
|
|
|
|
echo "$(blue_bold "Powering off the VPS...")"
|
|
hcloud server poweroff $vps_name
|
|
|
|
echo "$(blue_bold "Downgrading the VPS...")"
|
|
hcloud server change-type --keep-disk $vps_name $vps_type_downgrade
|
|
|
|
echo "$(blue_bold "Powering on the VPS...")"
|
|
hcloud server poweron $vps_name
|
|
|
|
echo "$(blue_bold "Waiting 15 seconds...")"
|
|
sleep 15
|
|
|
|
echo "$(blue_bold "Executing the up commands on the VPS...")"
|
|
ssh $ssh_user@$ssh_host -p $ssh_port $commands_up
|
|
|
|
echo "$(green_bold "Downgrade successful!")"
|
|
}
|
|
|
|
# :command.function
|
|
duhm_poweron_command() {
|
|
# :src/poweron_command.sh
|
|
echo "$(green_bold "Powering on the Hetzner VPS")"
|
|
echo "$(green_bold "===========================")"
|
|
|
|
echo "$(blue_bold "Loading VPS settings...")"
|
|
filename=${args[filename]}
|
|
eval $(yaml_load "$filename")
|
|
|
|
echo "$(blue_bold "Powering on the VPS...")"
|
|
hcloud server poweron $vps_name
|
|
|
|
echo "$(blue_bold "Waiting 15 seconds...")"
|
|
sleep 15
|
|
|
|
echo "$(blue_bold "Executing the up commands on the VPS...")"
|
|
ssh $ssh_user@$ssh_host -p $ssh_port $commands_up
|
|
|
|
echo "$(green_bold "Power on successful!")"
|
|
}
|
|
|
|
# :command.function
|
|
duhm_poweroff_command() {
|
|
# :src/poweroff_command.sh
|
|
echo "$(green_bold "Powering off the Hetzner VPS")"
|
|
echo "$(green_bold "============================")"
|
|
|
|
echo "$(blue_bold "Loading VPS settings...")"
|
|
filename=${args[filename]}
|
|
eval $(yaml_load "$filename")
|
|
|
|
echo "$(blue_bold "Executing the down commands on the VPS...")"
|
|
ssh $ssh_user@$ssh_host -p $ssh_port $commands_down
|
|
|
|
echo "$(blue_bold "Powering off the VPS...")"
|
|
hcloud server poweroff $vps_name
|
|
|
|
echo "$(green_bold "Power off successful!")"
|
|
}
|
|
|
|
# :command.parse_requirements
|
|
parse_requirements() {
|
|
# :command.fixed_flag_filter
|
|
case "$1" in
|
|
--version | -v )
|
|
version_command
|
|
exit
|
|
;;
|
|
|
|
--help | -h )
|
|
long_usage=yes
|
|
duhm_usage
|
|
exit 1
|
|
;;
|
|
|
|
esac
|
|
# :command.environment_variables_filter
|
|
# :command.dependencies_filter
|
|
# :command.command_filter
|
|
action=$1
|
|
|
|
case $action in
|
|
-* )
|
|
;;
|
|
|
|
upgrade | u )
|
|
action="upgrade"
|
|
shift
|
|
duhm_upgrade_parse_requirements "$@"
|
|
shift $#
|
|
;;
|
|
|
|
downgrade | d )
|
|
action="downgrade"
|
|
shift
|
|
duhm_downgrade_parse_requirements "$@"
|
|
shift $#
|
|
;;
|
|
|
|
poweron | true )
|
|
action="poweron"
|
|
shift
|
|
duhm_poweron_parse_requirements "$@"
|
|
shift $#
|
|
;;
|
|
|
|
poweroff )
|
|
action="poweroff"
|
|
shift
|
|
duhm_poweroff_parse_requirements "$@"
|
|
shift $#
|
|
;;
|
|
|
|
* )
|
|
duhm_usage
|
|
exit 1
|
|
;;
|
|
|
|
esac
|
|
# :command.required_args_filter
|
|
# :command.required_flags_filter
|
|
# :command.parse_requirements_while
|
|
while [[ $# -gt 0 ]]; do
|
|
key="$1"
|
|
case "$key" in
|
|
|
|
-* )
|
|
printf "invalid option: %s\n" "$key"
|
|
exit 1
|
|
;;
|
|
|
|
* )
|
|
# :command.parse_requirements_case
|
|
printf "invalid argument: %s\n" "$key"
|
|
exit 1
|
|
;;
|
|
|
|
esac
|
|
done
|
|
# :command.default_assignments
|
|
}
|
|
|
|
# :command.parse_requirements
|
|
duhm_upgrade_parse_requirements() {
|
|
# :command.fixed_flag_filter
|
|
case "$1" in
|
|
--version | -v )
|
|
version_command
|
|
exit
|
|
;;
|
|
|
|
--help | -h )
|
|
long_usage=yes
|
|
duhm_upgrade_usage
|
|
exit 1
|
|
;;
|
|
|
|
esac
|
|
# :command.environment_variables_filter
|
|
# :command.dependencies_filter
|
|
# :command.command_filter
|
|
action="upgrade"
|
|
# :command.required_args_filter
|
|
if [[ $1 && $1 != -* ]]; then
|
|
args[filename]=$1
|
|
shift
|
|
else
|
|
printf "missing required argument: FILENAME\nusage: duhm upgrade FILENAME\n"
|
|
exit 1
|
|
fi
|
|
# :command.required_flags_filter
|
|
# :command.parse_requirements_while
|
|
while [[ $# -gt 0 ]]; do
|
|
key="$1"
|
|
case "$key" in
|
|
|
|
-* )
|
|
printf "invalid option: %s\n" "$key"
|
|
exit 1
|
|
;;
|
|
|
|
* )
|
|
# :command.parse_requirements_case
|
|
if [[ ! ${args[filename]} ]]; then
|
|
args[filename]=$1
|
|
shift
|
|
else
|
|
printf "invalid argument: %s\n" "$key"
|
|
exit 1
|
|
fi
|
|
;;
|
|
|
|
esac
|
|
done
|
|
# :command.default_assignments
|
|
}
|
|
|
|
# :command.parse_requirements
|
|
duhm_downgrade_parse_requirements() {
|
|
# :command.fixed_flag_filter
|
|
case "$1" in
|
|
--version | -v )
|
|
version_command
|
|
exit
|
|
;;
|
|
|
|
--help | -h )
|
|
long_usage=yes
|
|
duhm_downgrade_usage
|
|
exit 1
|
|
;;
|
|
|
|
esac
|
|
# :command.environment_variables_filter
|
|
# :command.dependencies_filter
|
|
# :command.command_filter
|
|
action="downgrade"
|
|
# :command.required_args_filter
|
|
if [[ $1 && $1 != -* ]]; then
|
|
args[filename]=$1
|
|
shift
|
|
else
|
|
printf "missing required argument: FILENAME\nusage: duhm downgrade FILENAME\n"
|
|
exit 1
|
|
fi
|
|
# :command.required_flags_filter
|
|
# :command.parse_requirements_while
|
|
while [[ $# -gt 0 ]]; do
|
|
key="$1"
|
|
case "$key" in
|
|
|
|
-* )
|
|
printf "invalid option: %s\n" "$key"
|
|
exit 1
|
|
;;
|
|
|
|
* )
|
|
# :command.parse_requirements_case
|
|
if [[ ! ${args[filename]} ]]; then
|
|
args[filename]=$1
|
|
shift
|
|
else
|
|
printf "invalid argument: %s\n" "$key"
|
|
exit 1
|
|
fi
|
|
;;
|
|
|
|
esac
|
|
done
|
|
# :command.default_assignments
|
|
}
|
|
|
|
# :command.parse_requirements
|
|
duhm_poweron_parse_requirements() {
|
|
# :command.fixed_flag_filter
|
|
case "$1" in
|
|
--version | -v )
|
|
version_command
|
|
exit
|
|
;;
|
|
|
|
--help | -h )
|
|
long_usage=yes
|
|
duhm_poweron_usage
|
|
exit 1
|
|
;;
|
|
|
|
esac
|
|
# :command.environment_variables_filter
|
|
# :command.dependencies_filter
|
|
# :command.command_filter
|
|
action="poweron"
|
|
# :command.required_args_filter
|
|
if [[ $1 && $1 != -* ]]; then
|
|
args[filename]=$1
|
|
shift
|
|
else
|
|
printf "missing required argument: FILENAME\nusage: duhm poweron FILENAME\n"
|
|
exit 1
|
|
fi
|
|
# :command.required_flags_filter
|
|
# :command.parse_requirements_while
|
|
while [[ $# -gt 0 ]]; do
|
|
key="$1"
|
|
case "$key" in
|
|
|
|
-* )
|
|
printf "invalid option: %s\n" "$key"
|
|
exit 1
|
|
;;
|
|
|
|
* )
|
|
# :command.parse_requirements_case
|
|
if [[ ! ${args[filename]} ]]; then
|
|
args[filename]=$1
|
|
shift
|
|
else
|
|
printf "invalid argument: %s\n" "$key"
|
|
exit 1
|
|
fi
|
|
;;
|
|
|
|
esac
|
|
done
|
|
# :command.default_assignments
|
|
}
|
|
|
|
# :command.parse_requirements
|
|
duhm_poweroff_parse_requirements() {
|
|
# :command.fixed_flag_filter
|
|
case "$1" in
|
|
--version | -v )
|
|
version_command
|
|
exit
|
|
;;
|
|
|
|
--help | -h )
|
|
long_usage=yes
|
|
duhm_poweroff_usage
|
|
exit 1
|
|
;;
|
|
|
|
esac
|
|
# :command.environment_variables_filter
|
|
# :command.dependencies_filter
|
|
# :command.command_filter
|
|
action="poweroff"
|
|
# :command.required_args_filter
|
|
if [[ $1 && $1 != -* ]]; then
|
|
args[filename]=$1
|
|
shift
|
|
else
|
|
printf "missing required argument: FILENAME\nusage: duhm poweroff FILENAME\n"
|
|
exit 1
|
|
fi
|
|
# :command.required_flags_filter
|
|
# :command.parse_requirements_while
|
|
while [[ $# -gt 0 ]]; do
|
|
key="$1"
|
|
case "$key" in
|
|
|
|
-* )
|
|
printf "invalid option: %s\n" "$key"
|
|
exit 1
|
|
;;
|
|
|
|
* )
|
|
# :command.parse_requirements_case
|
|
if [[ ! ${args[filename]} ]]; then
|
|
args[filename]=$1
|
|
shift
|
|
else
|
|
printf "invalid argument: %s\n" "$key"
|
|
exit 1
|
|
fi
|
|
;;
|
|
|
|
esac
|
|
done
|
|
# :command.default_assignments
|
|
}
|
|
|
|
# :command.initialize
|
|
initialize() {
|
|
version="0.1.0"
|
|
long_usage=''
|
|
set -e
|
|
|
|
# :src/initialize.sh
|
|
# Code here runs inside the initialize() function
|
|
# Use it for anything that you need to run before any other function, like
|
|
# setting environment vairables:
|
|
# CONFIG_FILE=settings.ini
|
|
#
|
|
# Feel free to empty (but not delete) this file.
|
|
}
|
|
|
|
# :command.run
|
|
run() {
|
|
declare -A args
|
|
parse_requirements "$@"
|
|
|
|
if [[ $action == "upgrade" ]]; then
|
|
if [[ ${args[--help]} ]]; then
|
|
long_usage=yes
|
|
duhm_upgrade_usage
|
|
else
|
|
duhm_upgrade_command
|
|
fi
|
|
|
|
elif [[ $action == "downgrade" ]]; then
|
|
if [[ ${args[--help]} ]]; then
|
|
long_usage=yes
|
|
duhm_downgrade_usage
|
|
else
|
|
duhm_downgrade_command
|
|
fi
|
|
|
|
elif [[ $action == "poweron" ]]; then
|
|
if [[ ${args[--help]} ]]; then
|
|
long_usage=yes
|
|
duhm_poweron_usage
|
|
else
|
|
duhm_poweron_command
|
|
fi
|
|
|
|
elif [[ $action == "poweroff" ]]; then
|
|
if [[ ${args[--help]} ]]; then
|
|
long_usage=yes
|
|
duhm_poweroff_usage
|
|
else
|
|
duhm_poweroff_command
|
|
fi
|
|
|
|
elif [[ ${args[--version]} ]]; then
|
|
version_command
|
|
elif [[ ${args[--help]} ]]; then
|
|
long_usage=yes
|
|
duhm_usage
|
|
elif [[ $action == "root" ]]; then
|
|
root_command
|
|
fi
|
|
}
|
|
|
|
initialize
|
|
run "$@"
|