From 85388901cf6a69659569ad751767fd7108b25a3c Mon Sep 17 00:00:00 2001 From: Yehonal Date: Sun, 15 Jul 2018 22:40:49 +0200 Subject: Rewrite of bash system + Implemented new dashboard menu + some fixes for db_assembler + new module installation process with version check via json files + some fixes to modules installer + implemented simple crossplatform worldserver and authserver restarters + new compiler script + client data downloader (beta) + various other fixes --- deps/jsonpath/.gitignore | 5 + deps/jsonpath/.travis.yml | 10 + deps/jsonpath/CNAME | 1 + deps/jsonpath/JSONPath.sh | 857 ++++++++++++++++++++++++++++++++++++++++ deps/jsonpath/LICENSE.APACHE2 | 15 + deps/jsonpath/LICENSE.MIT | 24 ++ deps/jsonpath/MANIFEST.in | 3 + deps/jsonpath/README.md | 491 +++++++++++++++++++++++ deps/jsonpath/_config.yml | 1 + deps/jsonpath/all-tests.sh | 33 ++ deps/jsonpath/package.json | 19 + deps/jsonpath/setup.py | 31 ++ deps/semver_bash/.gitignore | 4 + deps/semver_bash/LICENSE | 26 ++ deps/semver_bash/README.md | 31 ++ deps/semver_bash/semver.sh | 130 ++++++ deps/semver_bash/semver_test.sh | 151 +++++++ 17 files changed, 1832 insertions(+) create mode 100644 deps/jsonpath/.gitignore create mode 100644 deps/jsonpath/.travis.yml create mode 100644 deps/jsonpath/CNAME create mode 100644 deps/jsonpath/JSONPath.sh create mode 100644 deps/jsonpath/LICENSE.APACHE2 create mode 100644 deps/jsonpath/LICENSE.MIT create mode 100644 deps/jsonpath/MANIFEST.in create mode 100644 deps/jsonpath/README.md create mode 100644 deps/jsonpath/_config.yml create mode 100644 deps/jsonpath/all-tests.sh create mode 100644 deps/jsonpath/package.json create mode 100644 deps/jsonpath/setup.py create mode 100644 deps/semver_bash/.gitignore create mode 100644 deps/semver_bash/LICENSE create mode 100644 deps/semver_bash/README.md create mode 100644 deps/semver_bash/semver.sh create mode 100644 deps/semver_bash/semver_test.sh (limited to 'deps') diff --git a/deps/jsonpath/.gitignore b/deps/jsonpath/.gitignore new file mode 100644 index 0000000000..36ed3d2069 --- /dev/null +++ b/deps/jsonpath/.gitignore @@ -0,0 +1,5 @@ +test/errlog +test/outlog + +# vi .swp files +.*.swp diff --git a/deps/jsonpath/.travis.yml b/deps/jsonpath/.travis.yml new file mode 100644 index 0000000000..acf1f26295 --- /dev/null +++ b/deps/jsonpath/.travis.yml @@ -0,0 +1,10 @@ +language: python + +addons: + apt: + packages: + - bash + +# Whatever the current shebang, replace with hardcoded shell +script: > + ./all-tests.sh diff --git a/deps/jsonpath/CNAME b/deps/jsonpath/CNAME new file mode 100644 index 0000000000..4f3d0812c3 --- /dev/null +++ b/deps/jsonpath/CNAME @@ -0,0 +1 @@ +jsonpath.obdi.io \ No newline at end of file diff --git a/deps/jsonpath/JSONPath.sh b/deps/jsonpath/JSONPath.sh new file mode 100644 index 0000000000..a03752e130 --- /dev/null +++ b/deps/jsonpath/JSONPath.sh @@ -0,0 +1,857 @@ +#!/bin/bash + +# --------------------------------------------------------------------------- +# GLOBALS +# --------------------------------------------------------------------------- + +DEBUG=0 +INCLEMPTY=0 +NOCASE=0 +WHOLEWORD=0 +FILE= +NO_HEAD=0 +NORMALIZE_SOLIDUS=0 +BRIEF=0 +PASSTHROUGH=0 +JSON=0 +PRINT=1 +MULTIPASS=0 +FLATTEN=0 +STDINFILE=/var/tmp/JSONPath.$$.stdin +STDINFILE2=/var/tmp/JSONPath.$$.stdin2 +PASSFILE=/var/tmp/JSONPath.$$.pass1 +declare -a INDEXMATCH_QUERY + +# --------------------------------------------------------------------------- +main() { +# --------------------------------------------------------------------------- +# It all starts here + + parse_options "$@" + + trap cleanup EXIT + + if [[ $QUERY == *'?(@'* ]]; then + # This will be a multipass query + + [[ -n $FILE ]] && STDINFILE=$FILE + [[ -z $FILE ]] && cat >$STDINFILE + + while true; do + tokenize_path + create_filter + + cat "$STDINFILE" | tokenize | parse | filter | indexmatcher >$PASSFILE + + [[ $MULTIPASS -eq 1 ]] && { + # replace filter expression with index sequence + SET=$(sed -rn 's/.*,([0-9]+)[],].*/\1/p' $PASSFILE | tr '\n' ,) + SET=${SET%,} + QUERY=$(echo $QUERY | sed "s/?(@[^)]\+)/$SET/") + [[ $DEBUG -eq 1 ]] && echo "QUERY=$QUERY" + reset + continue + } + + cat $PASSFILE | flatten | json | brief + + break + done + + else + + tokenize_path + create_filter + + if [[ $PASSTHROUGH -eq 1 ]]; then + JSON=1 + flatten | json + elif [[ -z $FILE ]]; then + tokenize | parse | filter | indexmatcher | flatten | json | brief + else + cat "$FILE" | tokenize | parse | filter | indexmatcher | flatten | \ + json | brief + fi + + fi +} + +# --------------------------------------------------------------------------- +reset() { +# --------------------------------------------------------------------------- + + # Reset some vars + declare -a INDEXMATCH_QUERY + PATHTOKENS= + FILTER= + OPERATOR= + RHS= + MULTIPASS=0 +} + +# --------------------------------------------------------------------------- +cleanup() { +# --------------------------------------------------------------------------- + + [[ -e "$PASSFILE" ]] && rm -f "$PASSFILE" + [[ -e "$STDINFILE2" ]] && rm -f "$STDINFILE2" + [[ -z "$FILE" && -e "$STDINFILE" ]] && rm -f "$STDINFILE" +} + +# --------------------------------------------------------------------------- +usage() { +# --------------------------------------------------------------------------- + + echo + echo "Usage: JSONPath.sh [-b] [j] [-h] [-f FILE] [pattern]" + echo + echo "pattern - the JSONPath query. Defaults to '$.*' if not supplied." + #echo "-s - Remove escaping of the solidus symbol (straight slash)." + echo "-b - Brief. Only show values." + echo "-j - JSON ouput." + echo "-u - Strip unnecessary leading path elements." + echo "-i - Case insensitive." + echo "-p - Pass-through to the JSON parser." + echo "-w - Match whole words only (for filter script expression)." + echo "-f FILE - Read a FILE instead of stdin." + #echo "-n - No-head. Do not show nodes that have no path (lines that start with [])." + echo "-h - This help text." + echo +} + +# --------------------------------------------------------------------------- +parse_options() { +# --------------------------------------------------------------------------- + + set -- "$@" + local ARGN=$# + while [ "$ARGN" -ne 0 ] + do + case $1 in + -h) usage + exit 0 + ;; + -f) shift + FILE=$1 + ;; + -i) NOCASE=1 + ;; + -j) JSON=1 + ;; + -n) NO_HEAD=1 + ;; + -b) BRIEF=1 + ;; + -u) FLATTEN=1 + ;; + -p) PASSTHROUGH=1 + ;; + -w) WHOLEWORD=1 + ;; + -s) NORMALIZE_SOLIDUS=1 + ;; + ?*) QUERY=$1 + ;; + esac + shift 1 + ARGN=$((ARGN-1)) + done + [[ -z $QUERY ]] && QUERY='$.*' +} + +# --------------------------------------------------------------------------- +awk_egrep() { +# --------------------------------------------------------------------------- + local pattern_string=$1 + + gawk '{ + while ($0) { + start=match($0, pattern); + token=substr($0, start, RLENGTH); + print token; + $0=substr($0, start+RLENGTH); + } + }' pattern="$pattern_string" +} + +# --------------------------------------------------------------------------- +tokenize() { +# --------------------------------------------------------------------------- +# json parsing + + local GREP + local ESCAPE + local CHAR + + if echo "test string" | egrep -ao --color=never "test" >/dev/null 2>&1 + then + GREP='egrep -ao --color=never' + else + GREP='egrep -ao' + fi + + if echo "test string" | egrep -o "test" >/dev/null 2>&1 + then + ESCAPE='(\\[^u[:cntrl:]]|\\u[0-9a-fA-F]{4})' + CHAR='[^[:cntrl:]"\\]' + else + GREP=awk_egrep + ESCAPE='(\\\\[^u[:cntrl:]]|\\u[0-9a-fA-F]{4})' + CHAR='[^[:cntrl:]"\\\\]' + fi + + local STRING="\"$CHAR*($ESCAPE$CHAR*)*\"" + local NUMBER='-?(0|[1-9][0-9]*)([.][0-9]*)?([eE][+-]?[0-9]*)?' + local KEYWORD='null|false|true' + local SPACE='[[:space:]]+' + + # Force zsh to expand $A into multiple words + local is_wordsplit_disabled=$(unsetopt 2>/dev/null | grep -c '^shwordsplit$') + if [ $is_wordsplit_disabled != 0 ]; then setopt shwordsplit; fi + $GREP "$STRING|$NUMBER|$KEYWORD|$SPACE|." | egrep -v "^$SPACE$" + if [ $is_wordsplit_disabled != 0 ]; then unsetopt shwordsplit; fi +} + +# --------------------------------------------------------------------------- +tokenize_path () { +# --------------------------------------------------------------------------- + local GREP + local ESCAPE + local CHAR + + if echo "test string" | egrep -ao --color=never "test" >/dev/null 2>&1 + then + GREP='egrep -ao --color=never' + else + GREP='egrep -ao' + fi + + if echo "test string" | egrep -o "test" >/dev/null 2>&1 + then + CHAR='[^[:cntrl:]"\\]' + else + GREP=awk_egrep + #CHAR='[^[:cntrl:]"\\\\]' + fi + + local WILDCARD='\*' + local WORD='[ A-Za-z0-9_-]*' + local INDEX="\\[$WORD(:$WORD){0,2}\\]" + local INDEXALL="\\[\\*\\]" + local STRING="[\\\"'][^[:cntrl:]\\\"']*[\\\"']" + local SET="\\[($WORD|$STRING)(,($WORD|$STRING))*\\]" + local FILTER='\?\(@[^)]+' + local DEEPSCAN="\\.\\." + local SPACE='[[:space:]]+' + + # Force zsh to expand $A into multiple words + local is_wordsplit_disabled=$(unsetopt 2>/dev/null | grep -c '^shwordsplit$') + if [ $is_wordsplit_disabled != 0 ]; then setopt shwordsplit; fi + readarray -t PATHTOKENS < <( echo "$QUERY" | \ + $GREP "$INDEX|$STRING|$WORD|$WILDCARD|$FILTER|$DEEPSCAN|$SET|$INDEXALL|." | \ + egrep -v "^$SPACE$|^\\.$|^\[$|^\]$|^'$|^\\\$$|^\)$") + [[ $DEBUG -eq 1 ]] && { + echo "egrep -o '$INDEX|$STRING|$WORD|$WILDCARD|$FILTER|$DEEPSCAN|$SET|$INDEXALL|.'" + echo -n "TOKENISED QUERY="; echo "$QUERY" | \ + $GREP "$INDEX|$STRING|$WORD|$WILDCARD|$FILTER|$DEEPSCAN|$SET|$INDEXALL|." | \ + egrep -v "^$SPACE$|^\\.$|^\[$|^\]$|^'$|^\\\$$|^\)$" + } + if [ $is_wordsplit_disabled != 0 ]; then unsetopt shwordsplit; fi +} + +# --------------------------------------------------------------------------- +create_filter() { +# --------------------------------------------------------------------------- +# Creates the filter from the user's query. +# Filter works in a single pass through the data, unless a filter (script) +# expression is used, in which case two passes are required (MULTIPASS=1). + + local len=${#PATHTOKENS[*]} + + local -i i=0 + local query="^\[" comma= + while [[ i -lt len ]]; do + case "${PATHTOKENS[i]}" in + '"') : + ;; + '..') query+="$comma[^]]*" + comma= + ;; + '[*]') query+="$comma[^,]*" + comma="," + ;; + '*') query+="$comma(\"[^\"]*\"|[0-9]+[^],]*)" + comma="," + ;; + '?(@'*) a=${PATHTOKENS[i]#?(@.} + elem="${a%%[<>=!]*}" + rhs="${a##*[<>=!]}" + a="${a#$elem}" + elem="${elem//./[\",.]+}" # Allows child node matching + operator="${a%$rhs}" + [[ -z $operator ]] && { operator="=="; rhs=; } + if [[ $rhs == *'"'* || $rhs == *"'"* ]]; then + case $operator in + '=='|'=') OPERATOR= + if [[ $elem == '?(@' ]]; then + # To allow search on @.property such as: + # $..book[?(@.title==".*Book 1.*")] + query+="$comma[0-9]+[],][[:space:]\"]*${rhs//\"/}" + else + # To allow search on @ (this node) such as: + # $..reviews[?(@==".*Fant.*")] + query+="$comma[0-9]+,\"$elem\"[],][[:space:]\"]*${rhs//\"/}" + fi + FILTER="$query" + ;; + '>='|'>') OPERATOR=">" + RHS="$rhs" + query+="$comma[0-9]+,\"$elem\"[],][[:space:]\"]*" + FILTER="$query" + ;; + '<='|'<') OPERATOR="<" + RHS="$rhs" + query+="$comma[0-9]+,\"$elem\"[],][[:space:]\"]*" + FILTER="$query" + ;; + esac + else + case $operator in + '=='|'=') OPERATOR= + query+="$comma[0-9]+,\"$elem\"[],][[:space:]\"]*$rhs" + FILTER="$query" + ;; + '>=') OPERATOR="-ge" + RHS="$rhs" + query+="$comma[0-9]+,\"$elem\"[],][[:space:]\"]*" + FILTER="$query" + ;; + '>') OPERATOR="-gt" + RHS="$rhs" + query+="$comma[0-9]+,\"$elem\"[],][[:space:]\"]*" + FILTER="$query" + ;; + '<=') OPERATOR="-le" + RHS="$rhs" + query+="$comma[0-9]+,\"$elem\"[],][[:space:]\"]*" + FILTER="$query" + ;; + '<') OPERATOR="-lt" + RHS="$rhs" + query+="$comma[0-9]+,\"$elem\"[],][[:space:]\"]*" + FILTER="$query" + esac + fi + MULTIPASS=1 + ;; + "["*) if [[ ${PATHTOKENS[i]} =~ , ]]; then + a=${PATHTOKENS[i]#[} + a=${a%]} + if [[ $a =~ [[:alpha:]] ]]; then + # converts only one comma: s/("[^"]+),([^"]+")/\1`\2/g;s/"//g + #a=$(echo $a | sed 's/\([[:alpha:]]*\)/"\1"/g') + a=$(echo $a | sed -r "s/[\"']//g;s/([^,]*)/\"\1\"/g") + fi + query+="$comma(${a//,/|})" + elif [[ ${PATHTOKENS[i]} =~ : ]]; then + if ! [[ ${PATHTOKENS[i]} =~ [0-9][0-9] || ${PATHTOKENS[i]} =~ :] ]] + then + if [[ ${PATHTOKENS[i]#*:} =~ : ]]; then + INDEXMATCH_QUERY+=("${PATHTOKENS[i]}") + query+="$comma[^,]*" + else + # Index in the range of 0-9 can be handled by regex + query+="${comma}$(echo ${PATHTOKENS[i]} | \ + awk '/:/ { a=substr($0,0,index($0,":")-1); + b=substr($0,index($0,":")+1,index($0,"]")-index($0,":")-1); + if(b>0) { print a ":" b-1 "]" }; + if(b<=0) { print a ":]" } }' | \ + sed 's/\([0-9]\):\([0-9]\)/\1-\2/; + s/\[:\([0-9]\)/[0-\1/; + s/\([0-9]\):\]/\1-9999999]/')" + fi + else + INDEXMATCH_QUERY+=("${PATHTOKENS[i]}") + query+="$comma[^,]*" + fi + else + a=${PATHTOKENS[i]#[} + a=${a%]} + if [[ $a =~ [[:alpha:]] ]]; then + a=$(echo $a | sed -r "s/[\"']//g;s/([^,]*)/\"\1\"/g") + else + [[ $i -gt 0 ]] && comma="," + fi + #idx=$(echo "${PATHTOKENS[i]}" | tr -d "[]") + query+="$comma$a" + fi + comma="," + ;; + *) PATHTOKENS[i]=${PATHTOKENS[i]//\'/\"} + query+="$comma\"${PATHTOKENS[i]//\"/}\"" + comma="," + ;; + esac + i=i+1 + done + + [[ -z $FILTER ]] && FILTER="$query[],]" + [[ $DEBUG -eq 1 ]] && echo "FILTER=$FILTER" +} + +# --------------------------------------------------------------------------- +parse_array () { +# --------------------------------------------------------------------------- +# json parsing + + local index=0 + local ary='' + read -r token + case "$token" in + ']') + ;; + *) + while : + do + parse_value "$1" "$index" + index=$((index+1)) + ary="$ary""$value" + read -r token + case "$token" in + ']') break ;; + ',') ary="$ary," ;; + *) throw "EXPECTED , or ] GOT ${token:-EOF}" ;; + esac + read -r token + done + ;; + esac + value= + : +} + +# --------------------------------------------------------------------------- +parse_object () { +# --------------------------------------------------------------------------- +# json parsing + + local key + local obj='' + read -r token + case "$token" in + '}') + ;; + *) + while : + do + case "$token" in + '"'*'"') key=$token ;; + *) throw "EXPECTED string GOT ${token:-EOF}" ;; + esac + read -r token + case "$token" in + ':') ;; + *) throw "EXPECTED : GOT ${token:-EOF}" ;; + esac + read -r token + parse_value "$1" "$key" + obj="$obj$key:$value" + read -r token + case "$token" in + '}') break ;; + ',') obj="$obj," ;; + *) throw "EXPECTED , or } GOT ${token:-EOF}" ;; + esac + read -r token + done + ;; + esac + value= + : +} + +# --------------------------------------------------------------------------- +parse_value () { +# --------------------------------------------------------------------------- +# json parsing + + local jpath="${1:+$1,}$2" isleaf=0 isempty=0 print=0 + case "$token" in + '{') parse_object "$jpath" ;; + '[') parse_array "$jpath" ;; + # At this point, the only valid single-character tokens are digits. + ''|[!0-9]) throw "EXPECTED value GOT ${token:-EOF}" ;; + *) value=$token + # if asked, replace solidus ("\/") in json strings with normalized value: "/" + [ "$NORMALIZE_SOLIDUS" -eq 1 ] && value=$(echo "$value" | sed 's#\\/#/#g') + isleaf=1 + [ "$value" = '""' ] && isempty=1 + ;; + esac + [[ -z INCLEMPTY ]] && [ "$value" = '' ] && return + [ "$NO_HEAD" -eq 1 ] && [ -z "$jpath" ] && return + + [ "$isleaf" -eq 1 ] && [ $isempty -eq 0 ] && print=1 + [ "$print" -eq 1 ] && printf "[%s]\t%s\n" "$jpath" "$value" + : +} + +# --------------------------------------------------------------------------- +flatten() { +# --------------------------------------------------------------------------- +# Take out + + local path a prevpath pathlen + + if [[ $FLATTEN -eq 1 ]]; then + cat >"$STDINFILE2" + + highest=9999 + + while read line; do + a=${line#[};a=${a%%]*} + readarray -t path < <(grep -o "[^,]*"<<<"$a") + [[ -z $prevpath ]] && { + prevpath=("${path[@]}") + highest=$((${#path[*]}-1)) + continue + } + + pathlen=$((${#path[*]}-1)) + + for i in `seq 0 $pathlen`; do + [[ ${path[i]} != ${prevpath[i]} ]] && { + high=$i + break + } + done + + [[ $high -lt $highest ]] && highest=$high + + prevpath=("${path[@]}") + done <"$STDINFILE2" + + if [[ $highest -gt 0 ]]; then + sed -r 's/\[(([0-9]+|"[^"]+")[],]){'$((highest))'}(.*)/[\3/' \ + "$STDINFILE2" + else + cat "$STDINFILE2" + fi + else + cat + fi +} + +# --------------------------------------------------------------------------- +indexmatcher() { +# --------------------------------------------------------------------------- +# For double digit or greater indexes match each line individually +# Single digit indexes are handled more efficiently by regex + + local a b + + [[ $DEBUG -eq 1 ]] && { + for i in `seq 0 $((${#INDEXMATCH_QUERY[*]}-1))`; do + echo "INDEXMATCH_QUERY[$i]=${INDEXMATCH_QUERY[i]}" + done + } + + matched=1 + + step= + if [[ ${#INDEXMATCH_QUERY[*]} -gt 0 ]]; then + while read -r line; do + for i in `seq 0 $((${#INDEXMATCH_QUERY[*]}-1))`; do + [[ ${INDEXMATCH_QUERY[i]#*:} =~ : ]] && { + step=${INDEXMATCH_QUERY[i]##*:} + step=${step%]} + INDEXMATCH_QUERY[i]="${INDEXMATCH_QUERY[i]%:*}]" + } + q=${INDEXMATCH_QUERY[i]:1:-1} # <- strip '[' and ']' + a=${q%:*} # <- number before ':' + b=${q#*:} # <- number after ':' + [[ -z $b ]] && b=99999999999 + readarray -t num < <( (grep -Eo ',[0-9]+[],]' | tr -d ,])<<<$line ) + if [[ ${num[i]} -ge $a && ${num[i]} -lt $b && matched -eq 1 ]]; then + matched=1 + [[ $i -eq $((${#INDEXMATCH_QUERY[*]}-1)) ]] && { + if [[ $step -gt 1 ]]; then + [[ $(((num[i]-a)%step)) -eq 0 ]] && { + [[ $DEBUG -eq 1 ]] && echo -n "($a,$b,${num[i]}) " + echo "$line" + } + else + [[ $DEBUG -eq 1 ]] && echo -n "($a,$b,${num[i]}) " + echo "$line" + fi + } + else + matched=0 + continue + fi + done + matched=1 + done + else + cat - + fi +} + +# --------------------------------------------------------------------------- +brief() { +# --------------------------------------------------------------------------- +# Only show the value + + if [[ $BRIEF -eq 1 ]]; then + sed 's/^[^\t]*\t//;s/^"//;s/"$//;' + else + cat + fi +} + +# --------------------------------------------------------------------------- +json() { +# --------------------------------------------------------------------------- +# Turn output into JSON + + local a tab=$(echo -e "\t") + local UP=1 DOWN=2 SAME=3 + local prevpathlen=-1 prevpath=() path a + declare -a closers + + if [[ $JSON -eq 0 ]]; then + cat - + else + while read -r line; do + a=${line#[};a=${a%%]*} + readarray -t path < <(grep -o "[^,]*"<<<"$a") + value=${line#*$tab} + + # Not including the object itself (last item) + pathlen=$((${#path[*]}-1)) + + # General direction + + direction=$SAME + [[ $pathlen -gt $prevpathlen ]] && direction=$DOWN + [[ $pathlen -lt $prevpathlen ]] && direction=$UP + + # Handle jumps UP the tree (close previous paths) + + [[ $prevpathlen != -1 ]] && { + for i in `seq 0 $((pathlen-1))`; do + [[ ${prevpath[i]} == ${path[i]} ]] && continue + [[ ${path[i]} != '"'* ]] && { + a=(${!arrays[*]}) + [[ -n $a ]] && { + for k in `seq $((i+1)) ${a[-1]}`; do + arrays[k]= + done + } + a=(${!comma[*]}) + [[ -n $a ]] && { + for k in `seq $((i+1)) ${a[-1]}`; do + comma[k]= + done + } + for j in `seq $((prevpathlen)) -1 $((i+2))` + do + arrays[j]= + [[ -n ${closers[j]} ]] && { + let indent=j*4 + printf "\n%0${indent}s${closers[j]}" "" + unset closers[j] + comma[j]= + } + done + direction=$DOWN + break + } + direction=$DOWN + for j in `seq $((prevpathlen)) -1 $((i+1))` + do + arrays[j]= + [[ -n ${closers[j]} ]] && { + let indent=j*4 + printf "\n%0${indent}s${closers[j]}" "" + unset closers[j] + comma[j]= + } + done + a=(${!arrays[*]}) + [[ -n $a ]] && { + for k in `seq $i ${a[-1]}`; do + arrays[k]= + done + } + break + done + } + + [[ $direction -eq $UP ]] && { + [[ $prevpathlen != -1 ]] && comma[prevpathlen]= + for i in `seq $((prevpathlen+1)) -1 $((pathlen+1))` + do + arrays[i]= + [[ -n ${closers[i]} ]] && { + let indent=i*4 + printf "\n%0${indent}s${closers[i]}" "" + unset closers[i] + comma[i]= + } + done + a=(${!arrays[*]}) + [[ -n $a ]] && { + for k in `seq $i ${a[-1]}`; do + arrays[k]= + done + } + } + + # Opening braces (the path leading up to the key) + + broken= + for i in `seq 0 $((pathlen-1))`; do + [[ -z $broken && ${prevpath[i]} == ${path[i]} ]] && continue + [[ -z $broken ]] && { + broken=$i + [[ $prevpathlen -ne -1 ]] && broken=$((i+1)) + } + if [[ ${path[i]} == '"'* ]]; then + # Object + [[ $i -ge $broken ]] && { + let indent=i*4 + printf "${comma[i]}%0${indent}s{\n" "" + closers[i]='}' + comma[i]= + } + let indent=(i+1)*4 + printf "${comma[i]}%0${indent}s${path[i]}:\n" "" + comma[i]=",\n" + else + # Array + if [[ ${arrays[i]} != 1 ]]; then + let indent=i*4 + printf "%0${indent}s" "" + echo "[" + closers[i]=']' + arrays[i]=1 + comma[i]= + else + let indent=(i+1)*4 + printf "\n%0${indent}s${closers[i-1]}" "" + direction=$DOWN + comma[i+1]=",\n" + fi + fi + done + + # keys & values + + if [[ ${path[-1]} == '"'* ]]; then + # Object + [[ $direction -eq $DOWN ]] && { + let indent=pathlen*4 + printf "${comma[pathlen]}%0${indent}s{\n" "" + closers[pathlen]='}' + comma[pathlen]= + } + let indent=(pathlen+1)*4 + printf "${comma[pathlen]}%0${indent}s" "" + echo -n "${path[-1]}:$value" + comma[pathlen]=",\n" + else + # Array + [[ ${arrays[i]} != 1 ]] && { + let indent=(pathlen-0)*4 + printf "%0${indent}s[\n" "" + closers[pathlen]=']' + comma[pathlen]= + arrays[i]=1 + } + let indent=(pathlen+1)*4 + printf "${comma[pathlen]}%0${indent}s" "" + echo -n "$value" + comma[pathlen]=",\n" + fi + + prevpath=("${path[@]}") + prevpathlen=$pathlen + done + + # closing braces + + for i in `seq $((pathlen)) -1 0` + do + let indent=i*4 + printf "\n%0${indent}s${closers[i]}" "" + done + echo + fi +} + +# --------------------------------------------------------------------------- +filter() { +# --------------------------------------------------------------------------- +# Apply the query filter + + local a tab=$(echo -e "\t") v + + [[ $NOCASE -eq 1 ]] && opts+="-i" + [[ $WHOLEWORD -eq 1 ]] && opts+=" -w" + if [[ -z $OPERATOR ]]; then + egrep $opts "$FILTER" + else + egrep $opts "$FILTER" | \ + while read line; do + v=${line#*$tab} + case $OPERATOR in + '-ge') if awk '{exit !($1>=$2)}'<<<"$v $RHS";then echo "$line"; fi + ;; + '-gt') if awk '{exit !($1>$2) }'<<<"$v $RHS";then echo "$line"; fi + ;; + '-le') if awk '{exit !($1<=$2) }'<<<"$v $RHS";then echo "$line"; fi + ;; + '-lt') if awk '{exit !($1<$2) }'<<<"$v $RHS";then echo "$line"; fi + ;; + '>') v=${v#\"};v=${v%\"} + RHS=${RHS#\"};RHS=${RHS%\"} + [[ "$v" > "$RHS" ]] && echo "$line" + ;; + '<') v=${v#\"};v=${v%\"} + RHS=${RHS#\"};RHS=${RHS%\"} + [[ "$v" < "$RHS" ]] && echo "$line" + ;; + esac + done #< <(egrep $opts "$FILTER") + fi +} + +# --------------------------------------------------------------------------- +parse () { +# --------------------------------------------------------------------------- +# Parses json + + read -r token + parse_value + read -r token + case "$token" in + '') ;; + *) throw "EXPECTED EOF GOT $token" + exit 1;; + esac +} + +# --------------------------------------------------------------------------- +throw() { +# --------------------------------------------------------------------------- + echo "$*" >&2 + exit 1 +} + +if ([ "$0" = "$BASH_SOURCE" ] || ! [ -n "$BASH_SOURCE" ]); +then + main "$@" +fi + +# vi: expandtab sw=2 ts=2 \ No newline at end of file diff --git a/deps/jsonpath/LICENSE.APACHE2 b/deps/jsonpath/LICENSE.APACHE2 new file mode 100644 index 0000000000..6366c04716 --- /dev/null +++ b/deps/jsonpath/LICENSE.APACHE2 @@ -0,0 +1,15 @@ +Apache License, Version 2.0 + +Copyright (c) 2011 Dominic Tarr + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/deps/jsonpath/LICENSE.MIT b/deps/jsonpath/LICENSE.MIT new file mode 100644 index 0000000000..6eafbd734a --- /dev/null +++ b/deps/jsonpath/LICENSE.MIT @@ -0,0 +1,24 @@ +The MIT License + +Copyright (c) 2011 Dominic Tarr + +Permission is hereby granted, free of charge, +to any person obtaining a copy of this software and +associated documentation files (the "Software"), to +deal in the Software without restriction, including +without limitation the rights to use, copy, modify, +merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom +the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR +ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/deps/jsonpath/MANIFEST.in b/deps/jsonpath/MANIFEST.in new file mode 100644 index 0000000000..b98f63d048 --- /dev/null +++ b/deps/jsonpath/MANIFEST.in @@ -0,0 +1,3 @@ +include README.md +include LICENSE.MIT +include LICENSE.APACHE2 \ No newline at end of file diff --git a/deps/jsonpath/README.md b/deps/jsonpath/README.md new file mode 100644 index 0000000000..5b770bc5d1 --- /dev/null +++ b/deps/jsonpath/README.md @@ -0,0 +1,491 @@ +# JSONPath.sh + +yo, so it's a JSONPath implementation written in Bash - and it probably only works in Bash. + +[![travis](https://secure.travis-ci.org/mclarkson/JSONPath.sh.png?branch=master)](https://travis-ci.org/mclarkson/JSONPath.sh) + +## Invocation + + JSONPath.sh [-b] [-i] [-j] [-h] [-p] [-u] [-f FILE] [pattern] + +pattern +> the JSONPath query. Defaults to '$.\*' if not supplied. + +-b +> Brief output. Only show the values, not the path and key. + +-f FILE +> Read a FILE instead of reading from standard input. + +-i +> Case insensitive searching. + +-j +> Output in JSON format, instead of JSON.sh format. + +-u +> Strip unnecessary leading path elements. + +-p +> Pass JSON.sh formatted data through to the JSON parser only. Useful after +> JSON.sh data has been manipulated. + +-h +> Show help text. + +## Requirements + +JSONPath.sh is a Bash script that uses the standard GNU tools: *bash*, *cat*, *sed*, *awk*, *grep*, and *seq*. + +## Installation + +Install with pip: + +* `sudo pip install git+https://github.com/mclarkson/JSONPath.sh#egg=JSONPath.sh` + +Install with npm: + +* `sudo npm install -g jsonpath.sh` + +Or copy the `JSONPath.sh` script to your PATH, for example: + +``` bash +curl -O https://raw.githubusercontent.com/mclarkson/JSONPath.sh/master/JSONPath.sh +chmod +x JSONPath.sh +mv JSONPath.sh ~/bin +``` + +## Examples + +``` bash +$ ./JSONPath.sh < package.json +["name"] "JSONPath.sh" +["version"] "0.0.0" +["description"] "JSONPath implementation written in Bash" +["homepage"] "http://github.com/mclarkson/JSONPath.sh" +["repository","type"] "git" +["repository","url"] "https://github.com/mclarkson/JSONPath.sh.git" +["bin","JSONPath.sh"] "./JSONPath.sh" +["author"] "Mark Clarkson " +["scripts","test"] "./all-tests.sh" +``` + +more complex examples: + +*NPMJS.ORG EXAMPLES* + +``` bash +# Number of downloads yesterday +curl -s https://api.npmjs.org/downloads/point/last-day/jsonpath.sh | \ + JSONPath.sh '$.downloads' -b + +# Show all versions +curl registry.npmjs.org/express | ./JSONPath.sh '$.versions.*.version' + +# Show version 2.2.0 +./JSONPath.sh \ + -f test/valid/npmjs.org.json \ + '$.versions.["2.2.0"]' + +# Find versions 2.2.x (using a regular expression) +# and show version and contributors +./JSONPath.sh \ + -f test/valid/npmjs.org.json \ + '$..["2.2.*"].[version,contributors]' +``` +*JSONPATH.ORG EXAMPLES* + +``` bash +# The default query +./JSONPath.sh \ + -f test/valid/jsonpath.com.json \ + '$.phoneNumbers[:1].type' + +# The same, but using a filter (script) expression +# (This takes 2 passes through the data) +./JSONPath.sh \ + -f test/valid/jsonpath.com.json \ + '$.phoneNumbers[?(@.type=iPhone)]' +``` + +*KUBERNETES EXAMPLES* + +``` bash +# Show the NodePort of a service named bob +# from a list of all services +kubectl get svc -o json | JSONPath.sh \ + '$..items[?(@.metadata.name==bob)].spec.ports[0].nodePort' -b + +# Or, more simply, show the NodePort of the service +kubectl get svc bob -o json | JSONPath.sh '$..nodePort' -b + +# Get the port of the kubernetes-dashboard and output as json: +kubectl get svc --all-namespaces -o json | JSONPath.sh -j -u \ + '$.items[?(@.spec.selector.app=".*dashboard")]..ports[*].nodePort' +``` + +*DOCKER EXAMPLES* + +``` bash +# Show Everything +./JSONPath.sh -f test/valid/docker_stopped.json '$.*' + +# Look for an ip address (using case insensitive searching to start) +./JSONPath.sh \ + -f test/valid/docker_running.json \ + /valid/docker_running.json -i '$..".*ip.*"' + +# Now get the IP address exactly +./JSONPath.sh \ + -f test/valid/docker_running.json \ + '$.*.NetworkSettings.IPAddress' -b + +# Show all Mounts +./JSONPath.sh \ + -f test/valid/docker_stopped.json \ + '$.[*].Mounts' + +# Show sources and destinations for all mounts +./JSONPath.sh \ + -f test/valid/docker_stopped.json \ + '$.[*].Mounts[*].[Source,Destination]' + +# Use brief (-b) output to store mounts in an array for use in a loop +readarray -t MNTS \ + < <(./JSONPath.sh -b -f test/valid/docker_stopped.json '$.*.Mounts[*].[Source,Destination]') + +# the loop: +for idx in `seq 0 $((${#MNTS[*]}/2-1))`; do + echo "'${MNTS[idx*2]}' is mounted on the host at '${MNTS[idx*2+1]}'" +done +``` + +*GOESSNER.NET (EXPANDED) EXAMPLES* + +``` bash +# dot-notation (my latest favourite book) +./JSONPath.sh \ + -f test/valid/goessner.net.expanded.json \ + '$.store.book[16].title' + +# dot-notation with a node set +./JSONPath.sh \ + -f test/valid/goessner.net.expanded.json \ + '$.store.book[4,6,16,22].title' + +# bracket-notation ('$[' needs escaping at the +# command line, so bash doesn't think it's an +# arithmetic expression) +./JSONPath.sh \ + -f test/valid/goessner.net.expanded.json \ + "\$['store']['book'][16]['title']" + +# bracket-notation with an array slice and a set +./JSONPath.sh \ + -f test/valid/goessner.net.expanded.json \ + "\$['store']['book'][14:25:2]['title','reviews']" + +# Mixed bracket- and dot- notation +./JSONPath.sh \ + -f test/valid/goessner.net.expanded.json \ + "\$['store'].book[16].title" + +# Show all titles +./JSONPath.sh \ + -f test/valid/goessner.net.expanded.json \ + '$..book[*].title' + +# All books with 'Book 1' somewhere in the title +./JSONPath.sh \ + -f test/valid/goessner.net.expanded.json \ + -i '$..book[?(@.title==".*Book 1.*")].title' + +# All books with a price less than or equal to 4.20 +# Show both the title and the price and output in +# JSON format but without redundant path elements. +./JSONPath.sh -j -u \ + -f test/valid/goessner.net.expanded.json \ + '$.store.book[?(@.price<4.20)].[title,price]' + +# The following does not work yet (TODO) +./JSONPath.sh \ + -f test/valid/goessner.net.expanded.json \ + '$.store.book[(@.length-1)].title' +``` + +## JSONPath patterns and extensions + +### Supported JSONPath options + +| JSONPath | Supported | Comment | +| -----------------------|-----------|---------------------------------------------------------| +| $ | Y | the root object/element (optional) | +| @ | Y | the current object/element | +| . or [] | Y | child operator. | +| .. | Y | recusive descent. | +| * | Y | wildcard. All objects/elements regardless their names. | +| [] | Y | subscript operator. | +| [,] | Y | node sets. | +| ```[start:end:step]``` | Y | array slice operator. | +| ?() | Y | applies a filter (script) expressions | +| () | Y | script expression, using the underlying script engine. | + +### Searching for things + +"regex" + +Use a regular expression inside the JSONPath pattern.
+Combine with '-i' for case insensitive search.
+Combine with '-w' to match whole words only. + +Examples: + +Find every node key starting with 'ip': + +``` bash +# These are all equivalent +./JSONPath.sh -f test/valid/docker_running.json -i "$..['ip.*']" +./JSONPath.sh -f test/valid/docker_running.json -i '$..["ip.*"]' +./JSONPath.sh -f test/valid/docker_running.json -i '$.."ip.*"' +./JSONPath.sh -f test/valid/docker_running.json -i "$..'ip.*'" +``` + +Restrict the previous search to the bridge object. + +``` bash +./JSONPath.sh -f test/valid/docker_running.json -i "$..bridge.'ip.*'" +``` + +Show all book titles by authors starting with 'Doug'. + +``` bash +# Show the title +./JSONPath.sh -f test/valid/goessner.net.expanded.json -i \ + "$..book[?(@.author==Doug)].title" + +# Show the author, title and rating (can be with or without double quotes) +./JSONPath.sh -f test/valid/goessner.net.expanded.json -i \ + '$..book[?(@.author="Doug")].["author","title",rating]' +``` + +### Modification + +A common task is to modify JSON data on-the-fly. Unix style 'one-liners' can be +created to easily and logically modify JSON data. + +The key to data modification (that is: add, modify or deletion of data) is to +modify the *JSON.sh* formatted data, then use the passthrough, '-p', option to +output again as JSON. Sequence is: + +1. Read JSON data and output as *JSON.sh* data. +2. Modify *JSON.sh* data using standard Unix tools. +3. Pipe modified *JSON.sh* data to JSONPath.sh with passthrough option producing + JSON data again. + +For example: The following 'one-liner' will read a kubernetes deployment +configuration (using 'kubectl get ...'), output it in *JSON.sh* format (using +'JSONPath.sh'), change the number of replicas from the existing value to 5 +(using *sed*), output again in JSON (using 'JSONPath.sh -p'), then replace the +original deployment with the newly changed one (using 'kubectl replace ...'). + +``` +kubectl get deployment sample-deployment -o json | \ +JSONPath.sh | \ +sed 's/\["spec","replicas"\].*/["spec","replicas"]\t5/' | \ +JSONPath.sh -p | \ +kubectl replace deployment sample-deployment -f - +``` + +This allows you to reuse your Unix skills rather than learn new terse syntax +or Domain Specific Language. + +### Re-injection + +This tool, JSONPath.sh, is really handy for handing json formatted +data to other tools, and using pass-through mode (-p) comes in quite +handy for creating complex queries and outputting in json. + +**Re-injection** allows the user to overcome the limitation +of a single filter expression per invocation. To do this the first +query, or set of queries, should output in JSON format using the +'-j' option. + +**Usage Example** + +Show all books with a price greater than 4 that also have a 5 star +rating (note that the first process in the pipeline outputs in json): + +``` +./JSONPath.sh -j -f test/valid/goessner.net.expanded.json \ + '$..book[?(@.price>4)]' | ./JSONPath.sh \ + '$..book[?(@.rating==5)].title' +``` + +**Pass-through mode** reads the standard output JSONPath.sh (or JSON.sh) +produces and outputs JSON. This gives the user an opportunity to filter +or modify the results: + +**Filtering Usage Example** + +Show all authors, without showing duplicates and output in JSON format. + +All authors with duplicates: + +``` +$ ./JSONPath.sh -f test/valid/goessner.net.expanded.json '$..author' +... omitted ... +["store","book",9,"author"] "James S. A. Corey" +["store","book",10,"author"] "James S. A. Corey" +["store","book",11,"author"] "James S. A. Corey" +... 25 lines of output ... +``` + +Use standard unix tools to remove duplicates: + +``` +$ ./JSONPath.sh -f test/valid/goessner.net.expanded.json '$..author' \ + | sort -k2 | uniq -f 1 +... 11 lines of output ... +``` + +And pipe (re-inject - 'cos it sounds cool) the output into JSONPath.sh: + +``` +$ ./JSONPath.sh -f test/valid/goessner.net.expanded.json '$..author' \ + | sort -k2 | uniq -f 1 \ + | ./JSONPath.sh -p +{ + "store": + { + "book": + [ + { + "author":"Douglas E. Richards" + } + ,{ + "author":"Evelyn Waugh" + } +... JSON output with unique data ... +``` + +Use the '-u' option to flatten the output: + +``` +$ ./JSONPath.sh -f test/valid/goessner.net.expanded.json \ + '$..author' \ + | sort -k2 | uniq -f 1 \ + | ./JSONPath.sh -p -u +... JSON flattened output ... +{ + "book": + [ + { + "author":"Douglas E. Richards" + }, + { + "author":"Evelyn Waugh" + }, +``` + +**Filter and Merge Usage Example** + +Different parts of JSON input, or entirely different JSON input, can be merged +together with Unix 'sort' and output in json format. + +This is a complex kubernetes example that uses JSONPath.sh and standard Unix +tools to output just the command, pod mounts, and container mounts (output from +different parts of the tree) for the first matched kube-proxy pod. + +``` +# Get details of all pods +kubectl get -n kube-system pods -o json >/tmp/kpod + +# Get the index of the first pod with name starting 'kube-proxy' +idx=`JSONPath.sh -f /tmp/kpod '$.items[?(@.metadata.name=="kube-proxy.*")].apiVersion' \ + | head -n1 | grep -o ',[0-9]\+,' | tr -d ,` + +# Get three subtrees using the index and merge them using sort +# and then output in json format +( JSONPath.sh -f /tmp/kpod '$.items['$idx'].spec.volumes'; \ + JSONPath.sh -f /tmp/kpod '$.items['$idx']..volumeMounts'; \ + JSONPath.sh -f /tmp/kpod '$.items['$idx']..containers[*].command' +) | sort | JSONPath.sh -p -u +``` + +, which produces: + +``` +{ + "containers": + [ + { + "command": + [ + "/usr/local/bin/kube-proxy", + "--kubeconfig=/var/lib/kube-proxy/kubeconfig.conf" + ], + "volumeMounts": + [ + { + "mountPath":"/var/lib/kube-proxy", + "name":"kube-proxy" + }, + { + "mountPath":"/var/run/secrets/kubernetes.io/serviceaccount", + "name":"kube-proxy-token-m9b6j", + "readOnly":true + } + ] + } + ], + "volumes": + [ + { + "configMap": + { + "defaultMode":420, + "name":"kube-proxy" + }, + "name":"kube-proxy" + }, + { + "name":"kube-proxy-token-m9b6j", + "secret": + { + "defaultMode":420, + "secretName":"kube-proxy-token-m9b6j" + } + } + ] +} +``` + +## Cool Links + +* [dominictarr/JSON.sh](https://github.com/dominictarr/JSON.sh) The original, the best, JSON.sh. + +## Performance + +* Performance is acceptable for small data sizes +* Worse when using: + * large data files (hundreds of kilobytes). + * filter (script) expressions (An extra pass is required). + * Indexes greater than 9. + * Indexes with steps even with indexes less than 10. +* Better with: + * Small data files (A few kilobytes). + * Indexes less than 10 (then matching is done by regex, unless a step is used). + * No filter (script) expressions (so no extra pass through the data). + +## Limitations (todo) + +* Only one filter expression, '?(@', per query. + Use re-injection, detailed above, to overcome this limitation. + +## License + +This software is available under the following licenses: + + * MIT + * Apache 2 + diff --git a/deps/jsonpath/_config.yml b/deps/jsonpath/_config.yml new file mode 100644 index 0000000000..c741881743 --- /dev/null +++ b/deps/jsonpath/_config.yml @@ -0,0 +1 @@ +theme: jekyll-theme-slate \ No newline at end of file diff --git a/deps/jsonpath/all-tests.sh b/deps/jsonpath/all-tests.sh new file mode 100644 index 0000000000..84f826f75d --- /dev/null +++ b/deps/jsonpath/all-tests.sh @@ -0,0 +1,33 @@ +#!/bin/sh + +cd ${0%/*} + +#set -e +fail=0 +tests=0 +#all_tests=${__dirname:} +#echo PLAN ${#all_tests} +for test in test/*.sh ; +do + tests=$((tests+1)) + echo TEST: $test + ./$test + ret=$? + if [ $ret -eq 0 ] ; then + echo OK: ---- $test + passed=$((passed+1)) + else + echo FAIL: $test $fail + fail=$((fail+ret)) + fi +done + +if [ $fail -eq 0 ]; then + echo -n 'SUCCESS ' + exitcode=0 +else + echo -n 'FAILURE ' + exitcode=1 +fi +echo $passed / $tests +exit $exitcode diff --git a/deps/jsonpath/package.json b/deps/jsonpath/package.json new file mode 100644 index 0000000000..458b822a53 --- /dev/null +++ b/deps/jsonpath/package.json @@ -0,0 +1,19 @@ +{ + "name": "jsonpath.sh", + "version": "0.0.14", + "description": "JSONPath implementation written in Bash", + "homepage": "http://github.com/mclarkson/JSONPath.sh", + "repository": { + "type": "git", + "url": "https://github.com/mclarkson/JSONPath.sh.git" + }, + "bin": { + "JSONPath.sh": "./JSONPath.sh" + }, + "dependencies": {}, + "devDependencies": {}, + "author": "Mark Clarkson ", + "scripts": { + "test": "./all-tests.sh" + } +} diff --git a/deps/jsonpath/setup.py b/deps/jsonpath/setup.py new file mode 100644 index 0000000000..df9863f921 --- /dev/null +++ b/deps/jsonpath/setup.py @@ -0,0 +1,31 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +from setuptools import setup +import os + +# Allow setup.py to be run from any path +os.chdir(os.path.normpath(os.path.join(os.path.abspath(__file__), os.pardir))) + +setup( + name='JSONPath.sh', + scripts=[ + 'JSONPath.sh', + ], + version='0.0.14', + description="JSONPath implementation written in Bash", + long_description="", + author='Mark Clarkson', + author_email='mark.clarkson@smorg.co.uk', + url='https://github.com/mclarkson/JSONPath.sh', + classifiers=[ + "Programming Language :: Unix Shell", + "License :: OSI Approved :: MIT License", + "License :: OSI Approved :: Apache Software License", + "Intended Audience :: System Administrators", + "Intended Audience :: Developers", + "Operating System :: POSIX :: Linux", + "Topic :: Utilities", + "Topic :: Software Development :: Libraries", + ], +) diff --git a/deps/semver_bash/.gitignore b/deps/semver_bash/.gitignore new file mode 100644 index 0000000000..5cb19d201a --- /dev/null +++ b/deps/semver_bash/.gitignore @@ -0,0 +1,4 @@ +*~ +*tmp +*swp + diff --git a/deps/semver_bash/LICENSE b/deps/semver_bash/LICENSE new file mode 100644 index 0000000000..04ac66f8f6 --- /dev/null +++ b/deps/semver_bash/LICENSE @@ -0,0 +1,26 @@ +Copyright (c) 2013, Ray Bejjani +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +The views and conclusions contained in the software and documentation are those +of the authors and should not be interpreted as representing official policies, +either expressed or implied, of the FreeBSD Project. diff --git a/deps/semver_bash/README.md b/deps/semver_bash/README.md new file mode 100644 index 0000000000..180c368964 --- /dev/null +++ b/deps/semver_bash/README.md @@ -0,0 +1,31 @@ +semver_bash is a bash parser for semantic versioning +==================================================== + +[Semantic Versioning](http://semver.org/) is a set of guidelines that help keep +version and version management sane. This is a bash based parser to help manage +a project's versions. Use it from a Makefile or any scripts you use in your +project. + +Usage +----- +semver_bash can be used from the command line as: + + $ ./semver.sh "3.2.1" "3.2.1-alpha" + 3.2.1 -> M: 3 m:2 p:1 s: + 3.2.1-alpha -> M: 3 m:2 p:1 s:-alpha + 3.2.1 == 3.2.1-alpha -> 1. + 3.2.1 < 3.2.1-alpha -> 1. + 3.2.1 > 3.2.1-alpha -> 0. + + +Alternatively, you can source it from within a script: + + . ./semver.sh + + local MAJOR=0 + local MINOR=0 + local PATCH=0 + local SPECIAL="" + + semverParseInto "1.2.3" MAJOR MINOR PATCH SPECIAL + semverParseInto "3.2.1" MAJOR MINOR PATCH SPECIAL diff --git a/deps/semver_bash/semver.sh b/deps/semver_bash/semver.sh new file mode 100644 index 0000000000..e5237a4e2e --- /dev/null +++ b/deps/semver_bash/semver.sh @@ -0,0 +1,130 @@ +#!/usr/bin/env sh + +function semverParseInto() { + local RE='[^0-9]*\([0-9]*\)[.]\([0-9]*\)[.]\([0-9]*\)\([0-9A-Za-z-]*\)' + #MAJOR + eval $2=`echo $1 | sed -e "s#$RE#\1#"` + #MINOR + eval $3=`echo $1 | sed -e "s#$RE#\2#"` + #MINOR + eval $4=`echo $1 | sed -e "s#$RE#\3#"` + #SPECIAL + eval $5=`echo $1 | sed -e "s#$RE#\4#"` +} + +function semverEQ() { + local MAJOR_A=0 + local MINOR_A=0 + local PATCH_A=0 + local SPECIAL_A=0 + + local MAJOR_B=0 + local MINOR_B=0 + local PATCH_B=0 + local SPECIAL_B=0 + + semverParseInto $1 MAJOR_A MINOR_A PATCH_A SPECIAL_A + semverParseInto $2 MAJOR_B MINOR_B PATCH_B SPECIAL_B + + if [ $MAJOR_A -ne $MAJOR_B ]; then + return 1 + fi + + if [ $MINOR_A -ne $MINOR_B ]; then + return 1 + fi + + if [ $PATCH_A -ne $PATCH_B ]; then + return 1 + fi + + if [[ "_$SPECIAL_A" != "_$SPECIAL_B" ]]; then + return 1 + fi + + + return 0 + +} + +function semverLT() { + local MAJOR_A=0 + local MINOR_A=0 + local PATCH_A=0 + local SPECIAL_A=0 + + local MAJOR_B=0 + local MINOR_B=0 + local PATCH_B=0 + local SPECIAL_B=0 + + semverParseInto $1 MAJOR_A MINOR_A PATCH_A SPECIAL_A + semverParseInto $2 MAJOR_B MINOR_B PATCH_B SPECIAL_B + + if [ $MAJOR_A -lt $MAJOR_B ]; then + return 0 + fi + + if [[ $MAJOR_A -le $MAJOR_B && $MINOR_A -lt $MINOR_B ]]; then + return 0 + fi + + if [[ $MAJOR_A -le $MAJOR_B && $MINOR_A -le $MINOR_B && $PATCH_A -lt $PATCH_B ]]; then + return 0 + fi + + if [[ "_$SPECIAL_A" == "_" ]] && [[ "_$SPECIAL_B" == "_" ]] ; then + return 1 + fi + if [[ "_$SPECIAL_A" == "_" ]] && [[ "_$SPECIAL_B" != "_" ]] ; then + return 1 + fi + if [[ "_$SPECIAL_A" != "_" ]] && [[ "_$SPECIAL_B" == "_" ]] ; then + return 0 + fi + + if [[ "_$SPECIAL_A" < "_$SPECIAL_B" ]]; then + return 0 + fi + + return 1 + +} + +function semverGT() { + semverEQ $1 $2 + local EQ=$? + + semverLT $1 $2 + local LT=$? + + if [ $EQ -ne 0 ] && [ $LT -ne 0 ]; then + return 0 + else + return 1 + fi +} + +if [ "___semver.sh" == "___`basename $0`" ]; then + +MAJOR=0 +MINOR=0 +PATCH=0 +SPECIAL="" + +semverParseInto $1 MAJOR MINOR PATCH SPECIAL +echo "$1 -> M: $MAJOR m:$MINOR p:$PATCH s:$SPECIAL" + +semverParseInto $2 MAJOR MINOR PATCH SPECIAL +echo "$2 -> M: $MAJOR m:$MINOR p:$PATCH s:$SPECIAL" + +semverEQ $1 $2 +echo "$1 == $2 -> $?." + +semverLT $1 $2 +echo "$1 < $2 -> $?." + +semverGT $1 $2 +echo "$1 > $2 -> $?." + +fi diff --git a/deps/semver_bash/semver_test.sh b/deps/semver_bash/semver_test.sh new file mode 100644 index 0000000000..a0ff99461e --- /dev/null +++ b/deps/semver_bash/semver_test.sh @@ -0,0 +1,151 @@ +#!/usr/bin/env bash + +. ./semver.sh + +semverTest() { +local A=R1.3.2 +local B=R2.3.2 +local C=R1.4.2 +local D=R1.3.3 +local E=R1.3.2a +local F=R1.3.2b +local G=R1.2.3 + +local MAJOR=0 +local MINOR=0 +local PATCH=0 +local SPECIAL="" + +semverParseInto $A MAJOR MINOR PATCH SPECIAL +echo "$A -> M:$MAJOR m:$MINOR p:$PATCH s:$SPECIAL. Expect M:1 m:3 p:2 s:" +semverParseInto $E MAJOR MINOR PATCH SPECIAL +echo "$E -> M:$MAJOR m:$MINOR p:$PATCH s:$SPECIAL. Expect M:1 m:3 p:2 s:a" + +echo "Equality comparisions" +semverEQ $A $A +echo "$A == $A -> $?. Expect 0." + +semverLT $A $A +echo "$A < $A -> $?. Expect 1." + +semverGT $A $A +echo "$A > $A -> $?. Expect 1." + + +echo "Major number comparisions" +semverEQ $A $B +echo "$A == $B -> $?. Expect 1." + +semverLT $A $B +echo "$A < $B -> $?. Expect 0." + +semverGT $A $B +echo "$A > $B -> $?. Expect 1." + +semverEQ $B $A +echo "$B == $A -> $?. Expect 1." + +semverLT $B $A +echo "$B < $A -> $?. Expect 1." + +semverGT $B $A +echo "$B > $A -> $?. Expect 0." + + +echo "Minor number comparisions" +semverEQ $A $C +echo "$A == $C -> $?. Expect 1." + +semverLT $A $C +echo "$A < $C -> $?. Expect 0." + +semverGT $A $C +echo "$A > $C -> $?. Expect 1." + +semverEQ $C $A +echo "$C == $A -> $?. Expect 1." + +semverLT $C $A +echo "$C < $A -> $?. Expect 1." + +semverGT $C $A +echo "$C > $A -> $?. Expect 0." + +echo "patch number comparisions" +semverEQ $A $D +echo "$A == $D -> $?. Expect 1." + +semverLT $A $D +echo "$A < $D -> $?. Expect 0." + +semverGT $A $D +echo "$A > $D -> $?. Expect 1." + +semverEQ $D $A +echo "$D == $A -> $?. Expect 1." + +semverLT $D $A +echo "$D < $A -> $?. Expect 1." + +semverGT $D $A +echo "$D > $A -> $?. Expect 0." + +echo "special section vs no special comparisions" +semverEQ $A $E +echo "$A == $E -> $?. Expect 1." + +semverLT $A $E +echo "$A < $E -> $?. Expect 1." + +semverGT $A $E +echo "$A > $E -> $?. Expect 0." + +semverEQ $E $A +echo "$E == $A -> $?. Expect 1." + +semverLT $E $A +echo "$E < $A -> $?. Expect 0." + +semverGT $E $A +echo "$E > $A -> $?. Expect 1." + +echo "special section vs special comparisions" +semverEQ $E $F +echo "$E == $F -> $?. Expect 1." + +semverLT $E $F +echo "$E < $F -> $?. Expect 0." + +semverGT $E $F +echo "$E > $F -> $?. Expect 1." + +semverEQ $F $E +echo "$F == $E -> $?. Expect 1." + +semverLT $F $E +echo "$F < $E -> $?. Expect 1." + +semverGT $F $E +echo "$F > $E -> $?. Expect 0." + +echo "Minor and patch number comparisons" +semverEQ $A $G +echo "$A == $G -> $?. Expect 1." + +semverLT $A $G +echo "$A < $G -> $?. Expect 1." + +semverGT $A $G +echo "$A > $G -> $?. Expect 0." + +semverEQ $G $A +echo "$G == $A -> $?. Expect 1." + +semverLT $G $A +echo "$G < $A -> $?. Expect 0." + +semverGT $G $A +echo "$G > $A -> $?. Expect 1." +} + +semverTest -- cgit v1.2.3