Skip to content

use grep -E, add Makefile, add -S, -A, -T options, fix ensure_deps.sh for macOS, fix command line parsing, make JSONPath.sh and test scripts robust #16

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Aug 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
421 changes: 241 additions & 180 deletions JSONPath.sh

Large diffs are not rendered by default.

43 changes: 43 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
#!/usr/bin/env make
#
# JSONPath.sh - JSONPath implementation written in Bash

#############
# utilities #
#############

INSTALL= install
SHELL= bash

######################
# target information #
######################

DESTDIR= /usr/local/bin

TARGETS= JSONPath.sh

######################################
# all - default rule - must be first #
######################################

all: ${TARGETS}

#################################################
# .PHONY list of rules that do not create files #
#################################################

.PHONY: all configure clean clobber install

###################################
# standard Makefile utility rules #
###################################

configure:

clean:

clobber: clean

install: all
${INSTALL} -m 0555 ${TARGETS} ${DESTDIR}
52 changes: 37 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,32 +12,50 @@ try wrapping the command like `./ensure_deps.sh ./JSONPath.sh`.

## Invocation

JSONPath.sh [-b] [-i] [-j] [-h] [-p] [-u] [-f FILE] [pattern]
JSONPath.sh [-h] [-b] [-j] [-u] [-i] [-p] [-w] [-f FILE] [-n] [-s] [-S] [-A] [-T] [pattern]

pattern
> the JSONPath query. Defaults to '$.\*' if not supplied.
-h
> Show help text.

-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.

-i
> Case insensitive searching.

-p
> Pass JSON.sh formatted data through to the JSON parser only. Useful after
> JSON.sh data has been manipulated.

-h
> Show help text.
-w
> Match whole words only (for filter script expression).

-f FILE
> Read a FILE instead of reading from standard input.

-n
> Do not print header.

-s
> Normalize solidus.

-S
> Print spaces around :'s.

-A
> Start array on same line as JSON member.

-T
> Indent with tabs instead of 4 character spaces.

pattern
> the JSONPath query. Defaults to '$.\*' if not supplied.

## Requirements

Expand All @@ -55,6 +73,10 @@ Install with npm:

* `sudo npm install -g jsonpath.sh`

Install with make:

* `make install`

Or copy the `JSONPath.sh` script to your PATH, for example:

