feat: POSIX compatibility
This commit is contained in:
		
							
								
								
									
										338
									
								
								piglet
									
									
									
									
									
								
							
							
						
						
									
										338
									
								
								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 <http://unlicense.org/> | ||||
|  | ||||
| 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. | ||||
|  | ||||
| 	/\\ ____ /\\ | ||||
| 	\\/      \\/  <OINK!> | ||||
| 	| *(00)* | / | ||||
| 	\\        /&" | ||||
| 	 |_|--|_| | ||||
| /\ ____ /\ | ||||
| \/      \/  <OINK!> | ||||
| | *(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: | ||||
| 	<https://porkbun.com/api/json/v3/documentation> | ||||
| For more info, please refference to original API Documentation: | ||||
| <https://porkbun.com/api/json/v3/documentation> | ||||
|  | ||||
| 	This software is not affiliated with Porkbun LLC <https://porkbun.com/> | ||||
| 	License: The Unlicense <http://unlicense.org/> | ||||
| 	EOF | ||||
| This software is not affiliated with Porkbun LLC <https://porkbun.com/> | ||||
| License: The Unlicense <http://unlicense.org/> | ||||
| 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: <https://kb.porkbun.com/article/190-getting-started-with-the-porkbun-dns-api>\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";; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user