pull/2/head
Joseph Werle 10 years ago
parent 81cec6d0f9
commit 16a53e5bcb

@ -0,0 +1 @@
bpkg.sh

@ -0,0 +1 @@
lib/install/install.sh

@ -0,0 +1 @@
lib/json/JSON.sh

@ -0,0 +1 @@
lib/package/package.sh

@ -0,0 +1,60 @@
#!/bin/bash
VERSION="0.0.1"
## output error to stderr
error () {
printf >&2 "error: %s\n" "${@}"
}
## output usage
usage () {
echo "usage: bpkg [-hV] <command> [args]"
}
## feature tests
features () {
if ! type bpkg-json > /dev/null 2>&1; then
error "Missing json parser dependency"
exit 1
fi
}
bpkg () {
local arg="$1"
local cmd=""
shift
case "${arg}" in
## flags
-V|--version)
echo "${VERSION}"
return 0
;;
-h|--help)
usage
return 0
;;
*)
cmd="bpkg-${arg}"
if type -f "${cmd}" > /dev/null 2>&1; then
"${cmd}" "${@}"
return $?
fi
;;
esac
}
## test for required features
features
if [[ ${BASH_SOURCE[0]} != $0 ]]; then
export -f bpkg
else
bpkg "${@}"
exit $?
fi

