diff options
author | Yehonal <yehonal.azeroth@gmail.com> | 2018-07-15 22:40:49 +0200 |
---|---|---|
committer | Yehonal <yehonal.azeroth@gmail.com> | 2018-07-15 22:51:17 +0200 |
commit | 85388901cf6a69659569ad751767fd7108b25a3c (patch) | |
tree | a004b01dfd378841c2ee473023313ade212118d7 | |
parent | 07a451e1402cf8a7c24cf6196d541d304f5dcff2 (diff) |
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
38 files changed, 2178 insertions, 162 deletions
diff --git a/acore.json b/acore.json new file mode 100644 index 0000000000..fa828e3f65 --- /dev/null +++ b/acore.json @@ -0,0 +1,5 @@ +{ + "name" : "azerothcore-wotlk", + "version" : "2.0.0-dev", + "license" : "AGPL3" +}
\ No newline at end of file diff --git a/acore.sh b/acore.sh new file mode 100644 index 0000000000..ba247e009c --- /dev/null +++ b/acore.sh @@ -0,0 +1,7 @@ +#!/usr/bin/env bash + +set -e + +CUR_PATH="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" + +source "$CUR_PATH/apps/installer/main.sh" diff --git a/apps/bash_shared/common.sh b/apps/bash_shared/common.sh new file mode 100644 index 0000000000..7b42858057 --- /dev/null +++ b/apps/bash_shared/common.sh @@ -0,0 +1,23 @@ +function registerHooks() { hwc_event_register_hooks "$@"; } +function runHooks() { hwc_event_run_hooks "$@"; } + +source "$AC_PATH_CONF/config.sh.dist" # "hack" to avoid missing conf variables + +if [ -f "$AC_PATH_CONF/config.sh" ]; then + source "$AC_PATH_CONF/config.sh" # should overwrite previous +else + echo "NOTICE: file <$AC_PATH_CONF/config.sh> has not been found, you should create and configure it." +fi + +# +# Load modules +# + +for entry in "$AC_PATH_MODULES/"*/include.sh +do + if [ -e $entry ]; then + source $entry + fi +done + +ACORE_VERSION=$("$AC_PATH_DEPS/jsonpath/JSONPath.sh" -f $AC_PATH_ROOT/acore.json -b '$.version')
\ No newline at end of file diff --git a/apps/bash_shared/includes.sh b/apps/bash_shared/includes.sh index d90b4b451d..312b5ad19b 100644 --- a/apps/bash_shared/includes.sh +++ b/apps/bash_shared/includes.sh @@ -11,25 +11,5 @@ source "$AC_PATH_SHARED/defines.sh" source "$AC_PATH_DEPS/hw-core/bash-lib-event/src/hooks.sh" +source "$AC_PATH_SHARED/common.sh" -function registerHooks() { hwc_event_register_hooks "$@"; } -function runHooks() { hwc_event_run_hooks "$@"; } - -source "$AC_PATH_CONF/config.sh.dist" # "hack" to avoid missing conf variables - -if [ -f "$AC_PATH_CONF/config.sh" ]; then - source "$AC_PATH_CONF/config.sh" # should overwrite previous -else - echo "NOTICE: file <$AC_PATH_CONF/config.sh> has not been found, you should create and configure it." -fi - -# -# Load modules -# - -for entry in "$AC_PATH_MODULES/"*/include.sh -do - if [ -e $entry ]; then - source $entry - fi -done diff --git a/apps/compiler/1-clean.sh b/apps/compiler/1-clean.sh deleted file mode 100755 index 558c093e3f..0000000000 --- a/apps/compiler/1-clean.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/usr/bin/env bash - -CURRENT_PATH="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" - -bash "$CURRENT_PATH/compiler.sh" 1 diff --git a/apps/compiler/2-configure.sh b/apps/compiler/2-configure.sh deleted file mode 100755 index 0d59b1caac..0000000000 --- a/apps/compiler/2-configure.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/usr/bin/env bash - -CURRENT_PATH="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" - -bash "$CURRENT_PATH/compiler.sh" 2 diff --git a/apps/compiler/3-build.sh b/apps/compiler/3-build.sh deleted file mode 100755 index 6956f82fd3..0000000000 --- a/apps/compiler/3-build.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/usr/bin/env bash - -CURRENT_PATH="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" - -bash "$CURRENT_PATH/compiler.sh" 3 diff --git a/apps/compiler/compiler.sh b/apps/compiler/compiler.sh index cb89bfb705..388ad41a32 100755 --- a/apps/compiler/compiler.sh +++ b/apps/compiler/compiler.sh @@ -4,41 +4,67 @@ CURRENT_PATH="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" source "$CURRENT_PATH/includes/includes.sh" -function all() { - comp_clean - comp_configure - comp_build -} - function run_option() { - if test "${comp_functions[$1-1]+'test'}"; then + re='^[0-9]+$' + if [[ $1 =~ $re ]] && test "${comp_functions[$1-1]+'test'}"; then ${comp_functions[$1-1]} + elif [ -n "$(type -t comp_$1)" ] && [ "$(type -t comp_$1)" = function ]; then + fun="comp_$1" + $fun else - echo "invalid option" - fi + echo "invalid option, use --help option for the commands list" + fi } -comp_options=("Clean" "Configure" "Build" "All") -comp_functions=("comp_clean" "comp_configure" "comp_build" "all") +function comp_quit() { + exit 0 +} -runHooks "ON_AFTER_OPTIONS" #you can create your custom options +comp_options=( + "build: Configure and compile" + "clean: Clean build files" + "configure: Run CMake" + "compile: Compile only" + "all: clean, configure and compile" + "quit: Close this menu") +comp_functions=( + "comp_build" + "comp_clean" + "comp_configure" + "comp_compile" + "comp_all" + "comp_quit") -# push exit after custom options -comp_options+=('Exit') -comp_functions+=('exit 0') +PS3='[ Please enter your choice ]: ' -# run option directly if specified in argument -[ ! -z $1 ] && run_option $1 && exit 0 +runHooks "ON_AFTER_OPTIONS" #you can create your custom options -PS3='[ Please enter your choice ]: ' -select opt in "${comp_options[@]}" -do - case $opt in - 'Exit') - break +function _switch() { + _reply="$1" + _opt="$2" + + case $_reply in + ""|"--help") + echo "Available commands:" + printf '%s\n' "${options[@]}" ;; *) - run_option $REPLY + run_option $_reply $_opt ;; esac +} + + +while true +do + # run option directly if specified in argument + [ ! -z $1 ] && _switch $@ + [ ! -z $1 ] && exit 0 + + select opt in "${comp_options[@]}" + do + echo "==== ACORE COMPILER ====" + _switch $REPLY + break; + done done diff --git a/apps/compiler/includes/functions.sh b/apps/compiler/includes/functions.sh index 4dfaa46038..947f9ff5fc 100644 --- a/apps/compiler/includes/functions.sh +++ b/apps/compiler/includes/functions.sh @@ -39,7 +39,7 @@ function comp_configure() { } -function comp_build() { +function comp_compile() { [ $MTHREADS == 0 ] && MTHREADS=`grep -c ^processor /proc/cpuinfo` && MTHREADS=$(($MTHREADS + 2)) echo "Using $MTHREADS threads" @@ -55,3 +55,13 @@ function comp_build() { runHooks "ON_AFTER_BUILD" } + +function comp_build() { + comp_configure + comp_build +} + +function comp_all() { + comp_clean + comp_build +}
\ No newline at end of file diff --git a/apps/db_assembler/db_assembler.sh b/apps/db_assembler/db_assembler.sh index 4b4c23e5b9..e1e1de240a 100644 --- a/apps/db_assembler/db_assembler.sh +++ b/apps/db_assembler/db_assembler.sh @@ -6,56 +6,70 @@ source "$CURRENT_PATH/includes/includes.sh" cmdopt=$1 -while true -do -echo "===== DB ASSEMBLER MENU =====" -PS3='Please enter your choice: ' +PS3='[Please enter your choice]: ' options=( - "Assemble ALL" "Assemble only bases" "Assemble only updates" "Assemble only customs" - "Quit" - "Assemble & import ALL" "Assemble & import only bases" "Assemble & import only updates" "Assemble & import only customs" + "all: Assemble all" # 1 + "bases: Assemble only bases" # 2 + "updates: Assemble only updates" # 3 + "customs: Assemble only customs" # 4 + "import-all: Assemble & Import all" # 5 + "import-bases: Assemble & Import only bases" # 6 + "import-updates: Assemble & Import only updates" # 7 + "import-customs: Assemble & Import only customs" # 8 + "quit: Exit from this menu" # 9 ) function _switch() { - case $1 in - "Assemble ALL") + _reply="$1" + _opt="$2" + + case $_reply in + ""|"all"|"1") dbasm_run true true true ;; - "Assemble only bases") + ""|"bases"|"2") dbasm_run true false false ;; - "Assemble only updates") + ""|"updates"|"3") dbasm_run false true false ;; - "Assemble only customs") + ""|"customs"|"4") dbasm_run false false true ;; - "Assemble & import ALL") + ""|"import-all"|"5") dbasm_import true true true ;; - "Assemble & import only bases") + ""|"import-bases"|"6") dbasm_import true false false ;; - "Assemble & import only updates") + ""|"import-updates"|"7") dbasm_import false true false ;; - "Assemble & import only customs") + ""|"import-customs"|"8") dbasm_import false false true ;; - "Quit") + ""|"quit"|"9") echo "Goodbye!" exit ;; - *) echo invalid option;; + ""|"--help") + echo "Available commands:" + printf '%s\n' "${options[@]}" + ;; + *) echo "invalid option, use --help option for the commands list";; esac } -# run option directly if specified in argument -[ ! -z $1 ] && _switch "${options[$cmdopt-1]}" && exit 0 - -select opt in "${options[@]}" +while true do - _switch "$opt" - break -done + # run option directly if specified in argument + [ ! -z $1 ] && _switch $@ + [ ! -z $1 ] && exit 0 + + select opt in "${options[@]}" + do + echo "===== DB ASSEMBLER MENU =====" + _switch $REPLY + break + done done diff --git a/apps/installer/includes/functions.sh b/apps/installer/includes/functions.sh index 3aa0b6baf2..987fe5e3c8 100644 --- a/apps/installer/includes/functions.sh +++ b/apps/installer/includes/functions.sh @@ -44,10 +44,6 @@ function inst_cleanCompile() { inst_compile } -function inst_assembleDb { - dbasm_import true true true -} - function inst_allInOne() { inst_configureOS inst_updateRepo @@ -55,19 +51,66 @@ function inst_allInOne() { inst_assembleDb } +function inst_getVersionBranch() { + local res="master" + local v="not-defined" + local MODULE_MAJOR=0 + local MODULE_MINOR=0 + local MODULE_PATCH=0 + local MODULE_SPECIAL=0; + local ACV_MAJOR=0 + local ACV_MINOR=0 + local ACV_PATCH=0 + local ACV_SPECIAL=0; + local curldata=$(curl -f --silent -H 'Cache-Control: no-cache' "$1" || echo "{}") + local parsed=$(echo "$curldata" | "$AC_PATH_DEPS/jsonpath/JSONPath.sh" -b '$.compatibility.*.[version,branch]') + + semverParseInto "$ACORE_VERSION" ACV_MAJOR ACV_MINOR ACV_PATCH ACV_SPECIAL + + if [[ ! -z "$parsed" ]]; then + readarray -t vers < <(echo "$parsed") + local idx + res="none" + # since we've the pair version,branch alternated in not associative and one-dimensional + # array, we've to simulate the association with length/2 trick + for idx in `seq 0 $((${#vers[*]}/2-1))`; do + semverParseInto "${vers[idx*2]}" MODULE_MAJOR MODULE_MINOR MODULE_PATCH MODULE_SPECIAL + if [[ $MODULE_MAJOR -eq $ACV_MAJOR && $MODULE_MINOR -le $ACV_MINOR ]]; then + res="${vers[idx*2+1]}" + v="${vers[idx*2]}" + fi + done + fi + + echo "$v" "$res" +} + function inst_module_search { - search="" + + local res="$1" + local idx=0; + if [ -z "$1" ]; then echo "Type what to search or leave blank for full list" read -p "Insert name: " res - - search="+$res" fi - echo "Searching ..." + + local search="+$res" + + echo "Searching $res..." echo ""; - for i in `curl -s "https://api.github.com/search/repositories?q=org%3Aazerothcore${search}+fork%3Atrue+topic%3Acore-module+sort%3Astars&type=" | grep \"name\" | cut -d ':' -f 2-3|tr -d '",'`; do - echo "-> $i"; + readarray -t MODS < <(curl --silent "https://api.github.com/search/repositories?q=org%3Aazerothcore${search}+fork%3Atrue+topic%3Acore-module+sort%3Astars&type=" \ + | "$AC_PATH_DEPS/jsonpath/JSONPath.sh" -b '$.items.*.name') + while (( ${#MODS[@]} > idx )); do + mod="${MODS[idx++]}" + read v b < <(inst_getVersionBranch "https://raw.githubusercontent.com/azerothcore/$mod/master/acore-module.json") + + if [[ "$b" != "none" ]]; then + echo "-> $mod (tested with AC v$v)" + else + echo "-> $mod (no revision available for AC v$AC_VERSION, it could not work!)" + fi done echo ""; @@ -75,30 +118,50 @@ function inst_module_search { } function inst_module_install { + local res if [ -z "$1" ]; then echo "Type the name of the module to install" read -p "Insert name: " res + else + res="$1" fi - git clone "https://github.com/azerothcore/$res" "$AC_PATH_ROOT/modules/$res" && echo "Done, please re-run compiling and db assembly. Read instruction on module repository for more information" + read v b < <(inst_getVersionBranch "https://raw.githubusercontent.com/azerothcore/$res/master/acore-module.json") + + if [[ "$b" != "none" ]]; then + Joiner:add_repo "https://github.com/azerothcore/$res" "$res" "$b" && echo "Done, please re-run compiling and db assembly. Read instruction on module repository for more information" + else + echo "Cannot install $res module: it doesn't exists or no version compatible with AC v$ACORE_VERSION are available" + fi echo ""; echo ""; } function inst_module_update { + local res; + local _tmp; + local branch; + local p; + if [ -z "$1" ]; then echo "Type the name of the module to update" read -p "Insert name: " res + else + res="$1" fi - cd "$AC_PATH_ROOT/modules/$res" + _tmp=$PWD - #git reset --hard master - #git clean -f - git pull origin master && echo "Done" + if [ -d "$J_PATH_MODULES/$res/" ]; then + cd "$J_PATH_MODULES/$res/" + branch=`git rev-parse --abbrev-ref HEAD` - cd "../../" + Joiner:upd_repo "https://github.com/azerothcore/$res" "$res" "$branch" && echo "Done, please re-run compiling and db assembly" || echo "Cannot update" + cd $_tmp + else + echo "Cannot update! Path doesn't exist" + fi; echo ""; echo ""; @@ -108,10 +171,29 @@ function inst_module_remove { if [ -z "$1" ]; then echo "Type the name of the module to remove" read -p "Insert name: " res + else + res="$1" fi - rm -rf "$AC_PATH_ROOT/modules/$res" && echo "Done" + Joiner:remove "$res" && echo "Done, please re-run compiling" || echo "Cannot remove" echo ""; echo ""; +} + + +function inst_simple_restarter { + echo "Running $1 in background..." + bash "$AC_PATH_APPS/startup-scripts/simple-restarter" "$BINPATH" "$1" & +} + +function inst_download_client_data { + path="$BINPATH/data" + if [ -e "$path/.git/" ]; then + # if exists , update + git --git-dir="$path/.git/" rev-parse && git --git-dir="$path/.git/" pull origin master | grep 'Already up-to-date.' && changed="no" + else + # otherwise clone + git clone "https://github.com/wowgaming/client-data" -c advice.detachedHead=0 -b master --depth=1 $path + fi }
\ No newline at end of file diff --git a/apps/installer/includes/includes.sh b/apps/installer/includes/includes.sh index 16ba795792..a0dad11cb5 100644 --- a/apps/installer/includes/includes.sh +++ b/apps/installer/includes/includes.sh @@ -1,9 +1,31 @@ -CURRENT_PATH="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +[[ ${INSTALLER_GUARDYVAR:-} -eq 1 ]] && return || readonly INSTALLER_GUARDYVAR=1 # include it once + +CURRENT_PATH=$( cd "$(dirname "${BASH_SOURCE[0]}")" ; pwd ) source "$CURRENT_PATH/../../bash_shared/includes.sh" AC_PATH_INSTALLER="$AC_PATH_APPS/installer" + +J_VER_REQ="v0.8.3" +J_PATH="$AC_PATH_APPS/drassil/joiner" +J_PATH_MODULES="$AC_PATH_MODULES" + +#install/update and include joiner +if [ ! -d "$J_PATH/.git" ]; then + git clone https://github.com/drassil/joiner "$J_PATH" -b master + git --git-dir="$J_PATH/.git/" --work-tree="$J_PATH/" reset --hard "$J_VER_REQ" +else + # legacy code, with new rev of joiner the update process is internally handled + _cur_branch=`git --git-dir="$J_PATH/.git/" --work-tree="$J_PATH/" rev-parse --abbrev-ref HEAD` + _cur_ver=`git --git-dir="$J_PATH/.git/" --work-tree="$J_PATH/" name-rev --tags --name-only $_cur_branch` + if [ "$_cur_ver" != "$J_VER_REQ" ]; then + git --git-dir="$J_PATH/.git" --work-tree="$J_PATH/" rev-parse && git --git-dir="$J_PATH/.git" --work-tree="$J_PATH/" fetch --tags origin master --quiet + git --git-dir="$J_PATH/.git/" --work-tree="$J_PATH/" reset --hard "$J_VER_REQ" + fi +fi +source "$AC_PATH_APPS/drassil/joiner/joiner.sh" + if [ -f "$AC_PATH_INSTALLER/config.sh" ]; then source "$AC_PATH_INSTALLER/config.sh" # should overwrite previous fi @@ -11,4 +33,6 @@ fi source "$AC_PATH_APPS/compiler/includes/includes.sh" source "$AC_PATH_APPS/db_assembler/includes/includes.sh" +source "$AC_PATH_DEPS/semver_bash/semver.sh" + source "$AC_PATH_INSTALLER/includes/functions.sh" diff --git a/apps/installer/main.sh b/apps/installer/main.sh index 44fc65efb0..e9ee7a3918 100644 --- a/apps/installer/main.sh +++ b/apps/installer/main.sh @@ -4,75 +4,90 @@ CURRENT_PATH="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" source "$CURRENT_PATH/includes/includes.sh" -cmdopt=$1 - -while true -do -echo "===== INSTALLER SCRIPT =====" -PS3='Please enter your choice: ' +PS3='[Please enter your choice]: ' options=( - "First Installation" "Configure OS dep" "Update Repository" "Reset & Clean Repository" - "Compile" "Clean & Compile" "Assemble & Import DB" "Module Search" "Module Install" "Module Update" "Module Remove" - "Sub Menu >> Compiler" "Sub Menu >> DB Assembler" - "Quit" + "init (i): First Installation" # 1 + "install-deps (d): Configure OS dep" # 2 + "pull (u): Update Repository" # 3 + "reset (r): Reset & Clean Repository" # 4 + "compiler (c): Run compiler tool" # 5 + "db-assembler (a): Run db assembler tool" # 6 + "module-search (ms): Module Search by keyword" # 7 + "module-install (mi): Module Install by name" # 8 + "module-update (mu): Module Update by name" # 9 + "module-remove: (mr): Module Remove by name" # 10 + "client-data: (gd): download client data from github repository (beta)" # 11 + "run-worldserver (rw): execute a simple restarter for worldserver" # 12 + "run-authserver (ra): execute a simple restarter for authserver" # 13 + "quit: Exit from this menu" # 14 ) function _switch() { - case $1 in - "First Installation") + _reply="$1" + _opt="$2" + + case $_reply in + ""|"i"|"init"|"1") inst_allInOne ;; - "Configure OS dep") + ""|"d"|"install-deps"|"2") inst_configureOS ;; - "Update Repository") + ""|"u"|"pull"|"3") inst_updateRepo ;; - "Reset & Clean Repository") + ""|"r"|"reset"|"4") inst_resetRepo ;; - "Compile") - inst_compile + ""|"c"|"compiler"|"5") + bash "$AC_PATH_APPS/compiler/compiler.sh" $_opt ;; - "Clean & Compile") - inst_cleanCompile + ""|"a"|"db-assembler"|"6") + bash "$AC_PATH_APPS/db_assembler/db_assembler.sh" $_opt ;; - "Assemble & Import DB") - inst_assembleDb + ""|"ms"|"module-search"|"7") + inst_module_search "$_opt" ;; - "Module Search") - inst_module_search $2 + ""|"mi"|"module-install"|"8") + inst_module_install "$_opt" ;; - "Module Install") - inst_module_install $2 + ""|"mu"|"module-update"|"9") + inst_module_update "$_opt" ;; - "Module Update") - inst_module_update $2 + ""|"mr"|"module-remove"|"10") + inst_module_remove "$_opt" ;; - "Module Remove") - inst_module_remove $2 + ""|"gd"|"client-data"|"11") + inst_download_client_data ;; - "Sub Menu >> Compiler") - bash "$AC_PATH_APPS/compiler/compiler.sh" + ""|"rw"|"run-worldserver"|"12") + inst_simple_restarter worldserver ;; - "Sub Menu >> DB Assembler") - bash "$AC_PATH_APPS/db_assembler/db_assembler.sh" + ""|"ra"|"run-authserver"|"13") + inst_simple_restarter authserver ;; - "Quit") + ""|"quit"|"14") echo "Goodbye!" exit ;; - *) echo invalid option;; + ""|"--help") + echo "Available commands:" + printf '%s\n' "${options[@]}" + ;; + *) echo "invalid option, use --help option for the commands list";; esac } -# run option directly if specified in argument -[ ! -z $1 ] && _switch "${options[$cmdopt-1]}" -[ ! -z $1 ] && exit 0 - -select opt in "${options[@]}" +while true do - _switch "$opt" - break -done + # run option directly if specified in argument + [ ! -z $1 ] && _switch $@ # old method: "${options[$cmdopt-1]}" + [ ! -z $1 ] && exit 0 + + select opt in "${options[@]}" + do + echo "==== ACORE DASHBOARD ====" + _switch $REPLY + break + done done diff --git a/apps/startup-scripts/simple-restarter b/apps/startup-scripts/simple-restarter new file mode 100644 index 0000000000..084d1a1c92 --- /dev/null +++ b/apps/startup-scripts/simple-restarter @@ -0,0 +1,9 @@ +#PARAMETER 1: directory +#PARAMETER 2: binary file + +_bin_path=$1 +_bin_file=$2 +while true +do + cd "$_bin_path" && "./$_bin_file" &>/dev/null; echo "$_bin_file crashed (?), restarting..." +done
\ No newline at end of file @@ -1,3 +1,5 @@ #!/usr/bin/env bash -source ./acore-installer
\ No newline at end of file +CUR_PATH="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" + +source "$CUR_PATH/acore-installer"
\ No newline at end of file diff --git a/bin/acore-compiler b/bin/acore-compiler index aa356deede..ba5311a12f 100755 --- a/bin/acore-compiler +++ b/bin/acore-compiler @@ -1,3 +1,5 @@ #!/usr/bin/env bash -bash ../apps/compiler/compiler.sh
\ No newline at end of file +CUR_PATH="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" + +source "$CUR_PATH/../apps/compiler/compiler.sh" diff --git a/bin/acore-db-asm b/bin/acore-db-asm index 7cc11c8ef8..962a70b233 100755 --- a/bin/acore-db-asm +++ b/bin/acore-db-asm @@ -1,3 +1,5 @@ #!/usr/bin/env bash -bash ../apps/db_assembler/db_assembler.sh
\ No newline at end of file +CUR_PATH="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" + +source "$CUR_PATH/../apps/db_assembler/db_assembler.sh" diff --git a/bin/acore-db-export b/bin/acore-db-export index 9a1f154586..11b8d6cba0 100755 --- a/bin/acore-db-export +++ b/bin/acore-db-export @@ -1,3 +1,5 @@ #!/usr/bin/env bash -bash ../apps/db_exporter/db_exporter.sh
\ No newline at end of file +CUR_PATH="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" + +source "$CUR_PATH/../apps/db_exporter/db_exporter.sh" diff --git a/bin/acore-db-pendings b/bin/acore-db-pendings index 569d161c63..6f8d62f9e6 100755 --- a/bin/acore-db-pendings +++ b/bin/acore-db-pendings @@ -1,3 +1,5 @@ #!/usr/bin/env bash -bash ../apps/db_pendings/import.sh
\ No newline at end of file +CUR_PATH="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" + +source "$CUR_PATH/../apps/db_pendings/import.sh" diff --git a/bin/acore-installer b/bin/acore-installer index c61d00458e..ef68e06150 100755 --- a/bin/acore-installer +++ b/bin/acore-installer @@ -1,3 +1,5 @@ #!/usr/bin/env bash -bash ../apps/installer/main.sh
\ No newline at end of file +CUR_PATH="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" + +source "$CUR_PATH/../apps/installer/main.sh" 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. + +[](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 <mark.clarkson@smorg.co.uk>" +["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.<br> +Combine with '-i' for case insensitive search.<br> +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 <mark.clarkson@smorg.co.uk>", + "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 diff --git a/install.sh b/install.sh index 24a8320b4a..8950dab666 100755 --- a/install.sh +++ b/install.sh @@ -3,16 +3,8 @@ set -e CUR_PATH="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" -PATH_APPS="$CUR_PATH/apps/" -PATH_MODULES="$CUR_PATH/modules/" -[ ! -d $PATH_APPS/drassil/joiner ] && git clone https://github.com/drassil/joiner $PATH_APPS/drassil/joiner -b master -source "$PATH_APPS/drassil/joiner/joiner.sh" +source "$CUR_PATH/apps/installer/includes/includes.sh" -# installing repository dependencies -if [[ $1 == "dev" ]]; then - git submodule update --init "$CUR_PATH/data/doc" -fi -source "$CUR_PATH/apps/installer/main.sh" |