From 0eb1e02b0647f08445b77a8969e62731d2a5bf14 Mon Sep 17 00:00:00 2001 From: typebrook Date: Tue, 4 Feb 2020 15:10:34 +0800 Subject: update --- gist | 185 +++++++++++++++++++++++++++++++++++++------------------------------ 1 file changed, 101 insertions(+), 84 deletions(-) diff --git a/gist b/gist index ee400fb..e9e5130 100755 --- a/gist +++ b/gist @@ -4,60 +4,42 @@ # License: MIT # https://gist.github.com/typebrook/b0d2e7e67aa50298fdf8111ae7466b56 # +# gist +# Description: Host your gists as local cloned git repo +# Usage: gist [command] [] # -# This script host your gists as local cloned git repo -# It works under GNU curl, which is easy to get in most cases +# [star | s] list your gists with format below, star for your starred gists: +# [index_of_gist] [url] [file_num] [comment_num] [short description] +# update, u [star | s] update the local list of your gists, star for your starred gists +# show the path of local gist repo and do custom actions +# new, n [-d | --desc ] ... create a new gist with files +# new, n [-d | --desc ] [-f | --file ] create a new gist from STDIN +# detail, d show the detail of a gist +# edit, e edit a gist description +# delete, D ... delete a gist +# clean, C clean removed gists in local +# config, c [token | user | folder | auto-sync | EDITOR | action [value] ] do configuration +# user, U get gists from a given Github user +# help, h show this help message # -# Use the following commands to manage your gists: -# -# * update the local list of your gists, star for your starred gists -# gist (update | u) [star | s] -# -# * list your gists with format: [number] [url] [file_num] [comment_num] [short description] -# gist [star | s] +# Example: +# gist (Show your gists) +# gist 3 (show the repo path of your 3rd gist, and do custom actions) # -# * show the path of local gist repo and files -# gist -# -# * create a new gist with files -# gist (new | n) [-d | --desc ""] ... -# -# * create a new gist with STDIN -# gist (new | n) [-d | --desc ""] [-f | --file ] < -# -# * show the detail of a gist -# gist (detail | d) -# -# * edit a gist description -# gist (edit | e) -# -# * delete a gist -# gist (delete | D) ... -# -# * clean removed gists in local -# gist (clean | C) -# -# * update a gist # Since now a gist is a local cloned repo # It is your business to do git commit and git push -# -# * configuration -# gist (config | c) [token|user|folder|auto-sync|EDITOR|action [value]] -# -# * show this help message -# gist (help | h) -# TODO parallel branch works with wget and other stuff -# TODO new command "user" to fetch other user's gists # TODO grep mode for description, file content # TODO push github.com (may need new token) # TODO description for current directory -# TODO error handling, unit test +# TODO unit test # TODO test on mac and remote machine # TODO completion # Shell configuration +set -o pipefail [ "$TRACE" ] && set -x +trap 'rm -f "$http_data" "tmp_file"' EXIT GITHUB_API=https://api.github.com CONFIG=~/.config/gist.conf; mkdir -p ~/.config @@ -134,17 +116,17 @@ _validate_config(){ # load configuration _apply_config() { - source $CONFIG && _validate_config + _validate_config "$@" || return 1 AUTH_HEADER="Authorization: token $token" - [[ -z "$action" ]] && action="${EDITOR:-vi} *" + [[ -z "$action" ]] && action="${EDITOR:-vi} ." [[ -z "$folder" ]] && folder=~/gist && mkdir -p $folder INDEX=$folder/index } _apply_config "$@" || exit 1 -## This function determines which http get tool the system has installed and returns an error if there isnt one +# This function determines which http get tool the system has installed and returns an error if there isnt one getConfiguredClient() { if command -v curl &>/dev/null; then configuredClient="curl" @@ -160,13 +142,20 @@ getConfiguredClient() { fi } -## Allows to call the users configured client without if statements everywhere -httpGet() { - local header="" +# Allows to call the users configured client without if statements everywhere +http_method() { + local METHOD=$1; shift case "$configuredClient" in - curl) [[ -n $token ]] && header="--header Authorization: token $token"; curl -A curl -s $header "$@" ;; - wget) [[ -n $token ]] && header="--header Authorization: token $token"; wget -qO- $header "$@" ;; - httpie) [[ -n $token ]] && header="Authorization:token $token"; http -b GET "$@" "$header";; + curl) [[ -n $token ]] && local extra="--header" local header="Authorization: token $token" + [[ $METHOD =~ (POST|PATCH) ]] && extra2="--data" + curl -X $METHOD -A curl -s $extra "$header" $extra2 @$http_data "$@" ;; + wget) [[ -n $token ]] && local extra="--header" local header="Authorization: token $token" + [[ $METHOD =~ (POST|PATCH) ]] && extra2='--body-file' + wget --method=$METHOD -qO- $extra "$header" $extra2 $http_data "$@" ;; + httpie) [[ -n $token ]] && header="Authorization:token $token" + [[ $METHOD =~ (POST|PATCH) ]] && extra2="@$http_data" + http -b $METHOD "$@" "$header" $extra2 ;; + # TODO add other methods fetch) fetch -q "$@" ;; esac } @@ -180,14 +169,11 @@ _show_list() { echo ' gist update' return 0 fi - local filter="" - if [[ $1 == "s" ]]; then - filter='/^[^s]/ d' - else - filter='/^s/ d' - fi - cat $INDEX \ - | while read index link blob_code file_num extra description; do + local filter='/^s/ d; /^$/ d' + [[ $1 == "s" ]] && filter='/^[^s]/ d; /^$/ d' + + while read index link blob_code file_num extra author description; do + [[ $1 == "s" ]] && local author=$author local repo=$folder/$(echo $link | sed 's#.*/##') local occupy=0 @@ -198,27 +184,30 @@ _show_list() { # if there is a commit not yet push, show red message "ahead" [[ -n $(cd $repo && git cherry) ]] 2>/dev/null && extra="\e[31m[ahead]\e[0m" && occupy=7 - echo -e $index $link $file_num $extra $(echo $description | cut -c -$(( 60 -$occupy -1 )) ) - done \ + echo -e $index $link $author $file_num $extra $(echo $description | cut -c -$(( 60 -$occupy -1 )) ) + done < $INDEX \ | sed "$filter" + echo -e '\nrun "gist help" for more details' } # parse JSON from STDIN with string of commands AccessJsonElement() { PYTHONIOENCODING=utf-8 \ - python -c "from __future__ import print_function; import sys, json; raw = json.load(sys.stdin); $1" 2> /dev/null + python -c "from __future__ import print_function; import sys, json; $1" return "$?" } # equal to: jq '.[] | "\(.html_url) \([.files[] | .raw_url]) \(.files | keys | length) \(.comments) \(.description)"' _handle_gists() { echo ' +raw = json.load(sys.stdin) for gist in raw: print(gist["html_url"], end=" ") print([file["raw_url"] for file in gist["files"].values()], end=" ") print(gist["public"], end=" ") print(len(gist["files"]), end=" ") print(gist["comments"], end=" ") + print(gist["owner"]["login"], end=" ") print(gist["description"]) ' } @@ -228,36 +217,48 @@ for gist in raw: _parse_response() { AccessJsonElement "$(_handle_gists)" \ | tac | sed 's/, /,/g' | nl -s' ' \ - | while read index link file_url_array public file_num comment_num description; do + | while read index link file_url_array public file_num comment_num author description; do local blob_code=$(echo $file_url_array | tr ',' '\n' | sed -E 's#.*raw/(.*)/.*#\1#' | sort | cut -c -7 | paste -sd '-') [[ $public == 'False' ]] && local mark=p [[ -n $1 ]] && local index=$1 - echo $mark$index $link $blob_code $file_num $comment_num $description | tr -d '"' + echo $mark$index $link $blob_code $file_num $comment_num $author $description | tr -d '"' done } +# TODO add author, files and date of a gist # get latest list of gists from Github API _update() { echo "fetching $user's gists from $GITHUB_API..." echo local route="users/$user/gists" local mark="" - local filter='/^[^s]/ d' + local filter='/^[^s]/ d; /^$/ d' if [[ "$1" =~ ^(star|s)$ ]];then route="gists/starred" mark="s" - filter='/^[s]/ d' + filter='/^[s]/ d; /^$/ d' fi - local response=$(httpGet $GITHUB_API/$route) - false && echo Failed to update gists && return 1 - sed -i "$filter" $INDEX - echo $response | _parse_response >> $INDEX + result=$(http_method GET $GITHUB_API/$route | _parse_response) + [[ -z $result ]] && echo Failed to update gists && return 1 + + sed -i "$filter" $INDEX && echo "$result" >> $INDEX _show_list $mark if [[ $auto_sync != "false" ]]; then (_sync_repos $1 > /dev/null 2>&1 &); fi } +_query_user() { + local route="users/$1/gists" + result=$(http_method GET $GITHUB_API/$route | _parse_response) + [[ -z $result ]] && echo Failed to update gists && return 1 + + echo "$result" \ + | while read index link blob_code file_num extra description; do + echo $link $file_num $extra $(echo $description | cut -c -70 ) + done +} + # update local git repos _sync_repos() { # clone repos which are not in the local @@ -312,7 +313,7 @@ _goto_gist() { _delete_gist() { for i in "$@"; do _gist_id "$i" - curl -X DELETE -s -H "$AUTH_HEADER" $GITHUB_API/gists/$GIST_ID \ + http_method DELETE $GITHUB_API/gists/$GIST_ID \ && echo "$i" deleted \ && sed -i -E "/^$i / d" $INDEX done @@ -330,6 +331,7 @@ _clean_repos() { # parse JSON from gist detail _handle_gist() { echo ' +raw = json.load(sys.stdin) print("site:", raw["html_url"]) print("description:", raw["description"]) print("public:", raw["public"]) @@ -345,6 +347,7 @@ for file in raw["files"].keys(): # equal to jq '.[] | {user: .user.login, created_at: .created_at, updated_at: .updated_at, body: .body}' _handle_comment() { echo ' +raw = json.load(sys.stdin); for comment in raw: print() print("|", "user:", comment["user"]["login"]) @@ -357,16 +360,16 @@ for comment in raw: # TODO format with simple text _show_detail() { _gist_id $1 - httpGet $GITHUB_API/gists/$GIST_ID \ + http_method GET $GITHUB_API/gists/$GIST_ID \ | AccessJsonElement "$(_handle_gist)" - httpGet $GITHUB_API/gists/$GIST_ID/comments \ + http_method GET $GITHUB_API/gists/$GIST_ID/comments \ | AccessJsonElement "$(_handle_comment)" } # set filename/description/permission for a new gist _set_gist() { - public=true + public=True while [[ -n "$@" ]]; do case $1 in -d | --desc) description="$2" @@ -375,7 +378,7 @@ _set_gist() { filename="$2" shift; shift;; -p) - public=false + public=False shift;; *) files="$1 $files" @@ -388,7 +391,7 @@ _set_gist() { # Let user type the content of gist before setting filename _new_file() { [[ -t 0 ]] && echo "Type a gist. to cancel, when done" > /dev/tty - local tmp_file=$(mktemp) + tmp_file=$(mktemp) cat > $tmp_file echo -e '\n' > /dev/tty [[ -z "$1" ]] && read -p 'Type file name: ' filename < /dev/tty @@ -396,22 +399,33 @@ _new_file() { echo /tmp/$filename } +_gist_body(){ + echo " +import os.path +files_json = {} +files = sys.stdin.readline().split() +description = sys.stdin.readline().replace('\n','') +for file in files: + with open(file, 'r') as f: + files_json[os.path.basename(file)] = {'content': f.read()} +print(json.dumps({'public': $public, 'files': files_json, 'description': description})) + " +} + # create a new gist with files _create_gist() { _set_gist "$@" || return 1 [[ -z "$files" ]] && files=$(_new_file $filename) [[ -z "$description" ]] && read -p 'Type description: ' description < /dev/tty - local index=$(( $(sed '/^s/ d' $INDEX | wc -l) +1 )) echo 'Creating a new gist...' - for file in $files; do - echo "\"$(basename $file)\": {\"content\": \"$(sed '$ !s/$/\\n/' $file)\"}," - done | tr -d '\n' | sed 's/^/{/; s/,$/}/' \ - | echo "{ \"public\": $public, \"files\": $(cat -), \"description\": \"$description\"}" \ - | curl -s -H "$AUTH_HEADER" --data @- $GITHUB_API/gists \ - | tee jojo \ + http_data=$(mktemp) + + echo -e "$files\n$description" \ + | AccessJsonElement "$(_gist_body)" > $http_data \ + && http_method POST $GITHUB_API/gists \ | sed '1 s/^/[/; $ s/$/]/' \ - | _parse_response $index >> $INDEX + | _parse_response $(( $(sed '/^s/ d' $INDEX | wc -l) +1 )) >> $INDEX if [[ $? -eq 0 ]]; then echo 'Gist is created' @@ -428,12 +442,12 @@ _edit_gist() { echo -n 'Type new description: ' read DESC < /dev/tty echo "{ \"description\": \"$DESC\" }" \ - | curl -X PATCH -H "$AUTH_HEADER" --data @- $GITHUB_API/gists/$GIST_ID > /dev/null \ + | http_method PATCH $GITHUB_API/gists/$GIST_ID > /dev/null \ && _update } usage() { - sed -E -n ' /^$/ q; 8,$ s/^#//p' $0 + sed -E -n ' /^$/ q; 7,$ s/^#//p' $0 } getConfiguredClient @@ -462,6 +476,9 @@ case "$1" in config | c) shift _configure "$@" ;; + user | U) + shift + _query_user "$@" ;; help | h) usage ;; *) -- cgit v1.2.3-70-g09d2