From 6d9bf8a2ae7dbd3b84cb83d0f854a9d378a45e7f Mon Sep 17 00:00:00 2001 From: Eduard Veit Date: Sat, 3 Apr 2021 13:57:19 +0200 Subject: [PATCH] =?UTF-8?q?feat:=20=F0=9F=94=83=20replace=20getopt=20with?= =?UTF-8?q?=20argbash?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 10 +- README.md | 8 +- dynb.sh | 331 ++++++++++++++++++++++++++++++++++++++++----------- 3 files changed, 269 insertions(+), 80 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 57d92c9..e5f635c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,8 @@ ### New +* :sparkles: replace getopt with argbash. [Eduard Veit] + * :sparkles: add interpretaton of status codes and act accordingly. [Eduard Veit] * :sparkles: make network interface configurable. [Eduard Veit] @@ -13,7 +15,7 @@ * :sparkles: add .gitchangelog.rc. [Eduard Veit] -* :sparkles: add dynb. [Eduard Veit] +* :sparkles: add dynb.sh. [Eduard Veit] ### Fix @@ -25,12 +27,16 @@ * :memo: add CHANGELOG.md. [Eduard Veit] -* :memo: add .env.example. [Eduard Veit] +* :memo: add example.env. [Eduard Veit] * :memo: write README.md. [Eduard Veit] ### Other +* :recycle: refactor, fix and debug error handling. [Eduard Veit] + +* :recycle: refactor main code. [Eduard Veit] + * Initial commit. [EV21] diff --git a/README.md b/README.md index 4451130..eb05676 100644 --- a/README.md +++ b/README.md @@ -31,14 +31,10 @@ The following update methods are currently implemented: * `curl` - The minimum requirement for running DynDNS2 operations -essential for APIs: +also essential if you are using other APIs: * `jq` - Command-line JSON processor -optional requirement: - -* `getopt` for CLI parameter handling from [util-linux](https://pkgs.org/download/util-linux) - ## 🚀 Installation Download the latest release @@ -57,7 +53,7 @@ This convenience function only works if `util-linux` is installed on your system ## ⚙ Configuration You can use a config in form of an `.env` file. -Or if your system meets the relevant requirements you can use CLI parameters. +Or you can just use CLI parameters. Create `.env` in the app root directory or at `~/.local/share/dynb/.env`. ``` diff --git a/dynb.sh b/dynb.sh index da86e28..2c9b698 100755 --- a/dynb.sh +++ b/dynb.sh @@ -35,7 +35,7 @@ TTL=300 ## The IP-Check sites (some sites have different urls for v4 and v6) ## Pro tip: use your own ip check server for privacy -## it could be as simple as that... +## it could be as simple as that... ## create an index.php with _ipv4_checker=api64.ipify.org _ipv6_checker=api64.ipify.org @@ -55,7 +55,6 @@ _new_IPv4= _new_IPv6= _dns_records= _main_domain= -_has_getopt= _is_IPv4_enabled=false _is_IPv6_enabled=false _interface_str= @@ -72,6 +71,222 @@ _configFile=$HOME/.local/share/dynb/.env _statusFile=/tmp/dynb.status _debug=1 +# Created by argbash-init v2.10.0 +# Rearrange the order of options below according to what you would like to see in the help message. +# ARG_OPTIONAL_BOOLEAN([version],[v],[outputs the client version],[off]) +# ARG_OPTIONAL_BOOLEAN([link],[l],[links to your script at ~/.local/bin/dynb],[off]) +# ARG_OPTIONAL_BOOLEAN([reset],[r],[deletes the client blocking status file],[off]) +# ARG_OPTIONAL_BOOLEAN([debug],[],[enables debug mode],[off]) +# ARG_OPTIONAL_SINGLE([update-method],[m],[choose if you want to use DynDNS2 or the DomRobot RPC-API],[]) +# ARG_OPTIONAL_SINGLE([ip-mode],[i],[updates type A (IPv4) and AAAA (IPv6) records],[]) +# ARG_OPTIONAL_SINGLE([domain],[d],[set the domain you want to update],[]) +# ARG_OPTIONAL_SINGLE([service-provider],[s],[set your provider in case you are using DynDNS2],[]) +# ARG_OPTIONAL_SINGLE([username],[u],[depends on your selected update method and your provider],[]) +# ARG_OPTIONAL_SINGLE([password],[p],[depends on your selected update method and your provider],[]) +# ARG_OPTIONAL_SINGLE([token],[t],[depends on your selected update method and your provider],[]) +# ARG_HELP([DynB - dynamic DNS update script for bash]) +# ARGBASH_GO() +# needed because of Argbash --> m4_ignore([ +### START OF CODE GENERATED BY Argbash v2.10.0 one line above ### +# Argbash is a bash code generator used to get arguments parsing right. +# Argbash is FREE SOFTWARE, see https://argbash.io for more info + + +die() +{ + local _ret="${2:-1}" + test "${_PRINT_HELP:-no}" = yes && print_help >&2 + echo "$1" >&2 + exit "${_ret}" +} + + +begins_with_short_option() +{ + local first_option all_short_options='vlrmidsupth' + first_option="${1:0:1}" + test "$all_short_options" = "${all_short_options/$first_option/}" && return 1 || return 0 +} + +# THE DEFAULTS INITIALIZATION - OPTIONALS +_arg_version="off" +_arg_link="off" +_arg_reset="off" +_arg_debug="off" +_arg_update_method= +_arg_ip_mode= +_arg_domain= +_arg_service_provider= +_arg_username= +_arg_password= +_arg_token= + + +print_help() +{ + printf '%s\n' "DynB - dynamic DNS update script for bash" + printf 'Usage: %s [-v|--(no-)version] [-l|--(no-)link] [-r|--(no-)reset] [--(no-)debug] [-m|--update-method ] [-i|--ip-mode ] [-d|--domain ] [-s|--service-provider ] [-u|--username ] [-p|--password ] [-t|--token ] [-h|--help]\n' "$0" + printf '\t%s\n' "-v, --version, --no-version: outputs the client version (off by default)" + printf '\t%s\n' "-l, --link, --no-link: links to your script at ~/.local/bin/dynb (off by default)" + printf '\t%s\n' "-r, --reset, --no-reset: deletes the client blocking status file (off by default)" + printf '\t%s\n' "--debug, --no-debug: enables debug mode (off by default)" + printf '\t%s\n' "-m, --update-method: choose if you want to use DynDNS2 or the DomRobot RPC-API (no default)" + printf '\t%s\n' "-i, --ip-mode: updates type A (IPv4) and AAAA (IPv6) records (no default)" + printf '\t%s\n' "-d, --domain: set the domain you want to update (no default)" + printf '\t%s\n' "-s, --service-provider: set your provider in case you are using DynDNS2 (no default)" + printf '\t%s\n' "-u, --username: depends on your selected update method and your provider (no default)" + printf '\t%s\n' "-p, --password: depends on your selected update method and your provider (no default)" + printf '\t%s\n' "-t, --token: depends on your selected update method and your provider (no default)" + printf '\t%s\n' "-h, --help: Prints help" +} + + +parse_commandline() +{ + while test $# -gt 0 + do + _key="$1" + case "$_key" in + -v|--no-version|--version) + _arg_version="on" + test "${1:0:5}" = "--no-" && _arg_version="off" + ;; + -v*) + _arg_version="on" + _next="${_key##-v}" + if test -n "$_next" -a "$_next" != "$_key" + then + { begins_with_short_option "$_next" && shift && set -- "-v" "-${_next}" "$@"; } || die "The short option '$_key' can't be decomposed to ${_key:0:2} and -${_key:2}, because ${_key:0:2} doesn't accept value and '-${_key:2:1}' doesn't correspond to a short option." + fi + ;; + -l|--no-link|--link) + _arg_link="on" + test "${1:0:5}" = "--no-" && _arg_link="off" + ;; + -l*) + _arg_link="on" + _next="${_key##-l}" + if test -n "$_next" -a "$_next" != "$_key" + then + { begins_with_short_option "$_next" && shift && set -- "-l" "-${_next}" "$@"; } || die "The short option '$_key' can't be decomposed to ${_key:0:2} and -${_key:2}, because ${_key:0:2} doesn't accept value and '-${_key:2:1}' doesn't correspond to a short option." + fi + ;; + -r|--no-reset|--reset) + _arg_reset="on" + test "${1:0:5}" = "--no-" && _arg_reset="off" + ;; + -r*) + _arg_reset="on" + _next="${_key##-r}" + if test -n "$_next" -a "$_next" != "$_key" + then + { begins_with_short_option "$_next" && shift && set -- "-r" "-${_next}" "$@"; } || die "The short option '$_key' can't be decomposed to ${_key:0:2} and -${_key:2}, because ${_key:0:2} doesn't accept value and '-${_key:2:1}' doesn't correspond to a short option." + fi + ;; + --no-debug|--debug) + _arg_debug="on" + test "${1:0:5}" = "--no-" && _arg_debug="off" + ;; + -m|--update-method) + test $# -lt 2 && die "Missing value for the optional argument '$_key'." 1 + _arg_update_method="$2" + shift + ;; + --update-method=*) + _arg_update_method="${_key##--update-method=}" + ;; + -m*) + _arg_update_method="${_key##-m}" + ;; + -i|--ip-mode) + test $# -lt 2 && die "Missing value for the optional argument '$_key'." 1 + _arg_ip_mode="$2" + shift + ;; + --ip-mode=*) + _arg_ip_mode="${_key##--ip-mode=}" + ;; + -i*) + _arg_ip_mode="${_key##-i}" + ;; + -d|--domain) + test $# -lt 2 && die "Missing value for the optional argument '$_key'." 1 + _arg_domain="$2" + shift + ;; + --domain=*) + _arg_domain="${_key##--domain=}" + ;; + -d*) + _arg_domain="${_key##-d}" + ;; + -s|--service-provider) + test $# -lt 2 && die "Missing value for the optional argument '$_key'." 1 + _arg_service_provider="$2" + shift + ;; + --service-provider=*) + _arg_service_provider="${_key##--service-provider=}" + ;; + -s*) + _arg_service_provider="${_key##-s}" + ;; + -u|--username) + test $# -lt 2 && die "Missing value for the optional argument '$_key'." 1 + _arg_username="$2" + shift + ;; + --username=*) + _arg_username="${_key##--username=}" + ;; + -u*) + _arg_username="${_key##-u}" + ;; + -p|--password) + test $# -lt 2 && die "Missing value for the optional argument '$_key'." 1 + _arg_password="$2" + shift + ;; + --password=*) + _arg_password="${_key##--password=}" + ;; + -p*) + _arg_password="${_key##-p}" + ;; + -t|--token) + test $# -lt 2 && die "Missing value for the optional argument '$_key'." 1 + _arg_token="$2" + shift + ;; + --token=*) + _arg_token="${_key##--token=}" + ;; + -t*) + _arg_token="${_key##-t}" + ;; + -h|--help) + print_help + exit 0 + ;; + -h*) + print_help + exit 0 + ;; + *) + _PRINT_HELP=yes die "FATAL ERROR: Got an unexpected argument '$1'" 1 + ;; + esac + shift + done +} + +parse_commandline "$@" + +# OTHER STUFF GENERATED BY Argbash + +### END OF CODE GENERATED BY Argbash (sortof) ### ]) +# [ <-- needed because of Argbash + _help_message="$(cat << 'EOF' dynb - dynamic DNS update script for bash @@ -155,7 +370,7 @@ function fetchDNSRecords() { } # requires parameter A or AAAA -# result to stdout +# result to stdout function getRecordID() { echo "$_dns_records" | jq "select(.type == \"${1}\") | .id" } @@ -422,69 +637,45 @@ function ipHasChanged() { fi } -############### -## arguments ## -############### +################ +## parameters ## +################ -ARGS= -if [[ $_has_getopt == "" ]] && [[ $(uname) == Linux ]]; then - ARGS=$(getopt --options "hvi:,d:,m:,s:,u:,p:,t:" --longoptions "help,version,link,ip-mode:,domain:,update-method:,service-provider:,username:,password:,token:,reset" -- "$@"); -fi -eval set -- "$ARGS"; -unset ARGS - -function processParameters() { - while true; do - case $1 in - -h | --help ) - echo "$_help_message" - exit 0 - ;; - -v | --version ) - echo "$_version" - exit 0 - ;; - --link ) - ln --verbose --symbolic "$(realpath "$0")" "$HOME/.local/bin/dynb" - exit 0 - ;; - -i | --ip-mode ) - _ip_mode=$2 - shift 2 - ;; - -d | --domain ) - _dyn_domain=$2 - shift 2 - ;; - -m | --update-method ) - _update_method=$2 - shift 2 - ;; - -s | --service-provider ) - _serviceProvider=$2 - shift 2 - ;; - -u | --username ) - _username=$2 - shift 2 - ;; - -p | --password ) - _password=$2 - shift 2 - ;; - -t | --token ) - _token=$2 - shift 2 - ;; - --reset ) - rm --verbose "$_statusFile" - exit 0 - ;; - --) - shift - break - esac - done +function handleParameters() { + if [[ $_arg_version == "on" ]]; then + echo $_version + exit 0 + fi + if [[ $_arg_link == "on" ]]; then + ln --verbose --symbolic "$(realpath "$0")" "$HOME/.local/bin/dynb" + exit 0 + fi + if [[ $_arg_reset == "on" ]]; then + rm --verbose "$_statusFile" + exit 0 + fi + if [[ $_arg_update_method != "" ]]; then + _update_method=$_arg_update_method + fi + if [[ $_arg_ip_mode != "" ]]; then + _ip_mode=$_arg_ip_mode + fi + if [[ $_arg_domain != "" ]]; then + _dyn_domain=$_arg_domain + fi + if [[ $_arg_service_provider != "" ]]; then + _serviceProvider=$_arg_service_provider + fi + if [[ $_arg_username != "" ]]; then + _username=$_arg_username + fi + if [[ $_arg_password != "" ]]; then + _password=$_arg_password + fi + if [[ $_arg_token != "" ]]; then + _token=$_arg_token + fi + return 0 } ################## @@ -505,10 +696,6 @@ function checkDependencies() { exit 1 fi } - # maybe replace this with matejak/argbash - [[ -x $(command -v getopt 2> /dev/null) ]] || { - _has_getopt=false - } } function doUnsets() { @@ -557,9 +744,7 @@ function dynb() { source "$_statusFile" fi - if [[ $_has_getopt == "" ]] && [[ $(uname) == Linux ]]; then - processParameters "$@" - fi + handleParameters if [[ $_network_interface != "" ]]; then _interface_str="--interface $_network_interface" @@ -628,3 +813,5 @@ function dynb() { dynb "${@}" exit $? + +# ] <-- needed because of Argbash