@ -0,0 +1,140 @@
#!/bin/bash
BPKG_REMOTE="${BPKG_REMOTE:-"https://raw.githubusercontent.com"}"
BPKG_USER="${BPKG_USER:-"bpkg"}"
## outut usage
usage () {
echo "usage: bpkg-install [-h|--help]"
echo " or: bpkg-install <package>"
echo " or: bpkg-install <user>/<package>"
}
## Install a bash package
bpkg_install () {
local pkg="${1}"
local cwd="`pwd`"
local user=""
local name=""
local url=""
local uri=""
local version=""
local status=""
local json=""
declare -a local parts=()
declare -a local scripts=()
case "${pkg}" in
-h|--help)
usage
return 0
;;
esac
## ensure there is a package to install
if [ -z "${pkg}" ]; then
return 1
fi
## ensure remote is reachable
{
curl -s "${BPKG_REMOTE}"
if [ "0" != "$?" ]; then
return 1
fi
}
## get version if available
{
OLDIFS="${IFS}"
IFS="@"
parts=(${pkg})
IFS="${OLDIFS}"
}
if [ "1" = "${#parts[@]}" ]; then
version="master"
elif [ "2" = "${#parts[@]}" ]; then
name="${parts[0]}"
version="${parts[1]}"
else
echo >&2 "error: Error parsing package version"
return 1
fi
## split by user name and repo
{
OLDIFS="${IFS}"
IFS='/'
parts=(${pkg})
IFS="${OLDIFS}"
}
if [ "1" = "${#parts[@]}" ]; then
user="${BPKG_USER}"
name="${parts[0]}"
elif [ "2" = "${#parts[@]}" ]; then
user="${parts[0]}"
name="${parts[1]}"
else
echo >&2 "error: Unable to determine package name"
return 1
fi
## clean up name of weird trailing versions
name=${name/@*//}
## build uri portion
uri="/${user}/${name}/${version}"
## clean up extra slashes in uri
uri=${uri/\/\///}
## build url
url="${BPKG_REMOTE}${uri}"
## determine if `package.json' exists at url
{
status=$(curl -sL "${url}/package.json" -w '%{http_code}' -o /dev/null)
if [ "0" != "$?" ] || (( status >= 400 )); then
echo >&2 "error: Package doesn't exist"
return 1
fi
}
## read package.json
json=$(curl -sL "${url}/package.json")
## construct scripts array
{
scripts=$(echo -n $json | bpkg-json -b | grep 'scripts' | awk '{ print $2 }' | tr -d '"')
OLDIFS="${IFS}"
IFS=','
scripts=($(echo ${scripts}))
IFS="${OLDIFS}"
}
## get package name from `package.json'
name="$(echo -n ${json} | bpkg-json -b | grep 'name' | awk '{ print $2 }' | tr -d '"')"
if [ "${#scripts[@]}" -gt "0" ]; then
## make `deps/' directory if possible
mkdir -p "${cwd}/deps/${name}"
## grab each script and place in deps directory
for (( i = 0; i < ${#scripts[@]} ; ++i )); do
(
local script=${scripts[$i]}
curl -sL "${url}/${script}" -o "${cwd}/deps/${name}/${script}"
)
done
fi
return 0
}
if [[ ${BASH_SOURCE[0]} != $0 ]]; then
export -f bpkg_install
else
bpkg_install "${@}"
exit $?
fi

@ -0,0 +1,2 @@
test/errlog
test/outlog

@ -0,0 +1,191 @@
#!/usr/bin/env bash
throw () {
echo "$*" >&2
exit 1
}
BRIEF=0
LEAFONLY=0
PRUNE=0
usage() {
echo
echo "Usage: JSON.sh [-b] [-l] [-p] [-h]"
echo
echo "-p - Prune empty. Exclude fields with empty values."
echo "-l - Leaf only. Only show leaf nodes, which stops data duplication."
echo "-b - Brief. Combines 'Leaf only' and 'Prune empty' options."
echo "-h - This help text."
echo
}
parse_options() {
set -- "$@"
local ARGN=$#
while [ $ARGN -ne 0 ]
do
case $1 in
-h) usage
exit 0
;;
-b) BRIEF=1
LEAFONLY=1
PRUNE=1
;;
-l) LEAFONLY=1
;;
-p) PRUNE=1
;;
?*) echo "ERROR: Unknown option."
usage
exit 0
;;
esac
shift 1
ARGN=$((ARGN-1))
done
}
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 () {
local GREP
local ESCAPE
local CHAR
if echo "test string" | egrep -ao --color=never "test" &>/dev/null
then
GREP='egrep -ao --color=never'
else
GREP='egrep -ao'
fi
if echo "test string" | egrep -o "test" &>/dev/null
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:]]+'
$GREP "$STRING|$NUMBER|$KEYWORD|$SPACE|." | egrep -v "^$SPACE$"
}
parse_array () {
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
[ "$BRIEF" -eq 0 ] && value=`printf '[%s]' "$ary"` || value=
:
}
parse_object () {
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
[ "$BRIEF" -eq 0 ] && value=`printf '{%s}' "$obj"` || value=
:
}
parse_value () {
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
isleaf=1
[ "$value" = '""' ] && isempty=1
;;
esac
[ "$value" = '' ] && return
[ "$LEAFONLY" -eq 0 ] && [ "$PRUNE" -eq 0 ] && print=1
[ "$LEAFONLY" -eq 1 ] && [ "$isleaf" -eq 1 ] && [ $PRUNE -eq 0 ] && print=1
[ "$LEAFONLY" -eq 0 ] && [ "$PRUNE" -eq 1 ] && [ "$isempty" -eq 0 ] && print=1
[ "$LEAFONLY" -eq 1 ] && [ "$isleaf" -eq 1 ] && \
[ $PRUNE -eq 1 ] && [ $isempty -eq 0 ] && print=1
[ "$print" -eq 1 ] && printf "[%s]\t%s\n" "$jpath" "$value"
:
}
parse () {
read -r token
parse_value
read -r token
case "$token" in
'') ;;
*) throw "EXPECTED EOF GOT $token" ;;
esac
}
parse_options "$@"
if ([ "$0" = "$BASH_SOURCE" ] || ! [ -n "$BASH_SOURCE" ]);
then
tokenize | parse
fi

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

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

