From 507e32d7f867db0c44d6f20adae6d30b15eb9584 Mon Sep 17 00:00:00 2001 From: typebrook Date: Mon, 27 Jan 2020 23:28:00 +0800 Subject: update --- gist | 182 +++++++++++++++++++++++++++++++++++++------------------------------ 1 file changed, 100 insertions(+), 82 deletions(-) diff --git a/gist b/gist index da30e4b..f0816e5 100755 --- a/gist +++ b/gist @@ -45,10 +45,12 @@ # 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 ] +# # * show this help message # gist (help | h) -# TODO pipe syntax fix # TODO error handling, unit test # TODO parallel branch works with json parsing on python # TODO parallel branch works with wget and other stuff @@ -56,35 +58,41 @@ # Validate settings. config=~/.config/gistrc +set -eo pipefail [ "$TRACE" ] && set -x # TODO error handling while password is not true +# TODO support access token from input or web _auth() { - data="{\"scopes\":[\"gist\"], \"note\": \"gist-$(date -u +'%Y-%m-%dT%H:%M:%SZ')\"}" - read -p "Github username: " user - read -sp "Github password: " password + local data="{\"scopes\":[\"gist\"], \"note\": \"gist-$(date -u +'%Y-%m-%dT%H:%M:%SZ')\"}" + read -p "Github username: " user < /dev/tty + read -sp "Github password: " password < /dev/tty mkdir -p ~/.config && umask 0077 && echo user=$user > $config - curl https://api.github.com/authorizations \ + curl -i https://api.github.com/authorizations \ --user "$user:$password" \ - --data "$data" > /dev/null + --data "$data" - read -p "2-factor code: " OTP + read -p "2-factor code: " OTP < /dev/tty curl https://api.github.com/authorizations \ --user "$user:$password" -H "X-GitHub-OTP: $OTP" \ - --data "$data" |\ - sed '1 s/[^{]//g' | jq -r .token |\ - sed 's/^/token=/' >> $config + --data "$data" \ + | sed '1 s/[^{]//g' | jq -r .token \ + | sed 's/^/token=/' >> $config } -while ! source $config; do - _auth -done +case "$1" in + config | c) ;; + *) + while ! source $config 2> /dev/null || [[ -z "$token" ]] || [[ -z "$user" ]]; do + _auth + done;; +esac github_api=https://api.github.com auth_header="Authorization: token $token" -[[ -z "$folder" ]] && folder=~/git/gist +[[ -z "$folder" ]] && folder=~/gist mkdir -p $folder index=$folder/index starred=$folder/starred @@ -99,96 +107,105 @@ _show_list() { echo " gist update" exit 0 fi - cat $1 |\ - while read line_num link file_url_array file_num extra description; do - repo=$folder/$(echo $link | sed 's#.*/##') + cat $1 \ + | while read line_num link file_url_array file_num extra description; do + local repo=$folder/$(echo $link | sed 's#.*/##') + local occupy=0 + + # if repo is not yet cloned, show green message "Not cloned yet" + [[ ! -d $repo ]] && extra="\e[32m[Not cloned yet]\e[0m" && occupy=17 - # if repo is not yet cloned, show green message "Sync Now" - cd $repo 2>/dev/null || extra="\e[32m[Sync Now]\e[0m" # if there are some changes in git index or working directory, show blue message "working" - [[ -n $(git status --short) ]] 2>/dev/null && extra="\e[36m[working]\e[0m" + [[ -n $(cd $repo && git status --short) ]] 2>/dev/null && extra="\e[36m[working]\e[0m" && occupy=10 # if there is a commit not yet push, show red message "ahead" - [[ -n $(git cherry) ]] 2>/dev/null && extra="\e[31m[ahead]\e[0m" + [[ -n $(cd $repo && git cherry) ]] 2>/dev/null && extra="\e[31m[ahead]\e[0m" && occupy=8 - echo -e $line_num $link $file_num $extra $(echo $description | cut -c -60) + echo -e $line_num $link $file_num $extra $(echo $description | cut -c -$(( 60 - $occupy )) ) done } # get the list of gists -# TODO support secret gist _update() { echo "fetching from api.github.com..." echo - list_file=$index - route="users/$user/gists" - mark="" + local list_file=$index + local route="users/$user/gists" + local mark="" [[ "$1" =~ ^(star|s)$ ]] && list_file=$starred && route="gists/starred" && mark="s" - curl -s -H "$auth_header" $github_api/$route |\ - _parse_response | nl -s' ' | sed -E "s/^ */$mark/" > $list_file && \ - _show_list $list_file + curl -s -H "$auth_header" $github_api/$route \ + | _parse_response | nl -s' ' | sed -E "s/^ */$mark/" > $list_file \ + && _show_list $list_file \ + || echo Fail to update gists + if [[ $auto_sync != "false" ]]; then (_sync_repos $1 > /dev/null 2>&1 &); fi } # TODO check if a user create a very first gist _parse_response() { - jq '.[] | "\(.html_url) \([.files[] | .raw_url]) \(.files | keys | length) \(.comments) \(.description)"' |\ - tac |\ - while read link file_url_array file_num comment_num description; do - blob_code=$(echo $file_url_array | jq -r '.[]' | sed -E 's#.*raw/(.*)/.*#\1#' | sort | cut -c -7 | paste -sd '-') + jq '.[] | "\(.html_url) \([.files[] | .raw_url]) \(.files | keys | length) \(.comments) \(.description)"' \ + | tac \ + | while read link file_url_array file_num comment_num description; do + local blob_code=$(echo $file_url_array | jq -r '.[]' | sed -E 's#.*raw/(.*)/.*#\1#' | sort | cut -c -7 | paste -sd '-') echo $link $blob_code $file_num $comment_num $description | tr -d '"' done } _sync_repos() { - list_file=$index - [[ "$1" == "--star" ]] && list_file=$starred && route="gists/starred" + local list_file=$index + [[ "$1" =~ ^(star|s)$ ]] && list_file=$starred && route="gists/starred" # clone repos which are not in the local comm -13 <(find $folder -maxdepth 1 -type d | sed '1d; s#.*/##' | sort) \ - <(cat $list_file | cut -d' ' -f2 | sed 's#.*/##' | sort) |\ - xargs -I{} git clone git@github.com:{}.git $folder/{} + <(cat $list_file | cut -d' ' -f2 | sed 's#.*/##' | sort) \ + | xargs -I{} git clone git@github.com:{}.git $folder/{} # pull if remote repo has different blob objects - cat $index | cut -d' ' -f2,3 |\ - while read url blob_code_remote; do - repo=$folder/$(echo $url | sed 's#.*/##') - blob_code_local=$(cd $repo && git ls-tree master | cut -d' ' -f3 | cut -c-7 | sort | paste -sd '-') - - cd $repo && \ - [[ $blob_code_local != $blob_code_remote ]] && \ - [[ $(git rev-parse origin/master) == $(git rev-parse master) ]] && \ - git pull + cat $index | cut -d' ' -f2,3 \ + | while read url blob_code_remote; do + local repo=$folder/$(echo $url | sed 's#.*/##') + local blob_code_local=$(cd $repo && git ls-tree master | cut -d' ' -f3 | cut -c-7 | sort | paste -sd '-') + cd $repo \ + && [[ $blob_code_local != $blob_code_remote ]] \ + &&[[ $(git rev-parse origin/master) == $(git rev-parse master) ]] \ + && git pull done echo Everything is fine! } _gist_id() { - GIST_ID=$(cat $index $starred | sed -n "/^$1 / p" | cut -d' ' -f2 | sed -E 's#.*/##') + GIST_ID=$(cat $index $starred 2> /dev/null | sed -n "/^$1 / p" | cut -d' ' -f2 | sed -E 's#.*/##') if [[ -z "$GIST_ID" ]]; then echo -e "Not a valid index: \e[31m$1\e[0m" echo Use the index number in the first column instead: echo - _show_list "$index $starred" + _show_list "$index" exit 1 fi } -# FIXME error handling, if repo not cloned yet _goto_gist() { _gist_id $1 + + if [[ ! -d $folder/$GIST_ID ]]; then + echo 'Cloning gist as repo...' + git clone git@github.com:$GIST_ID.git $folder/$GIST_ID \ + && echo 'Repo is cloned' \ + || echo 'Failed to clone the gist' + fi + echo This gist is at $folder/$GIST_ID echo -e "You can run the following command to jump to this directory: \n" - echo -e " \e[32m. gist $1\e[0m" - echo + echo -e " \e[32m. gist $1\e[0m\n" cd $folder/$GIST_ID && ls && tig --all 2> /dev/null } +# TODO only remove deleted line _delete_gist() { for i in "$@"; do _gist_id "$i" - curl -X DELETE -s -H "$auth_header" $github_api/gists/$GIST_ID && \ - echo "$i" deleted + curl -X DELETE -s -H "$auth_header" $github_api/gists/$GIST_ID \ + && echo "$i" deleted done _update } @@ -196,8 +213,8 @@ _delete_gist() { # remove repos which are not in user gists anymore _clean_repos() { comm -23 <(find $folder -maxdepth 1 -type d | sed '1d; s#.*/##' | sort) \ - <(cat $index | cut -d' ' -f2 | sed 's#.*/##' | sort) |\ - while read dir; do + <(cat $index $starred 2> /dev/null | cut -d' ' -f2 | sed 's#.*/##' | sort) \ + | while read dir; do mv $folder/$dir /tmp && echo move $folder/$dir to /tmp done } @@ -205,11 +222,11 @@ _clean_repos() { # TODO format with simple text _show_detail() { _gist_id $1 - curl -s -H "$auth_header" $github_api/gists/$GIST_ID |\ - jq '{site: .html_url, description: .description, public: .public, API: .url, created_at: .created_at, updated_at: .updated_at, files: (.files | keys)}' + curl -s $github_api/gists/$GIST_ID \ + | jq '{site: .html_url, description: .description, public: .public, API: .url, created_at: .created_at, updated_at: .updated_at, files: (.files | keys)}' - curl -s -H "$auth_header" $github_api/gists/$GIST_ID/comments |\ - jq '.[] | {user: .user.login, created_at: .created_at, updated_at: .updated_at, body: .body}' + curl -s $github_api/gists/$GIST_ID/comments \ + | jq '.[] | {user: .user.login, created_at: .created_at, updated_at: .updated_at, body: .body}' } _set_gist() { @@ -223,6 +240,7 @@ _set_gist() { esac done if [[ "$1" == '--' ]]; then shift; fi + # TODO could be simplified? files="$@" && echo $files | xargs ls > /dev/null || exit 1 } @@ -231,32 +249,34 @@ _new_file() { tmp_file=$(mktemp) cat > $tmp_file echo -e '\n' > /dev/tty - [[ -z "$1" ]] && echo -n 'Type file name: ' > /dev/tty && read filename + [[ -z "$1" ]] && read -p 'Type file name: ' filename < /dev/tty mv $tmp_file /tmp/$filename echo /tmp/$filename } # create a new gist with files -# FIXME error handling if gist is not created, file doesn't exist +# TODO support secret gist _create_gist() { _set_gist "$@" [[ -z "$files" ]] && files=$(_new_file $filename) - [[ -z "$description" ]] && echo -n 'Type description: ' && read description + [[ -z "$description" ]] && read -p 'Type description: ' description < /dev/tty for file in $files; do FILE=$(basename $file) jq --arg FILE "$FILE" '. as $content | { ($FILE): {content: $content} }' -Rs $file - done |\ - jq --slurp --arg DESC "$description" '{ + done \ + | jq --slurp --arg DESC "$description" '{ public: true, files: add, description: ($DESC) - }' |\ - curl -H "$auth_header" --data @- $github_api/gists |\ - sed '1 s/^/[/; $ s/$/]/' |\ - _parse_response |\ - sed -E "s/^/$(( $(wc -l $index | cut -d' ' -f1) + 1 )) /" >> $index && \ - echo -e '\nGist created' + }' \ + | curl -s -H "$auth_header" --data @- $github_api/gists \ + | sed '1 s/^/[/; $ s/$/]/' \ + | _parse_response \ + | sed -E "s/^/$(( $(wc -l $index | cut -d' ' -f1) + 1 )) /" >> $index \ + && echo -e '\nGist created' \ + || echo 'Fail to create gist' + _show_list $index | tail -1 } @@ -265,10 +285,10 @@ _edit_gist() { _gist_id $1 echo -n 'Type new description: ' - read DESC - jq -n --arg DESC "$DESC" '{ description: ($DESC) }' |\ - curl -X PATCH -H "$auth_header" --data @- $github_api/gists/$GIST_ID > /dev/null && \ - _update + read DESC < /dev/tty + jq -n --arg DESC "$DESC" '{ description: ($DESC) }' \ + | curl -X PATCH -H "$auth_header" --data @- $github_api/gists/$GIST_ID > /dev/null \ + && _update } _help_message() { @@ -277,20 +297,19 @@ _help_message() { _cases() { if [[ $1 == 'token' ]]; then - [[ ${#2} -eq 40 ]] && echo token=$2 ||\ - echo Invalid token format, it is not 40 chars '\n' > /dev/tty + [[ ${#2} -eq 40 ]] && echo $1=$2 \ + || echo -e Invalid token format, it is not 40 chars '\n' > /dev/tty elif [[ $1 == 'auto_sync' ]]; then - [[ $2 == 'false' ]] && echo $1=$2 ||\ - echo $1=true + [[ $2 == 'false' ]] && echo $1=$2 \ + || echo $1=true elif [[ $1 == 'folder' ]]; then - [[ -n "$2" ]] && echo $1=$2 ||\ - echo $1=~/gist + [[ -n "$2" ]] && echo $1=$2 \ + || echo $1=~/gist elif [[ $1 == 'user' ]]; then echo $1=$2 fi } -# TODO consider the case that $2 is empty -> remove original setting _configure() { [[ -z "$@" ]] && (vim $config) && exit 0 target=$(_cases "$@") @@ -299,7 +318,6 @@ _configure() { cat $config } - case "$1" in "") _show_list $index ;; -- cgit v1.2.3-70-g09d2