######################################################################################
# ここから翻訳データ
+# 翻訳はBashの連想配列を使用して行います
+# 連想配列名は echo "${LANG}" | cut -d "." -f 1 の実行結果の値です
+#
+# 日本語
declare -A ja_JP=(
["Undefined operation"]="未定義のオペレーションです"
["only one operation may be used at a time"]="一度に使用できるオペレーションは1つだけです"
["Install dependent packages..."]="依存パッケージをインストールします..."
["Found %s"]="%s を見つけました"
["Packages to cleanBuild? [n] :"]="パッケージをクリーンビルドしますか? [n] :"
- ["Could not find all required packages:\n %s"]="必要なすべてのパッケージが見つかりませんでした %s"
+ ["Could not find all required packages: %s"]="必要なすべてのパッケージが見つかりませんでした: %s"
["This is a feature that has not been implemented yet"]="まだ実装されていない機能です"
-
+ ["Package not found on AUR: %s"]="パッケージがAUR上から見つかりませんでした: "
+ ["There is no aurvote"]="aurvote が見つかりませんでした"
+ ["Please install with %s"]="%s でインストールしてください"
+ ["Voted for %s"]="%s に投票しました"
+ ["Unvoted for %s"]="%s の投票を解除しました"
+ ["Help for this operation is not implemented"]="このオペレーションのヘルプは実装されていません"
["(Orphaned)"]="(メンテナ不在)"
["[Installed]"]="[インストール済み]"
["This is a feature that has not been implemented yet"]="まだ実装されていない機能です"
+ ["Operation: %s"]="オペレーション: %s"
+ ["Raw popularity: %s"]="人気度の正確な値: %s"
+ ["This program is an alpha version that is not yet stable\nIf you find a bug, please share it on GitHub\nhttps://github.com/hayao0819/wfa/issues"]="このプログラムはまだ安定しないアルファ版です\nもしバグを見つけたらGitHub上で共有してください\nhttps://github.com/hayao0819/wfa/issues"
+ ["Please make a contract with me and become a Puella Magi !"]="僕と契約して魔法少女になってよ! "
)
+
+
+# English
+# 翻訳データが存在しない場合はデフォルトメッセージ(英語)が出力されます
+# そのため英語の翻訳データは必要ありません
+declare -A en_US=()
+declare -A C=()
+
######################################################################################
# ここからデフォルト設定の定義
wfa_version="0.1"
wfa_name="WFA"
wfa_command="wfa"
+wfa_path="$(dirname "$(realpath "${0}")")/$(basename "${0}")"
#-- options (int) --#
option_y_count=0
sync_clean_count=0
#-- options (str) --#
+arch="$(uname -m)"
aururl="https://aur.archlinux.org/"
operation="none"
# 引数
sudo_args=""
+#-- curl --#
+# 実行ファイル
+curl_command="/usr/bin/curl"
+# 引数
+curl_args=""
######################################################################################
# ここからメッセージ関連の関数定義
+start_msg_debug() {
+ if [[ "${msgdebug}" = true ]]; then
+ set -xv
+ else
+ set +vx
+ fi
+}
+
+end_msg_debug() {
+ if [[ "${bash_debug}" = true ]]; then
+ set -xv
+ else
+ set +xv
+ fi
+}
+
# メッセージ出力の制御
# https://github.com/FascodeNet/alterlinux/blob/dev/tools/msg.sh の変数名にアンダーバーを追加し関数化
msg() {
}
# テキストの翻訳
-#set -xv
translate() {
local _msg_translate
_msg_translate() {
_get_text() {
set +eu
+ if [[ -z "${*}" ]]; then
+ return 1
+ fi
local _translated_text="$(eval echo '$'{${_locale}[\"${*}\"]})"
set -eu
if [[ -z "${_translated_text}" ]]; then
+ if [[ ! "${_locale}" = "C" ]] && [[ ! "${_locale}" = "en_US" ]]; then
+ echo "$(text -nc cyan "[WFA]") $(text -nc yellow "Warning") No translation data was found (${*})" 1>&2
+ fi
echo "${*}"
else
echo "${_translated_text}"
# Show an INFO message
# $1: message string
msg_info() {
- if [[ "${msgdebug}" = false ]]; then
- set +xv
- fi
+ start_msg_debug
local _msg_opts="-a ${wfa_name}"
if [[ "${1}" = "-n" ]]; then
_msg_opts="${_msg_opts} -o -n"
[[ "${msgdebug}" = true ]] && _msg_opts="${_msg_opts} -x"
[[ "${nocolor}" = true ]] && _msg_opts="${_msg_opts} -n"
msg ${_msg_opts} info "$(translate "${@}")"
- if [[ "${bash_debug}" = true ]]; then
- set -xv
- fi
+ end_msg_debug
}
# Show an Warning message
# $1: message string
msg_warn() {
- if [[ "${msgdebug}" = false ]]; then
- set +xv
- fi
+ start_msg_debug
local _msg_opts="-a ${wfa_name}"
if [[ "${1}" = "-n" ]]; then
_msg_opts="${_msg_opts} -o -n"
[[ "${msgdebug}" = true ]] && _msg_opts="${_msg_opts} -x"
[[ "${nocolor}" = true ]] && _msg_opts="${_msg_opts} -n"
msg ${_msg_opts} warn "$(translate "${@}")"
- if [[ "${bash_debug}" = true ]]; then
- set -xv
- fi
+ end_msg_debug
}
# Show an debug message
# $1: message string
msg_debug() {
- if [[ "${msgdebug}" = false ]]; then
- set +xv
- fi
+ start_msg_debug
if [[ "${debug}" = true ]]; then
local _msg_opts="-a ${wfa_name}"
if [[ "${1}" = "-n" ]]; then
[[ "${nocolor}" = true ]] && _msg_opts="${_msg_opts} -n"
msg ${_msg_opts} debug "$(translate "${@}")"
fi
- if [[ "${bash_debug}" = true ]]; then
- set -xv
- fi
+ end_msg_debug
}
# Show an ERROR message then exit with status
# $1: message string
# $2: exit code number (with 0 does not exit)
msg_error() {
- if [[ "${msgdebug}" = false ]]; then
- set +xv
- fi
+ start_msg_debug
local _msg_opts="-a ${wfa_name}"
if [[ "${1}" = "-n" ]]; then
_msg_opts="${_msg_opts} -o -n"
[[ "${msgdebug}" = true ]] && _msg_opts="${_msg_opts} -x"
[[ "${nocolor}" = true ]] && _msg_opts="${_msg_opts} -n"
msg ${_msg_opts} error "$(translate "${@}")"
- if [[ "${bash_debug}" = true ]]; then
- set -xv
- fi
+ end_msg_debug
}
+# 使い方
+# text [-b/-c color/-n/-f/-l/]
text() {
- local OPTIND OPTARG arg _textcolor _decotypes=() _message
- while getopts "c:b" arg; do
+ start_msg_debug
+ local OPTIND OPTARG arg _textcolor _decotypes="" _message _notranslate=false
+ while getopts "c:bnfl" arg; do
case ${arg} in
c)
case "${OPTARG}" in
esac
;;
b)
- _decotypes+=(1)
+ _decotypes="${_decotypes};1"
+ ;;
+ f)
+ _decotypes="${_decotypes};5"
+ ;;
+ l)
+ _decotypes="${_decotypes};4"
+ ;;
+ n)
+ _notranslate=true
;;
esac
done
shift $((OPTIND - 1))
_message="${@}"
- _message="$(translate "${@}")"
+ if [[ "${_notranslate}" = false ]]; then
+ _message="$(translate "${@}")"
+ fi
if [[ "${nocolor}" = true ]]; then
echo -ne "${@}"
else
- echo -ne "\e[$([[ -v _textcolor ]] && echo -n ";${_textcolor}"; [[ -v _decotypes ]] && echo -n ";${_decotypes}")m${_message}\e[m"
+ echo -ne "\e[$([[ -v _textcolor ]] && echo -n ";${_textcolor}"; [[ -v _decotypes ]] && echo -n "${_decotypes}")m${_message}\e[m"
fi
+
+ end_msg_debug
}
######################################################################################
echo
echo "operations:"
echo " ${wfa_command} {-h --help}"
+ echo " ${wfa_command} {-A --vote}"
echo " ${wfa_command} {-V --version}"
#echo " ${wfa_command} {-D --database} <options> <package(s)>"
#echo " ${wfa_command} {-F --files} [options] [package(s)]"
echo " --makepkgconf <file> makepkg.conf file to use"
echo " --nomakepkgconf Use the default makepkg.conf"
echo
+ echo "wfa specific options:"
+ echo " -c --clean Remove unneeded dependencies"
+ echo
+ echo "This program is an alpha version that is not yet stable"
+ echo "If you find a bug, please share it on GitHub"
+ echo "https://github.com/hayao0819/wfa/issues"
+ echo
}
local _wfa_usage_sync
echo " -u, --sysupgrade upgrade installed packages (-uu enables downgrades)"
echo " -y, --refresh download fresh package databases from the server"
echo " (-yy to force a refresh even if up to date)"
- echo
+ echo " --arch <arch> set an alternate architecture"
echo " --color <when> colorize the output"
echo " --config <path> set an alternate configuration file"
- echo " --noconfirm do not ask for any confirmation"
+ echo " --confirm always ask for confirmation"
echo " --debug display debug messages"
+ echo " --disable-download-timeout"
+ echo " use relaxed timeouts for download"
echo " --noconfirm do not ask for any confirmation"
}
+ local _wfa_usage_remove
+ _wfa_usage_remove() {
+ echo "usage: ${wfa_command} {-R --remove} [options] <package(s)>"
+ echo "options:"
+ echo " -b, --dbpath <path> set an alternate database location"
+ echo " -d, --nodeps skip dependency version checks (-dd to skip all checks)"
+ echo " -u, --unneeded remove unneeded packages"
+ echo " --arch <arch> set an alternate architecture"
+ echo " --color <when> colorize the output"
+ echo " --config <path> set an alternate configuration file"
+ echo " --confirm always ask for confirmation"
+ echo " --debug display debug messages"
+ echo " --disable-download-timeout"
+ echo " use relaxed timeouts for download"
+ echo " --noconfirm do not ask for any confirmation"
+ }
+
if [[ "${operation}" = "none" ]]; then
_wfa_usage
elif [[ "${_pacman_help}" = true ]]; then
elif [[ "$(type -t "_wfa_usage_${operation}" )" = "function" ]]; then
_wfa_usage_${operation}
else
- msg_error "Undefined operation"
+ msg_error "Help for this operation is not implemented"
exit 1
fi
}
run_sudo "${pacman_command}" ${@}
}
+wfa() {
+ "${wfa_path}" ${@}
+}
+
# pacmanの引数を追加する
# https://github.com/FascodeNet/aptpac/blob/master/aptpac のADD_OPTION関数を参考
-# Usage: add_args [pacman/makepkg] <args1> <args2>...
+# Usage: add_args [pacman/makepkg/git/gpg/sudo/curl] <args1> <args2>...
add_args() {
local _target="${1}"
local _args_array
sudo_args=${_args_array[@]}
msg_debug "sudo ARGS: ${sudo_args}"
;;
+ "curl")
+ _args_array=(${curl_args})
+ _args_array+="${@}"
+ curl_args=${_args_array[@]}
+ msg_debug "curl ARGS: ${curl_args}"
+ ;;
*)
msg_error "Failed to set the argument of %s" "${_target}"
msg_error "Setting that command is not currently supported"
echo "${_srcinfo_json}" | jq -rc "${2}" | tr '\n' ' '
}
+get_aur_json() {
+ local _package="${1}"
+ local _aur_json=$("${curl_command}" ${curl_args} -sL "https://aur.archlinux.org/rpc/?v=5&type=search&by=name&arg=${_package}" | jq -r)
+ if (( "$(echo "${_aur_json}" | jq -r ".resultcount")" != 0 )); then
+ echo "${_aur_json}" | jq -r ".results[]"
+ fi
+}
+
# AURからパッケージをビルドしてインストールします
# 現在1つのパッケージしか指定できません
# AurJsonから値を取得
msg_info "Searching in AUR ..."
- local _aur_json=$(curl -sL "https://aur.archlinux.org/rpc/?v=5&type=search&by=name&arg=${_package}" | jq -r)
- if (( "$(echo "${_aur_json}" | jq -r ".resultcount")" == 0 )); then
- msg_error "Could not find all required packages:\n ${_package}"
+ local _aur_json="$(get_aur_json "${_package}")"
+ if [[ -z "${_aur_json}" ]]; then
+ msg_error "Could not find all required packages: %s" "${_package}"
exit 1
fi
-
- local _found_packages="$(echo "${_aur_json}" | jq -r --tab '.results[].Name')"
+ local _found_packages="$(echo "${_aur_json}" | jq -r --tab '.Name')"
#msg_debug "Found package: $(echo ${_found_packages} | tr '\n' ' ')"
if [[ -n "$(echo "${_found_packages}" | grep -x "${_package}" )" ]]; then
# PKGBUILDをダウンロード
msg_info "Download PKGBUILD of %s" "${_package}"
- _aur_json=$(echo "${_aur_json}" | jq -r ".results[] | select(.Name == \"${_package}\")" )
+ _aur_json=$(echo "${_aur_json}" | jq -r "select(.Name == \"${_package}\")" )
local _aur_snapshot_url="${aururl%/}$(echo "${_aur_json}" | jq -r ".URLPath")"
local _aur_version="$(echo "${_aur_json}" | jq -r ".Version")"
msg_debug "Get PKGBUILD from %s" "${_aur_snapshot_url}"
fi
if [[ "${_download_pkgbuild}" = true ]]; then
remove "${_pkgbuild_archive_path}"
- curl -L -C - -f -o "${_pkgbuild_archive_path}" "${_aur_snapshot_url}"
+ "${curl_command}" ${curl_args} -L -C - -f -o "${_pkgbuild_archive_path}" "${_aur_snapshot_url}"
fi
# PKGBUILDを展開
if [[ "${_arch_array[*]}" = "any" ]]; then
_arch="any"
else
- _arch="$(uname -m)"
+ _arch="${arch}"
fi
local _PKGEXT=$(
source "${makepkg_config}"
# AURのパッケージを検索
search_aur_package() {
local _package="${1}"
- #msg_info "Searching in AUR ..."
- local _aur_json=$(curl -sL "https://aur.archlinux.org/rpc/?v=5&type=search&by=name-desc&arg=${_package}" | jq -r )
- local _found_result_count="$(echo "${_aur_json}" | jq -r ".resultcount")"
- if (( "${_found_result_count}" == 0 )); then
- msg_error "Could not find all required packages:\n %s" "${_package}"
+ local _aur_json="$(get_aur_json "${_package}")"
+ if [[ -z "${_aur_json}" ]]; then
+ msg_error "Could not find all required packages: %s" "${_package}"
exit 1
fi
- _aur_json=$(echo "${_aur_json}" | jq -r ".results[]")
-
local _found_pkgname=($(echo "${_aur_json}" | jq -r ".Name" ))
if [[ "${quiet}" = true ]]; then
# 人気度の少数2位以下を四捨五入
# 参考: http://www.rivhiro-weather.com/knowledge/?p=536
- msg_debug "Row popularity: %s" "${__popularity}"
+ msg_debug "Raw popularity: %s" "${__popularity}"
__popularity="$(printf "%g\n" "${__popularity}" | awk '{printf("%4.2f", $1)}')"
# 孤児判定
fi
__output_text+=(
- "$(text -c blue -b "aur")/$(text -b "${_found_package}") $(text -c cyan "${__pkgver}") (+$(text -b "${__vote} ${__popularity}"))"
+ "$(text -n -c blue -b "aur")/$(text -n -b "${_found_package}") $(text -n -c cyan "${__pkgver}") (+$(text -n -b "${__vote} ${__popularity}"))"
)
if [[ "${__orphaned}" = true ]]; then
# Usage: install_package <package1> <package2>...
install_package() {
- local _package
+ local _package _repo_packages=() _aur_packages=()
for _package in ${@}; do
if ! check_installed_package "${_package}"; then
if ! check_aur_package "${_package}"; then
# 公式パッケージなのでpacmanでそのままインストール
- run_pacman ${pacman_args} "${_package}"
+ _repo_packages+=("${_package}")
else
# AUR上のパッケージの場合の処理
- install_aur_package "${_package}"
- #msg_error "Getting the AUR package has not been implemented yet.
- #exit 1
+ _aur_packages+=("${_package}")
fi
fi
done
+
+ if (( "${#_repo_packages[@]}" > 0 )); then
+ run_pacman --asdeps ${pacman_args} "${_repo_packages[@]}"
+ fi
+
+ if (( "${#_aur_packages[@]}" > 0 )); then
+ unset _package
+ for _package in ${_aur_packages[@]}; do
+ install_aur_package "${_package}"
+ done
+ fi
}
upgrade_aur_package() {
}
+operation_vote() {
+
+ # aurvoteの確認
+ if ! type aurvote 1> /dev/null 2> /dev/null; then
+ msg_error "There is no aurvote"
+ msg_error "Please install with %s" "\"wfa -S aurvote\""
+ exit 1
+ fi
+
+ local _package _aur_json _found_result_count _pkgver _before_popularity _before_vote
+ for _package in ${specified_packages[@]}; do
+
+ # 存在するパッケージか確認
+ local _aur_json="$(get_aur_json "${_package}")"
+ if [[ -z "${_aur_json}" ]]; then
+ msg_error "Could not find all required packages: %s" "${_package}"
+ exit 1
+ fi
+ _aur_json=$(echo "${_aur_json}" | jq -r "select(.Name == \"${_package}\")")
+
+ # jsonから値を取り出して整形
+ _pkgver="$(echo "${_aur_json}" | jq -r ".Version" )"
+ _before_popularity="$(printf "%g\n" "$(echo "${_aur_json}" | jq -r ".Popularity" )" | awk '{printf("%4.2f", $1)}')"
+ _before_vote="$(echo "${_aur_json}" | jq -r ".NumVotes" )"
+
+ # 投票を操作
+ if [[ "$(aurvote --check "${_package}")" = "not voted" ]]; then
+ msg_info "Voted for %s" "${_package}"
+ aurvote --vote "${_package}" 1> /dev/null
+ else
+ msg_info "Unvoted for %s" "${_package}"
+ aurvote --unvote "${_package}" 1> /dev/null
+ fi
+
+ # 投票後の値を取得
+ _aur_json=$(get_aur_json | jq -r "select(.Name == \"${_package}\")")
+ _after_popularity="$(printf "%g\n" "$(echo "${_aur_json}" | jq -r ".Popularity" )" | awk '{printf("%4.2f", $1)}')"
+ _after_vote="$(echo "${_aur_json}" | jq -r ".NumVotes" )"
+
+ # 結果を出力
+ msg_info "%s %s (+%s) → (+%s)" "$(text -b "${_package}")" "$(text -c cyan "${_pkgver}")" "$(text -b "${_before_vote} ${_before_popularity}")" "$(text -b "${_after_vote} ${_after_popularity}")"
+ done
+}
+
+unavailable_in_this_operation() {
+ msg_error "This option is not available in the current operation"
+ exit 1
+}
+
+# オペレーションを実行します
+run_operation() {
+ local _operation="${1}"
+ msg_debug "Operation: %s" "${_operation}"
+ if [[ "${quiet}" = false ]]; then
+ msg_warn "This program is an alpha version that is not yet stable\nIf you find a bug, please share it on GitHub\nhttps://github.com/hayao0819/wfa/issues"
+ fi
+
+ operation_${_operation}
+}
+
# Parse options
ARGUMENT="${@}"
-_opt_short="QRShVdb:aysuc"q
-_opt_long="query,remove,sync,help,version,debug,dbpath:,aururl,aur,noconfirm,config:,makepkg:,mflags:,pacman:,git:,gitflags:,gpg:,gpgflags:,makepkgconf:,nomakepkgconf,nodeps,refresh,bash-debug,msg-debug,sysupgrade,color:,nocolor,clean,quiet"
+_opt_short="AQRShVdb:aysucqn"
+_opt_long="query,remove,sync,help,version,debug,dbpath:,aururl,aur,noconfirm,config:,makepkg:,mflags:,pacman:,git:,gitflags:,gpg:,gpgflags:,makepkgconf:,nomakepkgconf,nodeps,refresh,bash-debug,msg-debug,sysupgrade,color:,nocolor,clean,quiet,arch:,confirm,disable-download-timeout,curl:,curlflags:,unneeded,puella,wfa-debug,cascade"
OPT=$(getopt -o ${_opt_short} -l ${_opt_long} -- ${ARGUMENT})
[[ ${?} != 0 ]] && exit 1
while :; do
case ${1} in
+ -A | --vote)
+ set_operation "vote"
+ shift 1
+ ;;
-Q | --query)
set_operation "query"
shift 1
option_y_count=$(( option_y_count + 1 ))
shift 1
;;
- -s | --search)
- add_args pacman "--search"
- sync_search=true
+ -s | --search | --recursive)
+ case "${1}" in
+ --search)
+ if [[ "${operation}" = "sync" ]]; then
+ add_args pacman "--search"
+ sync_search=true
+ else
+ unavailable_in_this_operation
+ fi
+ ;;
+ --recursive)
+ if [[ "${operation}" = "remove" ]]; then
+ add_args pacman "--recursive"
+ else
+ unavailable_in_this_operation
+ fi
+ ;;
+ -s)
+ case "${operation}" in
+ "sync")
+ add_args pacman "--search"
+ sync_search=true
+ ;;
+ "remove")
+ add_args pacman "--recursive"
+ ;;
+ *)
+ unavailable_in_this_operation
+ ;;
+ esac
+ ;;
+ esac
shift 1
;;
- -u | --sysupgrade)
- sync_upgrade=true
+ -u | --sysupgrade | --unneeded)
+ case "${1}" in
+ --sysupgrade)
+ if [[ "${operation}" = "sync" ]]; then
+ sync_upgrade=true
+ else
+ unavailable_in_this_operation
+ fi
+ ;;
+ --unneeded)
+ if [[ "${operation}" = "remove" ]]; then
+ add_args pacman "--unneeded"
+ else
+ unavailable_in_this_operation
+ fi
+ ;;
+ -u)
+ case "${operation}" in
+ "sync")
+ sync_upgrade=true
+ ;;
+ "remove")
+ add_args pacman "--unneeded"
+ ;;
+ "none")
+ :
+ ;;
+ *)
+ unavailable_in_this_operation
+ ;;
+ esac
+ ;;
+ esac
shift 1
;;
- -c | --clean)
- sync_clean_count=$(( sync_clean_count + 1 ))
+ -c | --clean | --cascade)
+ case "${1}" in
+ --clean)
+ if [[ "${operation}" = "sync" ]]; then
+ sync_clean_count=$(( sync_clean_count + 1 ))
+ else
+ unavailable_in_this_operation
+ fi
+ ;;
+ --cascade)
+ if [[ "${operation}" = "remove" ]]; then
+ add_args pacman "--cascade"
+ else
+ unavailable_in_this_operation
+ fi
+ ;;
+ -c)
+ case "${operation}" in
+ "sync")
+ sync_clean_count=$(( sync_clean_count + 1 ))
+ ;;
+ "remove")
+ add_args pacman "--cascade"
+ ;;
+ *)
+ unavailable_in_this_operation
+ ;;
+ esac
+ ;;
+ esac
shift 1
;;
-q | --quiet)
add_args pacman "--quiet"
shift 1
;;
+ -n | --nosave)
+ add_args pacman "--nosave"
+ shift 1
+ ;;
+ --arch)
+ arch="${2}"
+ add_args pacman "--arch ${2}"
+ shift 2
+ ;;
--aururl)
aururl="${2}"
shift 2
shift 2
;;
--mflags)
- makepkg_args="${2}"
+ #makepkg_args="${2}"
+ add_args makepkg "${2}"
shift 2
;;
--pacman)
shift 2
;;
--gitflags)
- git_args="${2}"
+ #git_args="${2}"
+ add_args git "${2}"
shift 2
;;
--makepkgconfig)
add_args pacman "--color never"
shift 1
;;
+ --confirm)
+ noconfirm=false
+ shift 1
+ ;;
+ --disable-download-timeout)
+ add_args curl "--max-time 0"
+ add_args pacman "--disable-download-timeout"
+ shift 1
+ ;;
+ --curl)
+ curl_command="${2}"
+ shift 2
+ ;;
+ --curlflags)
+ add_args curl "${2}"
+ shift 2
+ ;;
+ --puella)
+ text -flb "Please make a contract with me and become a Puella Magi !"
+ echo
+ shift 1
+ exit 0
+ ;;
+ --wfa-debug)
+ debug=true
+ shift 1
+ ;;
-h | --help)
usage
shift 1
run_pacman -Syy
fi
+# set_operationで設定された操作を実行
case "${operation}" in
- "version")
- operation_version
- ;;
- "sync")
- operation_sync
- ;;
- "remove")
- operation_remove
+ "version" | "sync" | "remove" | "vote")
+ run_operation "${operation}"
;;
"none")
exit 0