@ -0,0 +1,69 @@
# JSON.sh
yo, so it's a json parser written in bash
pipe json to it, and it traverses the json objects and prints out the
path to the current object (as a JSON array) and then the object, without whitespace.
``` bash
$ json_parse < package.json
["name"] "JSON.sh"
["version"] "0.0.0"
["description"] ""
["homepage"] "http://github.com/dominictarr/JSON.sh"
["repository","type"] "git"
["repository","url"] "https://github.com/dominictarr/JSON.sh.git"
["repository"] {"type":"git","url":"https://github.com/dominictarr/JSON.sh.git"}
["bin","json_parse"] "./JSON.sh"
["bin"] {"json_parse":"./JSON.sh"}
["dependencies"] {}
# ... etc
```
a more complex example:
``` bash
curl registry.npmjs.org/express | ./JSON.sh | egrep '\["versions","[^"]*"\]'
... try it and see
```
## Options
-b
> Brief output. Combines 'Leaf only' and 'Prune empty' options.
-l
> Leaf only. Only show leaf nodes, which stops data duplication.
-p
> Prune empty. Exclude fields with empty values.
-h
> Show help text.
## Cool Links
* [step-/JSON.awk](https://github.com/step-/JSON.awk) JSON.sh ported to awk
* [kristopolous/TickTick](https://github.com/kristopolous/TickTick) Object Oriented BASH
* [archan937/jsonv.sh](https://github.com/archan937/jsonv.sh)
## Examples
If you have any examples with JSON.sh, streaming twitter, github, or whatever!
please issue a pull request and i will include them.
## Installation
install via npm or from AUR on archlinux
* `npm install -g JSON.sh`
* `yaourt -Sy json-sh`
([json-sh on aur](https://aur.archlinux.org/packages/json-sh/)
thanks to [kremlin-](https://github.com/kremlin-))
## License
This software is available under the following licenses:
* MIT
* Apache 2

@ -0,0 +1,30 @@
#! /usr/bin/env bash
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 '
else
echo -n 'FAILURE '
fi
echo $passed / $tests

@ -0,0 +1,14 @@
{ "name": "JSON.sh"
, "version": "0.1.8"
, "description": "JSON parser written in bash"
, "homepage": "http://github.com/dominictarr/JSON.sh"
, "repository":
{ "type": "git"
, "url": "https://github.com/dominictarr/JSON.sh.git" }
, "bin": {
"JSON.sh": "./JSON.sh"
}
, "dependencies": {}
, "devDependencies": {}
, "author": "Dominic Tarr <dominic.tarr@gmail.com> (http://bit.ly/dominictarr)"
, "scripts": { "test": "./all-tests.sh" } }

@ -0,0 +1,29 @@
#! /usr/bin/env bash
cd ${0%/*}
# make test output TAP compatible
# http://en.wikipedia.org/wiki/Test_Anything_Protocol
fails=0
tests=`ls invalid/* -1 | wc -l`
echo "1..${tests##* }"
for input in invalid/*
do
i=$((i+1))
if ../JSON.sh < "$input" > /tmp/JSON.sh_outlog 2> /tmp/JSON.sh_errlog
then
echo "not ok $i - cat $input | ../JSON.sh should fail"
#this should be indented with '#' at the start.
echo "OUTPUT WAS >>>"
cat /tmp/JSON.sh_outlog
echo "<<<"
fails=$((fails+1))
else
echo "ok $i - $input was rejected"
echo "#" `cat /tmp/JSON.sh_errlog`
fi
done
echo "$fails test(s) failed"
exit $fails

@ -0,0 +1,3 @@
{
"hello", "comma!"
}

@ -0,0 +1,35 @@
#! /usr/bin/env bash
cd ${0%/*}
. ../JSON.sh
ptest () {
tokenize | parse >/dev/null
}
fails=0
i=0
echo "1..4"
for input in '"oooo" ' '[true, 1, [0, {}]] ' '{"true": 1}'
do
i=$((i+1))
if echo "$input" | ptest
then
echo "ok $i - $input"
else
echo "not ok $i - $input"
fails=$((fails+1))
fi
done
if ! ptest < ../package.json
then
echo "not ok 4 - Parsing package.json failed!"
fails=$((fails+1))
else
echo "ok $i - package.json"
fi
echo "$fails test(s) failed"
exit $fails

@ -0,0 +1,54 @@
#! /usr/bin/env bash
cd ${0%/*}
. ../JSON.sh
i=0
fails=0
ttest () {
i=$((i+1))
local input="$1"; shift
local expected="$(printf '%s\n' "$@")"
echo "$expected" > /tmp/json_ttest_expected
if echo "$input" | tokenize | diff -u - /tmp/json_ttest_expected
then
echo "ok $i - $input"
else
echo "not ok $i - $input"
fails=$((fails+1))
fi
}
ttest '"dah"' '"dah"'
ttest '""' '""'
ttest '["dah"]' '[' '"dah"' ']'
ttest '" "' '" "'
ttest '" \" "' '" \" "'
ttest '["dah"]' '[' '"dah"' ']'
ttest '123' '123'
ttest '123.142' '123.142'
ttest '-123' '-123'
ttest '1e23' '1e23'
ttest '0.1' '0.1'
ttest '-110' '-110'
ttest '-110.10' '-110.10'
ttest '-110e10' '-110e10'
ttest 'null' 'null'
ttest 'true' 'true'
ttest 'false' 'false'
ttest '[ null , -110e10, "null" ]' \
'[' 'null' ',' '-110e10' ',' '"null"' ']'
ttest '{"e": false}' '{' '"e"' ':' 'false' '}'
ttest '{"e": "string"}' '{' '"e"' ':' '"string"' '}'
if ! cat ../package.json | tokenize >/dev/null
then
fails=$((fails+1))
echo "Tokenizing package.json failed!"
fi
echo "$fails test(s) failed"
exit $fails

@ -0,0 +1,21 @@
#! /usr/bin/env bash
cd ${0%/*}
fails=0
i=0
tests=`ls valid/*.json -1l | wc -l`
echo "1..$tests"
for input in valid/*.json
do
expected="${input%.json}.parsed"
i=$((i+1))
if ! ../JSON.sh < "$input" | diff -u - "$expected"
then
echo "not ok $i - $input"
fails=$((fails+1))
else
echo "ok $i - $input"
fi
done
echo "$fails test(s) failed"
exit $fails

@ -0,0 +1,5 @@
[0] 1
[1] 2
[2] 3
[3] "hello"
[] [1,2,3,"hello"]

@ -0,0 +1 @@
{"foo": "{\"foo\":\"bar\"}"}

@ -0,0 +1,2 @@
["foo"] "{\"foo\":\"bar\"}"
[] {"foo":"{\"foo\":\"bar\"}"}

@ -0,0 +1,4 @@
{
"key1": "string",
"key2": 3573
}

@ -0,0 +1,3 @@
["key1"] "string"
["key2"] 3573
[] {"key1":"string","key2":3573}

@ -0,0 +1,5 @@
[ 1
, []
, [4, "hello", {}]
, {"array": []}
]

@ -0,0 +1,9 @@
[0] 1
[1] []
[2,0] 4
[2,1] "hello"
[2,2] {}
[2] [4,"hello",{}]
[3,"array"] []
[3] {"array":[]}
[] [1,[],[4,"hello",{}],{"array":[]}]

@ -0,0 +1,7 @@
{
"object": {
"key": "value",
"empty": {}
},
"number": 5
}

@ -0,0 +1,5 @@
["object","key"] "value"
["object","empty"] {}
["object"] {"key":"value","empty":{}}
["number"] 5
[] {"object":{"key":"value","empty":{}},"number":5}

@ -0,0 +1,3 @@
{
"key": "Value"
}

@ -0,0 +1,2 @@
["key"] "Value"
[] {"key":"Value"}

@ -0,0 +1 @@
"hello this is a string"

@ -0,0 +1 @@
[] "hello this is a string"

@ -0,0 +1 @@
["hello this is a string"]

@ -0,0 +1,2 @@
[0] "hello this is a string"
[] ["hello this is a string"]

@ -0,0 +1 @@
{"key":"hello this is a string"}

@ -0,0 +1,2 @@
["key"] "hello this is a string"
[] {"key":"hello this is a string"}

@ -0,0 +1,53 @@
#!/bin/bash
## output usage
usage () {
echo "usage: bpkg-package [-h|--help]"
echo " or: bpkg-package <prop>"
echo " or: bpkg-package"
}
## Read a package property
bpkg_package () {
local prop="${1}"
local cwd="`pwd`"
local pkg="${cwd}/package.json"
## parse flags
case "${prop}" in
-h|--help)
usage
return 0
;;
esac
## ensure there is a package to read
if ! test -f "${pkg}"; then
echo 2>&1 "error: Unable to find \`package.json' in `pwd`"
return 1
fi
if [ -z "${prop}" ]; then
## output all propertyies if property
## is ommited
{
cat "${pkg}" | bpkg-json -b
}
else
## show value for a specific property
## in `package.json'
{
cat "${pkg}" | bpkg-json -b | grep "${prop}" | awk '{ printf $2 }'
echo
}
fi
return 0
}
if [[ ${BASH_SOURCE[0]} != $0 ]]; then
export -f bpkg_package
else
bpkg_package "${@}"
exit $?
fi

@ -0,0 +1,9 @@
{
"name": "bpkg",
"version": "0.0.1",
"description": "Lightweight bash package manager",
"global": true,
"scripts": [ "bpkg.sh" ],
"bin": { "bpkg": "bpkg.sh" },
"dependencies": { }
}
Loading…
Cancel
Save