``` bash
Expand Down Expand Up @@ -215,7 +237,7 @@ done
-f test/valid/goessner.net.expanded.json \
'$.store.book[?(@.price<4.20)].[title,price]'

# The following does not work yet (TODO)
# The following does not work yet (TODO)
./JSONPath.sh \
-f test/valid/goessner.net.expanded.json \
'$.store.book[(@.length-1)].title'
Expand Down Expand Up @@ -340,7 +362,7 @@ 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'
$ ./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"
Expand All @@ -352,7 +374,7 @@ Use standard unix tools to remove duplicates:

```
$ ./JSONPath.sh -f test/valid/goessner.net.expanded.json '$..author' \
| sort -k2 | uniq -f 1
| sort -k2 | uniq -f 1
... 11 lines of output ...
```

Expand Down Expand Up @@ -388,7 +410,7 @@ $ ./JSONPath.sh -f test/valid/goessner.net.expanded.json \
"book":
[
{
"author":"Douglas E. Richards"
"author":"Douglas E. Richards"
},
{
"author":"Evelyn Waugh"
Expand Down
29 changes: 15 additions & 14 deletions all-docker-tests.sh
Original file line number Diff line number Diff line change
@@ -1,45 +1,46 @@
#!/usr/bin/env bash

log=testlog.log

# Fedora
export IMAGE=json-path-fedora-bash
cp test/docker/Dockerfile-fedora test/docker/Dockerfile
./test/docker/wrap_in_docker.sh ./all-tests.sh | tee $log
./test/docker/wrap_in_docker.sh ./all-tests.sh | tee "$log"

a=$(grep 'test(s) failed' $log)
a=$(grep 'test(s) failed' "$log")

# Ubuntu
export IMAGE=json-path-ubuntu-bash
cp test/docker/Dockerfile-ubuntu test/docker/Dockerfile
./test/docker/wrap_in_docker.sh ./all-tests.sh | tee $log
./test/docker/wrap_in_docker.sh ./all-tests.sh | tee "$log"

b=$(grep 'test(s) failed' $log)
b=$(grep 'test(s) failed' "$log")

# Centos
export IMAGE=json-path-centos-bash
cp test/docker/Dockerfile-centos test/docker/Dockerfile
./test/docker/wrap_in_docker.sh ./all-tests.sh | tee $log
./test/docker/wrap_in_docker.sh ./all-tests.sh | tee "$log"

c=$(grep 'test(s) failed' $log)
c=$(grep 'test(s) failed' "$log")

# Debian
export IMAGE=json-path-debian-bash
cp test/docker/Dockerfile-debian test/docker/Dockerfile
./test/docker/wrap_in_docker.sh ./all-tests.sh | tee $log
./test/docker/wrap_in_docker.sh ./all-tests.sh | tee "$log"

d=$(grep 'test(s) failed' $log)
d=$(grep 'test(s) failed' "$log")

# Cleanup
rm $log
rm -- "$log"
rm test/docker/Dockerfile

# Results
echo
echo "Fedora tests"
echo $a
echo "$a"
echo "Ubuntu tests"
echo $b
echo "$b"
echo "Centos tests"
echo $c
echo "$c"
echo "Debian tests"
echo $c

echo "$d"
34 changes: 20 additions & 14 deletions all-tests.sh
Original file line number Diff line number Diff line change
@@ -1,33 +1,39 @@
#!/bin/sh
#!/usr/bin/env bash

cd ${0%/*}
shopt -s lastpipe
export CD_FAILED=
cd "${0%/*}" || CD_FAILED="true"
if [[ -n $CD_FAILED ]]; then
echo "$0: ERROR: cannot cd ${0%/*}" 1>&2
exit 1
fi

#set -e
fail=0
tests=0
#all_tests=${__dirname:}
#echo PLAN ${#all_tests}
for test in test/*.sh ;
find test -mindepth 1 -maxdepth 1 -name '*.sh' -print | while read -r test;
do
tests=$((tests+1))
echo TEST: $test
./$test
((++tests))
echo TEST: "$test"
./"$test"
ret=$?
if [ $ret -eq 0 ] ; then
echo OK: ---- $test
passed=$((passed+1))
if [[ $ret -eq 0 ]]; then
echo OK: ---- "$test"
((++passed))
else
echo FAIL: $test $fail
fail=$((fail+ret))
echo FAIL: "$test" "$fail"
((fail=fail+ret))
fi
done

if [ $fail -eq 0 ]; then
if [[ $fail -eq 0 ]]; then
echo -n 'SUCCESS '
exitcode=0
else
echo -n 'FAILURE '
exitcode=1
fi
echo $passed / $tests
exit $exitcode
echo "$passed" "/" "$tests"
exit "$exitcode"
14 changes: 9 additions & 5 deletions ensure_deps.sh
Original file line number Diff line number Diff line change
Expand Up @@ -22,18 +22,22 @@ test_gnu_compat() {
>&2 echo "Make sure you have GNU sed or compatible installed"
fi

if [[ $error -gt 0 && is_osx ]]; then
if [[ $error -gt 0 ]] && is_osx; then
>&2 echo "With homebrew you may install necessary deps via \`brew install grep gnu-sed coreutils\`"
>&2 echo 'Put /opt/homebrew/bin/gsed early in your PATH'
>&2 echo 'Then put /opt/homebrew/bin/ggrep early in your PATH'
>&2 echo 'And put /opt/homebrew/var/homebrew/linked/coreutils/libexec/gnubin early in your PATH'
>&2 echo "For example: PATH=$PATH"
fi

return $error
return "$error"
}

main() {
if is_osx; then
export PATH="/usr/local/opt/coreutils/libexec/gnubin:$PATH"
export PATH="/usr/local/opt/grep/libexec/gnubin:$PATH"
export PATH="/usr/local/opt/gnu-sed/libexec/gnubin:$PATH"
export PATH="/opt/homebrew/bin/gsed:$PATH"
export PATH="/opt/homebrew/bin/ggrep:$PATH"
export PATH="/opt/homebrew/var/homebrew/linked/coreutils/libexec/gnubin:$PATH"
fi

test_gnu_compat
Expand Down
24 changes: 15 additions & 9 deletions test/flatten-test.sh
Original file line number Diff line number Diff line change
@@ -1,24 +1,30 @@
#!/bin/sh
#!/usr/bin/env bash

cd ${0%/*}
shopt -s lastpipe
CD_FAILED=
cd "${0%/*}" || CD_FAILED="true"
if [[ -n $CD_FAILED ]]; then
echo "$0: ERROR: cannot cd ${0%/*}" 1>&2
exit 1
fi
fails=0
i=0
tests=`ls flatten/*.argp* | wc -l`
tests=$(find flatten -name '*.argp*' -print | wc -l)
echo "1..${tests##* }"
# Standard flatten tests
for argpfile in flatten/*.argp*
find flatten -name '*.argp*' -print | while read -r argpfile;
do
input="${argpfile%.*}.json"
expected="${argpfile%.*}_${argpfile##*.}.flattened"
argp=$(cat $argpfile)
i=$((i+1))
if ! ../JSONPath.sh "$argp" -u < "$input" | diff -u - "$expected"
argp=$(< "$argpfile")
((++i))
if ! ../JSONPath.sh -u -- "$argp" < "$input" | diff -u -- - "$expected"
then
echo "not ok $i - $argpfile"
fails=$((fails+1))
((++fails))
else
echo "ok $i - $argpfile"
fi
done
echo "$fails test(s) failed"
exit $fails
exit "$fails"
24 changes: 15 additions & 9 deletions test/json-encoding-test.sh
Original file line number Diff line number Diff line change
@@ -1,23 +1,29 @@
#!/bin/sh
#!/usr/bin/env bash

cd ${0%/*}
shopt -s lastpipe
CD_FAILED=
cd "${0%/*}" || CD_FAILED="true"
if [[ -n $CD_FAILED ]]; then
echo "$0: ERROR: cannot cd ${0%/*}" 1>&2
exit 1
fi
fails=0
i=0
tests=`ls valid/*.argp* | wc -l`
tests=$(find valid -name '*.argp*' -print | wc -l)
echo "1..${tests##* }"
# Json output tests
for argpfile in valid/*.argp*
find valid -name '*.argp*' -print | while read -r argpfile;
do
input="${argpfile%.*}.json"
argp=$(cat $argpfile)
i=$((i+1))
if ! ../JSONPath.sh "$argp" -j < "$input" | python -mjson.tool >/dev/null
argp=$(< "$argpfile")
((++i))
if ! ../JSONPath.sh -j -- "$argp" < "$input" | python3 -mjson.tool >/dev/null
then
echo "not ok $i - $argpfile"
fails=$((fails+1))
((++fails))
else
echo "ok $i - JSON validated for $argpfile"
fi
done
echo "$fails test(s) failed"
exit $fails
exit "$fails"
Loading