From ca762cf21c14476a9d39e8dba75a95daa3cd215a Mon Sep 17 00:00:00 2001 From: ge Date: Sun, 28 Aug 2022 11:29:13 +0300 Subject: [PATCH] feat: POSIX compatibility --- piglet | 338 +++++++++++++++++++++++++++------------------------------ 1 file changed, 161 insertions(+), 177 deletions(-) diff --git a/piglet b/piglet index ec0fdb8..c2aced7 100755 --- a/piglet +++ b/piglet @@ -1,4 +1,4 @@ -#!/usr/bin/env bash +#!/bin/sh # piglet - Porkbun DNS API client. # @@ -27,123 +27,123 @@ # # For more information, please refer to -piglet_version='0.1' +piglet_version='0.1.1' piglet_conf="${HOME}/.config/piglet.conf" print_help() { - cat <<- EOF - Porkbun DNS API client. +cat <<- 'EOF' +Porkbun DNS API client. - /\\ ____ /\\ - \\/ \\/ - | *(00)* | / - \\ /&" - |_|--|_| +/\ ____ /\ +\/ \/ +| *(00)* | / +\ /&" + |_|--|_| - Usage: piglet [-cdjhv] command [arg=value ...] +Usage: piglet [-cdjhv] command [arg=value ...] - Options: - -c, --config path to configuration file [default: ~/.config/piglet.conf] - -d, --domain domain name on which operations will be performed. - -j, --json raw JSON output. - -h, --help print this help message and exit. - -v, --version print version and exit. +Options: + -c, --config path to configuration file [default: ~/.config/piglet.conf] + -d, --domain domain name on which operations will be performed. + -j, --json raw JSON output. + -h, --help print this help message and exit. + -v, --version print version and exit. - Commands: - create Create a DNS record. - edit Edit a DNS record by Domain and ID. - delete Delete a specific DNS record by ID. - retrieve Retrieve all DNS records or a single record by ID. - config Setup configuration file. +Commands: + create Create a DNS record. + edit Edit a DNS record by Domain and ID. + delete Delete a specific DNS record by ID. + retrieve Retrieve all DNS records or a single record by ID. + config Setup configuration file. - Use 'piglet command --help' to see detailed help. +Use 'piglet command --help' to see detailed help. - For more info, please refference to original API Documentation: - +For more info, please refference to original API Documentation: + - This software is not affiliated with Porkbun LLC - License: The Unlicense - EOF +This software is not affiliated with Porkbun LLC +License: The Unlicense +EOF exit 0 } -print_help::create() { +print_help_create() { cat <<- EOF - Create a DNS record. +Create a DNS record. - Usage: piglet [options...] create [arg=value ...] +Usage: piglet [options...] create [arg=value ...] - Arguments: - name (optional) - The subdomain for the record being created, not including - the domain itself. Leave blank to create a record on the root domain. - Use '*' to create a wildcard record. - type - The type of record being created. Valid types are: A, MX, CNAME, ALIAS, - TXT, NS, AAAA, SRV, TLSA, CAA. - content - The answer content for the record. - ttl (optional) [default: 600 seconds] - The time to live in seconds for the record - prio (optional) [default: 0] - The priority of the record for those that support it. - EOF +Arguments: + name (optional) + The subdomain for the record being created, not including + the domain itself. Leave blank to create a record on the root domain. + Use '*' to create a wildcard record. + type + The type of record being created. Valid types are: A, MX, CNAME, ALIAS, + TXT, NS, AAAA, SRV, TLSA, CAA. + content + The answer content for the record. + ttl (optional) [default: 600 seconds] + The time to live in seconds for the record + prio (optional) [default: 0] + The priority of the record for those that support it. +EOF exit 0 } -print_help::edit() { +print_help_edit() { cat <<- EOF - Edit a DNS record by Domain and ID. +Edit a DNS record by Domain and ID. - Usage: piglet [options...] edit [arg=value ...] +Usage: piglet [options...] edit [arg=value ...] - Arguments: - id - ID of DNS record to edit. - name (optional) - The subdomain for the record being created, not including - the domain itself. Leave blank to create a record on the root domain. - Use '*' to create a wildcard record. - type - The type of record being created. Valid types are: A, MX, CNAME, ALIAS, - TXT, NS, AAAA, SRV, TLSA, CAA. - content - The answer content for the record. - ttl (optional) [default: 600 seconds] - The time to live in seconds for the record - prio (optional) [default: 0] - The priority of the record for those that support it. - EOF +Arguments: + id + ID of DNS record to edit. + name (optional) + The subdomain for the record being created, not including + the domain itself. Leave blank to create a record on the root domain. + Use '*' to create a wildcard record. + type + The type of record being created. Valid types are: A, MX, CNAME, ALIAS, + TXT, NS, AAAA, SRV, TLSA, CAA. + content + The answer content for the record. + ttl (optional) [default: 600 seconds] + The time to live in seconds for the record + prio (optional) [default: 0] + The priority of the record for those that support it. +EOF exit 0 } -print_help::delete() { +print_help_delete() { cat <<- EOF - Delete a specific DNS record by Doman and ID.. +Delete a specific DNS record by Doman and ID.. - Usage: piglet [options...] delete [arg=value ...] +Usage: piglet [options...] delete [arg=value ...] - Arguments: - id - DNS record ID. - EOF +Arguments: + id + DNS record ID. +EOF exit 0 } -print_help::retrieve() { +print_help_retrieve() { cat <<- EOF - Retrieve all editable DNS records associated with a domain or a single record - for a particular record ID. +Retrieve all editable DNS records associated with a domain or a single record +for a particular record ID. - Usage: piglet [options...] retrieve [arg=value ...] +Usage: piglet [options...] retrieve [arg=value ...] - Retrieve options: - -h, --help print this help message and exit. +Retrieve options: + -h, --help print this help message and exit. - Arguments: - id (optional) - DNS record ID. - EOF +Arguments: + id (optional) + DNS record ID. +EOF exit 0 } @@ -151,69 +151,51 @@ print_help::retrieve() { # API methods # # ----------------------------------------- # -api::create() { +api_create() { # Create DNS record. # See: https://porkbun.com/api/json/v3/documentation#DNS%20Create%20Record - # Usage: api::create domain name type content ttl prio + # Usage: api_create domain name type content ttl prio - local Domain="$1" - local Name="$2" - local Type="$3" - local Content="$4" - local TTL="$5" - local Prio="$6" - - curl -sS -X POST https://porkbun.com/api/json/v3/dns/create/$Domain \ + curl -sS -X POST https://porkbun.com/api/json/v3/dns/create/"$1" \ --data '{ "secretapikey": "'"$Secret_API_Key"'", "apikey": "'"$API_Key"'", - "name": "'"$Name"'", - "type": "'"$Type"'", - "content": "'"$Content"'", - "ttl": "'"$TTL"'", - "prio": "'"$Prio"'" + "name": "'"$2"'", + "type": "'"$3"'", + "content": "'"$4"'", + "ttl": "'"$5"'", + "prio": "'"$6"'" }' echo # just print new line } -api::edit() { +api_edit() { # Edit DNS record by Domain and ID. # See: https://porkbun.com/api/json/v3/documentation#DNS%20Edit%20Record%20by%20Domain%20and%20ID - # Usage: api::edit doamin id name type content ttl prio + # Usage: api_edit doamin id name type content ttl prio - local Domain="$1" - local ID="$2" - local Name="$3" - local Type="$4" - local Content="$5" - local TTL="$6" - local Prio="$7" - - curl -sS -X POST https://porkbun.com/api/json/v3/dns/edit/$Domain/$ID \ + curl -sS -X POST https://porkbun.com/api/json/v3/dns/edit/"$1"/"$2" \ --data '{ "secretapikey": "'"$Secret_API_Key"'", "apikey": "'"$API_Key"'", - "name": "'"$Name"'", - "type": "'"$Type"'", - "content": "'"$Content"'", - "ttl": "'"$TTL"'", - "prio": "'"$Prio"'" + "name": "'"$3"'", + "type": "'"$4"'", + "content": "'"$5"'", + "ttl": "'"$6"'", + "prio": "'"$7"'" }' echo # just print new line } -api::delete() { +api_delete() { # Delete DNS record. # See: https://porkbun.com/api/json/v3/documentation#DNS%20Delete%20Record%20by%20Domain%20and%20ID - # Usage: api::delete domain id + # Usage: api_delete domain id - local Domain="$1" - local ID="$2" - - curl -sS -X POST https://porkbun.com/api/json/v3/dns/delete/$Domain/$ID \ + curl -sS -X POST https://porkbun.com/api/json/v3/dns/delete/"$1"/"$2" \ --data '{ "secretapikey": "'"$Secret_API_Key"'", "apikey": "'"$API_Key"'" @@ -221,23 +203,19 @@ api::delete() { echo # just print new line } -api::retrieve() { +api_retrieve() { # Retrieve DNS records. # See: https://porkbun.com/api/json/v3/documentation#DNS%20Retrieve%20Records%20by%20Domain%20or%20ID - # Usage: api::retrieve domain id - # Function arguments: - # $1 domain name - # $2 DNS record ID + # Usage: api_retrieve domain id - local target= + _target="$1" - target="$1" - if [[ "$1" && "$2" ]]; then - target="${1}/${2}" + if [ "$#" -eq 2 ]; then + target="$1/$2" fi - curl -sS -X POST https://porkbun.com/api/json/v3/dns/retrieve/$target \ + curl -sS -X POST https://porkbun.com/api/json/v3/dns/retrieve/"$target" \ --data '{ "secretapikey": "'"$Secret_API_Key"'", "apikey": "'"$API_Key"'" @@ -251,37 +229,44 @@ api::retrieve() { _init_piglet() { # Source configuration file + # shellcheck disable=SC1090 . "$piglet_conf" - [[ "$API_Key" && "$Secret_API_Key" ]] || { - echo "Bad API credentials. Please check the ${piglet_conf}. " \ + if [ -z "$API_Key" ] || [ -z "$Secret_API_Key" ]; then + echo "Bad API credentials. Please check the ${piglet_conf}. " \ "Run 'piglet config' to create new config file." >&2; exit 1 - } - [ "$domain" ] || { echo 'Domain name is not set' >&2; exit 1; } + fi + + if [ -z "$domain" ]; then + echo 'Domain name is not set' >&2; exit 1; + fi } piglet_config() { - echo -e "Enter Porkbun DNS API keys. Press ^C to cancel.\n" \ - "\bHelp: \n" - read -p 'API_Key: ' api_key - read -p 'Secret_API_Key: ' secret_api_key + mkdir -p "$HOME"/.config + + printf '%s\n%s\n' \ + "Enter Porkbun DNS API keys. Press ^C to cancel." \ + "Help: https://kb.porkbun.com/article/190-getting-started-with-the-porkbun-dns-api" + + printf '%s ' 'API_Key:'; read -r api_key + printf '%s ' 'Secret_API_Key:'; read -r secret_api_key + cat > "$piglet_conf" <<- EOF - # Porkbun DNS API credentials - API_Key=$api_key - Secret_API_Key=$secret_api_key - EOF - echo -e "Config saved as $piglet_conf" +# Porkbun DNS API credentials +API_Key=$api_key +Secret_API_Key=$secret_api_key +EOF + printf 'Config saved as %s\n' "$piglet_conf" } piglet_create() { - local name= type= content= ttl= prio= - - while (( "$#" )); do + while [ "$#" -ne 0 ]; do case "$1" in -c|--config|--config=*) opts "$1" "$2"; piglet_conf="$val"; shift "$sft";; -d|--domain|--domain=*) opts "$1" "$2"; domain="$val"; shift "$sft";; -j|--json) raw_json=1; shift;; - -h|--help) print_help::create;; + -h|--help) print_help_create;; name=*) name="${1##*=}"; shift;; type=*) type="${1##*=}"; shift;; content=*) content="${1##*=}"; shift;; @@ -294,18 +279,16 @@ piglet_create() { _init_piglet - api::create "$domain" "$name" "$type" "$content" "$ttl" "$prio" + api_create "$domain" "$name" "$type" "$content" "$ttl" "$prio" } piglet_edit() { - local record_id= name= type= content= ttl= prio= - - while (( "$#" )); do + while [ "$#" -ne 0 ]; do case "$1" in -c|--config|--config=*) opts "$1" "$2"; piglet_conf="$val"; shift "$sft";; -d|--domain|--domain=*) opts "$1" "$2"; domain="$val"; shift "$sft";; -j|--json) raw_json=1; shift;; - -h|--help) print_help::edit;; + -h|--help) print_help_edit;; id=*) record_id="${1##*=}"; shift;; name=*) name="${1##*=}"; shift;; type=*) type="${1##*=}"; shift;; @@ -319,18 +302,16 @@ piglet_edit() { _init_piglet - api::edit "$domain" "$record_id" "$name" "$type" "$content" "$ttl" "$prio" + api_edit "$domain" "$record_id" "$name" "$type" "$content" "$ttl" "$prio" } piglet_delete() { - local record_id= - - while (( "$#" )); do + while [ "$#" -ne 0 ]; do case "$1" in -c|--config|--config=*) opts "$1" "$2"; piglet_conf="$val"; shift "$sft";; -d|--domain|--domain=*) opts "$1" "$2"; domain="$val"; shift "$sft";; -j|--json) raw_json=1; shift;; - -h|--help) print_help::delete;; + -h|--help) print_help_delete;; id=*) record_id="${1##*=}"; shift;; -*) echo "Unknown option: $1" >&2; exit 1;; *) echo "Unknown key: $1" >&2; exit 1;; @@ -339,18 +320,16 @@ piglet_delete() { _init_piglet - api::delete "$domain" "$record_id" + api_delete "$domain" "$record_id" } piglet_retrieve() { - local json_out= record_id= - - while (( "$#" )); do + while [ "$#" -ne 0 ]; do case "$1" in -c|--config|--config=*) opts "$1" "$2"; piglet_conf="$val"; shift "$sft";; -d|--domain|--domain=*) opts "$1" "$2"; domain="$val"; shift "$sft";; -j|--json) raw_json=1; shift;; - -h|--help) print_help::retrieve;; + -h|--help) print_help_retrieve;; id=*) record_id="${1##*=}"; shift;; -*) echo "Unknown option: $1" >&2; exit 1;; *) echo "Unknown key: $1" >&2; exit 1;; @@ -359,11 +338,11 @@ piglet_retrieve() { _init_piglet - json_out="$(api::retrieve "$domain" "$record_id")" + json_out="$(api_retrieve "$domain" "$record_id")" if ! hash jq 2>/dev/null; then raw_json=1 - echo -e "Install jq to enable table view." + echo "Install jq to enable table view." >&2 fi if [ "$raw_json" ]; then @@ -390,34 +369,39 @@ opts() { # $val - option value. # $sft - value for shift. - if [[ "$1" =~ .+=.+ ]]; then - opt="${1%%=*}"; val="${1#*=}"; sft=1 - elif [[ ! "$1" =~ .+=$ ]] && \ - [ "$2" ] && [ "${2:0:1}" != "-" ] - then - opt="$1"; val="$2"; sft=2 - else - opt="$1" - if [[ "$1" =~ .+=$ ]]; then opt="${1:0: -1}"; fi - echo "Missing argument for $opt" >& /dev/null; exit 1 + opt="${1%%=*}"; val="${1##*=}"; sft=1 + + if [ "$opt" = "$val" ]; then + if [ -n "$2" ] && [ "$(echo "$2" | cut -c1-1)" != "-" ]; then + val="$2"; sft=2 + else + unset val + fi + fi + + if [ -z "$val" ]; then + printf 'Missing argument for option %s\n' "$opt" >&2; exit 1 fi } -[[ "$@" ]] || print_help +if [ "$#" -eq 0 ]; then + print_help +fi # Split combined short options, e.g. '-abc' to '-a' '-b' '-c' for args in "$@"; do shift case "$args" in --*) set -- "$@" "$args";; # save long options - -*) args="$(echo "${args:1}" | grep -o . | xargs -I {} echo -n '-{} ')" + -*) args="$(echo "${args#-}" | grep -o . | xargs -I {} echo -n '-{} ')" + # shellcheck disable=SC2086 set -- "$@" $args;; *) set -- "$@" "$args";; # save positional arguments esac done # Final arguments parser -while (( "$#" )); do +while [ "$#" -ne 0 ]; do case "$1" in -c|--config|--config=*) opts "$1" "$2"; piglet_conf="$val"; shift "$sft";; -d|--domain|--domain=*) opts "$1" "$2"; domain="$val"; shift "$sft";;