-
-
Save mattdanielbrown/7aa94827278683934c5f22efdbe2858d to your computer and use it in GitHub Desktop.
bash gist cli
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
require() { | |
for what in $*; do | |
if !(which $what >& /dev/null); then | |
echo "error: $what is required to run this script, please install it" | |
exit 1 | |
fi | |
done | |
} | |
require xmlstarlet curl git | |
URL_BASE=https://gist.github.com | |
user=`git config gist.user` | |
[[ -z $user ]] && user=$GIST_USER | |
[[ -z $user ]] && user=`whoami` | |
token=`git config gist.token` | |
[[ -z $token ]] && token=$GIST_TOKEN | |
repo= | |
rest= | |
op= | |
verbosity=0 | |
desc= | |
cmdout= | |
err= | |
metadata= | |
verbose() { | |
level=$1 | |
shift | |
msg="$@" | |
(( $verbosity >= $level )) && echo $msg | |
return 0 | |
} | |
info() { | |
verbose 0 $@ | |
} | |
error() { | |
info "error: $@" && return 0 | |
} | |
warn() { | |
info "warning: $@" && return 0 | |
} | |
trace() { | |
verbose 1 "$@" | |
} | |
debug() { | |
local level=`expr $1 + 2` | |
shift | |
verbose $level "$@" | |
} | |
usage() { | |
local exe=`basename $0` | |
cat <<eom | |
gist bash cli | |
usage: $exe operation [-options] [files...] | |
operations: | |
help - this text | |
ls - lists files and repositories | |
put - create/update repository | |
rm - remove a repository | |
cat - prints the request files into stdout | |
metadata - prints raw metadata | |
options: | |
-h - this text | |
-v, -vv, -vvv... - increase verbosity | |
-r <repos> - specify repository | |
-u <user> - specify gist username | |
-t <token> - specify gist token | |
-d <description> - repository description for put command | |
notes: | |
default username is determined with the following priority: | |
1. specified by -u (HIGHEST) | |
2. content of \$GIST_USER | |
3. content of git config gist.user | |
4. \`whoami\` (LOWEST) | |
default token is determined with the following priority: | |
4. specified by -t (HIGHEST) | |
2. content of \$GIST_TOKEN | |
3. content of git config gist.token | |
examples: | |
$ $exe put -d "a neet file" file1 | |
creates a new repository with files file1 and file2 | |
$ $exe put -r 31337 -d "two neet files" file1 file2 | |
updates repository 31337 so that it would have file1 and file2 | |
$ $exe ls | |
lists all files in all repositories | |
$ $exe ls -r 31337 | |
lists all files in repository 3133 | |
$ $exe ls -v | |
listal all files in all repositories along with the repository description | |
$ $exe cat -u testuser testfile.py | |
prints contents of file testfile.py (in any repository) for user testuser | |
$ $exe cat -r 31337 testfile.py | |
prints contents of file testfile.py that is in repository 31337 | |
$ $exe cat -r 31337 | |
prints contents of entrie repository 31337 | |
$ $exe metadata | |
prints metadata of gist in xml format | |
$ $exe metadata -r 31337 | |
prints metadata of repository 31337, subset of the entire user's metadata | |
$ $exe rm -r 31337 | |
remove a repository | |
eom | |
} | |
opts() { | |
if [[ ${1:0:1} != "-" ]]; then | |
op=$1 | |
OPTIND=2 | |
fi | |
while getopts "hu:r:t:d:v" opt; do | |
case $opt in | |
h) usage; exit 0;; | |
u) user=$OPTARG;; | |
t) token=$OPTARG;; | |
r) repo=$OPTARG;; | |
d) desc=$OPTARG;; | |
v) verbosity=`expr $verbosity + 1`;; | |
*) usage; exit 1;; | |
esac | |
done | |
shift `expr $OPTIND - 1` | |
rest=$* | |
if [[ -z $op ]]; then | |
error "operation must be specified" | |
return 1 | |
else | |
return 0 | |
fi | |
} | |
copyall() { | |
while read line; do echo $line; done | |
} | |
notags() { | |
copyall | sed -e "s/<[^>]*>/ /g" -e "s/ / /g" | |
} | |
xmlsel() { | |
copyall | xmlstarlet sel -t -c "$@" | |
} | |
execute_raw() { | |
cmd=$* | |
debug 0 -n "exec: $cmd" | |
echo $cmd > /tmp/.gist.$$ | |
source /tmp/.gist.$$ | |
rc=$? | |
rm -f /tmp/.gist.$$ | |
debug 0 -e "\x20-> $rc" | |
return $rc | |
} | |
execute() { | |
cmd=$* | |
debug 0 -n "exec: $cmd" | |
echo $cmd > /tmp/.gist.$$ | |
cmdout=`source /tmp/.gist.$$` | |
rc=$? | |
rm -f /tmp/.gist.$$ | |
debug 0 -e "\x20-> $rc" | |
return $rc | |
} | |
do_curl_api() { | |
do_curl "/api/v1/xml/$*" | |
return $? | |
} | |
do_curl() { | |
err= | |
execute "curl -s $URL_BASE$*" | |
debug 2 $cmdout | |
rc=$? | |
if (( $rc )); then | |
err="curl failed" | |
elif [[ ${cmdout:0:1} != "<" ]]; then | |
if [[ ${cmdout} == "error" ]]; then | |
err="general failure" | |
else | |
err="invalid format" | |
fi | |
return 1 | |
else | |
error=`echo $cmdout | xmlstarlet sel -t -c "error" | notags` | |
if [[ -n $error ]]; then | |
err=$error | |
return 1 | |
else | |
return 0 | |
fi | |
fi | |
} | |
download_metadata() { | |
[[ -z $metadata ]] && { | |
trace "downloading user gists metadata" | |
do_curl_api "gists/$user" | |
(( $? )) && error "download_metadata: $err" && return 1 | |
metadata=$cmdout | |
debug 2 $metadata | |
} | |
return 0 | |
} | |
repo_files() { | |
repo=$1 | |
echo $metadata | xmlsel "gists/gist[repo=${repo}]/files/file/file" | notags | |
return $? | |
} | |
repos_list() { | |
echo $metadata | xmlsel "gists/gist/repo" | notags | |
} | |
do_ls() { | |
do_ls_core | |
return $? | |
} | |
do_ls_core() { | |
download_metadata | |
(( $? )) && return 1 | |
local repos=$repo | |
[[ -z $repos ]] && repos=`repos_list` | |
for r in $repos; do | |
local files=`repo_files $r` | |
local fs=$files | |
[[ -n $rest ]] && { | |
fs= | |
for f in $files; do | |
local found=`echo " $rest " | grep -o " $f "` | |
[[ -n $found ]] && fs="${fs}${f} " | |
done | |
} | |
[[ -n $fs ]] && { | |
info -n "$r: $fs" | |
local d=`echo $metadata | xmlsel "gists/gist[repo=${r}]/description" | notags` | |
[[ -n $d ]] && trace -ne "\x20# $d" | |
info | |
} | |
done | |
return 0 | |
} | |
for_files() { | |
local action=$1 | |
[[ -z $rest && -z $repo ]] && error "no files or repository specified" && return 1 | |
download_metadata | |
(( $? )) && return 1 | |
[[ -z $rest ]] && { | |
rest=`repo_files $repo` | |
[[ -z $rest ]] && error "no files in repository" | |
} | |
for f in $rest; do | |
local lines=`do_ls_core | cut -d# -f1 | egrep "\<${f}\>"` | |
local n=`echo $lines | sed -e "s/[^:]//g" | wc -c` | |
if [[ $n -lt 2 ]]; then | |
warn "$f not found" | |
elif [[ $n -gt 2 ]]; then | |
warn "$f found in multiple repositories, specify -r to select repository" | |
else | |
local r=`echo $lines | cut -d: -f1` | |
$action $r $f | |
(( $? )) && return 1 | |
fi | |
done | |
return 0 | |
} | |
do_cat_fetch() { | |
local r=$1 | |
local f=$2 | |
trace "downloading $f from repository $r" | |
execute_raw "curl -s $URL_BASE/raw/$r/$f" | |
info | |
} | |
do_cat() { | |
for_files do_cat_fetch | |
} | |
do_rm() { | |
[[ -n $rest ]] && error "file names must not be specified" && exit 1 | |
[[ -z $repo ]] && error "repository must be specified" && exit 1 | |
[[ -z $token ]] && error "authentication token must be specified" && exit 1 | |
do_curl "/delete/$repo --include --data login=$user --data token=$token --data _method=delete" | |
return 0 | |
} | |
do_put() { | |
[[ -z $rest ]] && error "file names must be specified" && exit 1 | |
[[ -z $token ]] && error "authentication token must be specified" && exit 1 | |
local files_data= | |
local i=0 | |
for f in $rest; do | |
i=`expr $i + 1` | |
local ii="gistfile$i" | |
[[ ! -r $f ]] && error "file $f is not readable" && exit 1 | |
local name=`basename $f` | |
local ext=${name##*.} | |
[[ $ext == $name ]] && ext= | |
files_data="$files_data --data 'file_ext[$ii]=${ext}' --data 'file_name[$ii]=$name' --data-urlencode description=$desc --data-urlencode file_contents[$ii]@$f" | |
done | |
[[ -n $repo ]] && repo_url="/$repo" && method="--data _method=put" | |
do_curl "/gists${repo_url} --include $method --data 'login=$user' --data 'token=$token' --data 'action_button=public' $files_data" | |
repo=`echo $cmdout | egrep -o "Location: [^ ]*" | grep -o [0-9]*` | |
if [[ -z $repo ]]; then | |
error "failed" | |
else | |
info repository $repo | |
rest= | |
do_ls | |
fi | |
} | |
do_metadata() { | |
download_metadata | |
(( $? )) && return 1 | |
if [[ -z $repo ]]; then | |
info -e $metadata | xmlstarlet fo | |
else | |
info $metadata | xmlsel "gists/gist[repo=$repo]" | xmlstarlet fo | |
fi | |
return $? | |
} | |
act() { | |
rc=0 | |
case $op in | |
help) usage; rc=0;; | |
metadata) do_metadata; rc=$?;; | |
ls) do_ls; rc=$?;; | |
cat) do_cat; rc=$?;; | |
put) do_put; rc=$?;; | |
rm) do_rm; rc=$?;; | |
*) error "unrecognized operation $op"; rc=1;; | |
esac | |
return $rc | |
} | |
dump() { | |
debug 2 "parameters: op=${op}, user=${user}, token=${token}, repo=${repo}, rest=${rest}, verbosity=${verbosity}" | |
return 0 | |
} | |
main() { | |
opts "$@" && dump && act | |
return $? | |
} | |
main "$@" | |
exit $? |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment