diff options
| -rwxr-xr-x | gist | 251 |
1 files changed, 138 insertions, 113 deletions
| @@ -8,7 +8,7 @@ | |||
| 8 | # Description: Manage your gists with git and Github API v3 | 8 | # Description: Manage your gists with git and Github API v3 |
| 9 | # Usage: gist [command] [<args>] | 9 | # Usage: gist [command] [<args>] |
| 10 | # | 10 | # |
| 11 | # [star | s] List your gists with format below, star for your starred gists: | 11 | # [star | s] List your gists with format below, star for your starred gists: |
| 12 | # [index_of_gist] [url] [file_num] [comment_num] [short description] | 12 | # [index_of_gist] [url] [file_num] [comment_num] [short description] |
| 13 | # fetch, f [star | s] Update the local list of your gists, star for your starred gists | 13 | # fetch, f [star | s] Update the local list of your gists, star for your starred gists |
| 14 | # <index_of_gist> [--no-action] Show the path of local gist repo and do custom actions | 14 | # <index_of_gist> [--no-action] Show the path of local gist repo and do custom actions |
| @@ -18,7 +18,7 @@ | |||
| 18 | # edit, e <index_of_gist> Edit a gist's description | 18 | # edit, e <index_of_gist> Edit a gist's description |
| 19 | # delete, D <index_of_gist>... Delete a gist | 19 | # delete, D <index_of_gist>... Delete a gist |
| 20 | # clean, C Clean removed gists in local | 20 | # clean, C Clean removed gists in local |
| 21 | # config, c [token | user | folder | auto_sync | EDITOR | action [value] ] Do configuration | 21 | # config, c [token | user | folder | auto_sync | EDITOR | action | protocol [value] ] Do configuration |
| 22 | # user, U <user> Get gists from a given Github user | 22 | # user, U <user> Get gists from a given Github user |
| 23 | # grep, g <pattern> Grep gists by a given pattern | 23 | # grep, g <pattern> Grep gists by a given pattern |
| 24 | # push, p <index_of_gist> Push changes by git (well, better to make commit by youself) | 24 | # push, p <index_of_gist> Push changes by git (well, better to make commit by youself) |
| @@ -45,8 +45,10 @@ CONFIG=~/.config/gist.conf; mkdir -p ~/.config | |||
| 45 | 45 | ||
| 46 | folder=~/gist && mkdir -p $folder | 46 | folder=~/gist && mkdir -p $folder |
| 47 | action="${EDITOR:-vi} ." | 47 | action="${EDITOR:-vi} ." |
| 48 | auto_sync=true # automatically clone the gist repo | ||
| 49 | [[ -z $hint ]] && hint=true # default to show hint with list of gist | 48 | [[ -z $hint ]] && hint=true # default to show hint with list of gist |
| 49 | [[ -z $confirm ]] && confirm=true # default to confirm when deleting gists | ||
| 50 | auto_sync=true # automatically clone the gist repo | ||
| 51 | protocol=https | ||
| 50 | 52 | ||
| 51 | # Shell configuration | 53 | # Shell configuration |
| 52 | set -o pipefail | 54 | set -o pipefail |
| @@ -72,16 +74,17 @@ getConfiguredClient() { | |||
| 72 | # TODO return false if code is not 20x | 74 | # TODO return false if code is not 20x |
| 73 | http_method() { | 75 | http_method() { |
| 74 | local METHOD=$1; shift | 76 | local METHOD=$1; shift |
| 77 | local header_opt; local header; local data_opt | ||
| 75 | case "$configuredClient" in | 78 | case "$configuredClient" in |
| 76 | curl) [[ -n $token ]] && local extra="--header" local header="Authorization: token $token" | 79 | curl) [[ -n $token ]] && header_opt="--header" header="Authorization: token $token" |
| 77 | [[ $METHOD =~ (POST|PATCH) ]] && extra2="--data" | 80 | [[ $METHOD =~ (POST|PATCH) ]] && data_opt='--data' |
| 78 | curl -X $METHOD -A curl -s $extra "$header" $extra2 @$http_data "$@" ;; | 81 | curl -X "$METHOD" -A curl -s $header_opt "$header" $data_opt "@$http_data" "$@" ;; |
| 79 | wget) [[ -n $token ]] && local extra="--header" local header="Authorization: token $token" | 82 | wget) [[ -n $token ]] && header_opt="--header" header="Authorization: token $token" |
| 80 | [[ $METHOD =~ (POST|PATCH) ]] && extra2='--body-file' | 83 | [[ $METHOD =~ (POST|PATCH) ]] && data_opt='--body-file' |
| 81 | wget --method=$METHOD -qO- $extra "$header" $extra2 $http_data "$@" ;; | 84 | wget --method="$METHOD" -qO- $header_opt "$header" $data_opt "$http_data" "$@" ;; |
| 82 | httpie) [[ -n $token ]] && header="Authorization:token $token" | 85 | httpie) [[ -n $token ]] && header="Authorization:token $token" |
| 83 | [[ $METHOD =~ (POST|PATCH) ]] && extra2="@$http_data" | 86 | [[ $METHOD =~ (POST|PATCH) ]] && data_opt="@$http_data" |
| 84 | http -b $METHOD "$@" "$header" $extra2 ;; | 87 | http -b "$METHOD" "$@" "$header" "$data_opt" ;; |
| 85 | esac | 88 | esac |
| 86 | } | 89 | } |
| 87 | 90 | ||
| @@ -116,7 +119,7 @@ update() { | |||
| 116 | echo "Error: no active internet connection" >&2 | 119 | echo "Error: no active internet connection" >&2 |
| 117 | exit 1 | 120 | exit 1 |
| 118 | else | 121 | else |
| 119 | if [[ $latestVersion != $currentVersion ]]; then | 122 | if [[ $latestVersion != "$currentVersion" ]]; then |
| 120 | echo "Version $latestVersion available" | 123 | echo "Version $latestVersion available" |
| 121 | echo -n "Do you wish to update $repositoryName [Y/n]: " | 124 | echo -n "Do you wish to update $repositoryName [Y/n]: " |
| 122 | read -r answer | 125 | read -r answer |
| @@ -124,6 +127,7 @@ update() { | |||
| 124 | cd ~ || { echo 'Update Failed'; exit 1; } | 127 | cd ~ || { echo 'Update Failed'; exit 1; } |
| 125 | if [[ -d ~/$repositoryName ]]; then rm -r -f $repositoryName || { echo "Permissions Error: try running the update as sudo"; exit 1; } ; fi | 128 | if [[ -d ~/$repositoryName ]]; then rm -r -f $repositoryName || { echo "Permissions Error: try running the update as sudo"; exit 1; } ; fi |
| 126 | echo -n "Downloading latest version of: $repositoryName." | 129 | echo -n "Downloading latest version of: $repositoryName." |
| 130 | # shellcheck disable=SC2015 | ||
| 127 | git clone -q "https://github.com/$githubUserName/$repositoryName" && touch .BSnippetsHiddenFile || { echo "Failure!"; exit 1; } & | 131 | git clone -q "https://github.com/$githubUserName/$repositoryName" && touch .BSnippetsHiddenFile || { echo "Failure!"; exit 1; } & |
| 128 | while [ ! -f .BSnippetsHiddenFile ]; do { echo -n "."; sleep 2; };done | 132 | while [ ! -f .BSnippetsHiddenFile ]; do { echo -n "."; sleep 2; };done |
| 129 | rm -f .BSnippetsHiddenFile | 133 | rm -f .BSnippetsHiddenFile |
| @@ -145,9 +149,9 @@ update() { | |||
| 145 | 149 | ||
| 146 | # handle configuration cases | 150 | # handle configuration cases |
| 147 | _configure() { | 151 | _configure() { |
| 148 | [[ -z $@ ]] && (${EDITOR:-vi} $CONFIG) && return 0 | 152 | [[ $# == 0 ]] && (${EDITOR:-vi} "$CONFIG") && return 0 |
| 149 | 153 | ||
| 150 | local valid_keys='user|token|folder|auto_sync|EDITOR|action' | 154 | local valid_keys='user|token|folder|auto_sync|EDITOR|action|protocol' |
| 151 | if [[ $1 =~ ^($valid_keys)$ ]]; then | 155 | if [[ $1 =~ ^($valid_keys)$ ]]; then |
| 152 | if [[ $1 == 'user' ]]; then | 156 | if [[ $1 == 'user' ]]; then |
| 153 | [[ -z $2 ]] && echo "Must specify username" >&2 && return 1 | 157 | [[ -z $2 ]] && echo "Must specify username" >&2 && return 1 |
| @@ -156,50 +160,53 @@ _configure() { | |||
| 156 | && return 1 | 160 | && return 1 |
| 157 | elif [[ $1 == 'auto_sync' ]]; then | 161 | elif [[ $1 == 'auto_sync' ]]; then |
| 158 | [[ ! $2 =~ ^(true|false)$ ]] && return 1 | 162 | [[ ! $2 =~ ^(true|false)$ ]] && return 1 |
| 163 | elif [[ $1 == 'protocol' ]]; then | ||
| 164 | [[ ! $2 =~ ^(https|ssh)$ ]] && return 1 | ||
| 159 | fi | 165 | fi |
| 160 | local key=$1 && shift && local target=$key=\'$@\' | 166 | local key=$1 && shift && local target=$key="'$*'" |
| 161 | else | 167 | else |
| 162 | echo "Not a valid key for configuration, use <$valid_keys> instead." | 168 | echo "Not a valid key for configuration, use <$valid_keys> instead." |
| 163 | return 1 | 169 | return 1 |
| 164 | fi | 170 | fi |
| 165 | 171 | ||
| 166 | umask 0077 && touch $CONFIG | 172 | umask 0077 && touch "$CONFIG" |
| 167 | sed -i'' -e "/^$key=/ d" $CONFIG && [[ -n $target ]] && echo $target >> $CONFIG | 173 | sed -i'' -e "/^$key=/ d" "$CONFIG" && [[ -n $target ]] && echo "$target" >> "$CONFIG" |
| 168 | cat $CONFIG | 174 | cat "$CONFIG" |
| 169 | } | 175 | } |
| 170 | 176 | ||
| 171 | # prompt for username | 177 | # prompt for username |
| 172 | _ask_username() { | 178 | _ask_username() { |
| 173 | while [[ ! $user =~ ^[[:alnum:]]+$ ]]; do | 179 | while [[ ! $user =~ ^[[:alnum:]]+$ ]]; do |
| 174 | [[ -n $user ]] && echo "Not a valid username" | 180 | [[ -n $user ]] && echo "Not a valid username" |
| 175 | read -p "Github username: " user < /dev/tty | 181 | read -r -p "Github username: " user < /dev/tty |
| 176 | done | 182 | done |
| 177 | _configure user $user | 183 | _configure user "$user" |
| 178 | } | 184 | } |
| 179 | 185 | ||
| 180 | # prompt for token | 186 | # prompt for token |
| 181 | # TODO check token scope contains gist, ref: https://developer.github.com/v3/apps/oauth_applications/#check-a-token | 187 | # TODO check token scope contains gist, ref: https://developer.github.com/v3/apps/oauth_applications/#check-a-token |
| 182 | _ask_token() { | 188 | _ask_token() { |
| 183 | echo -n "Create a new token from web browser? [Y/n] " | 189 | echo -n "Create a new token from web browser? [Y/n] " |
| 184 | read answer < /dev/tty | 190 | read -r answer < /dev/tty |
| 185 | if [[ ! $answer =~ ^(N|n|No|NO|no)$ ]]; then | 191 | if [[ ! $answer =~ ^(N|n|No|NO|no)$ ]]; then |
| 186 | python -mwebbrowser https://github.com/settings/tokens/new\?scopes\=gist | 192 | python -mwebbrowser https://github.com/settings/tokens/new?scopes=gist |
| 187 | fi | 193 | fi |
| 188 | 194 | ||
| 189 | while [[ ! $token =~ ^[[:alnum:]]{40}$ ]]; do | 195 | while [[ ! $token =~ ^[[:alnum:]]{40}$ ]]; do |
| 190 | [[ -n $token ]] && echo "Not a valid token" | 196 | [[ -n $token ]] && echo "Not a valid token" |
| 191 | read -p "Paste your token here (Ctrl-C to skip): " token < /dev/tty | 197 | read -r -p "Paste your token here (Ctrl-C to skip): " token < /dev/tty |
| 192 | done | 198 | done |
| 193 | _configure token $token | 199 | _configure token "$token" |
| 194 | } | 200 | } |
| 195 | 201 | ||
| 196 | # check configuration is fine with user setting | 202 | # check configuration is fine with user setting |
| 197 | _validate_config(){ | 203 | _validate_config(){ |
| 198 | source $CONFIG 2> /dev/null | 204 | # shellcheck source=/dev/null |
| 205 | source "$CONFIG" 2> /dev/null | ||
| 199 | [[ $1 =~ ^(c|config|h|help|u|user|update|version) ]] && return 0 | 206 | [[ $1 =~ ^(c|config|h|help|u|user|update|version) ]] && return 0 |
| 200 | if [[ -z $user ]]; then | 207 | if [[ -z $user ]]; then |
| 201 | echo 'Hi fellow! To access your gists, I need your Github username' | 208 | echo 'Hi fellow! To access your gists, I need your Github username' |
| 202 | echo "Also a personal token with scope which allows "gist"!'" | 209 | echo "Also a personal token with scope which allows \"gist\"!" |
| 203 | echo | 210 | echo |
| 204 | _ask_username && _ask_token && init=true | 211 | _ask_username && _ask_token && init=true |
| 205 | elif [[ -z $token && $1 =~ ^(n|new|e|edit|D|delete)$ ]]; then | 212 | elif [[ -z $token && $1 =~ ^(n|new|e|edit|D|delete)$ ]]; then |
| @@ -218,32 +225,31 @@ _validate_config(){ | |||
| 218 | # load configuration | 225 | # load configuration |
| 219 | _apply_config() { | 226 | _apply_config() { |
| 220 | _validate_config "$@" || return 1 | 227 | _validate_config "$@" || return 1 |
| 221 | |||
| 222 | AUTH_HEADER="Authorization: token $token" | ||
| 223 | INDEX=$folder/index; [[ -e $INDEX ]] || touch $INDEX | 228 | INDEX=$folder/index; [[ -e $INDEX ]] || touch $INDEX |
| 224 | } | 229 | } |
| 225 | 230 | ||
| 226 | _check_repo_status() { | 231 | _check_repo_status() { |
| 227 | if [[ ! -d $1 ]]; then | 232 | if [[ ! -d $1 ]]; then |
| 228 | if [[ $auto_sync == 'true' ]]; then | 233 | if [[ $auto_sync == 'true' ]]; then |
| 229 | echo "\e[32m[cloning]\e[0m"; | 234 | echo "\e[32m[cloning]\e[0m"; |
| 230 | else | 235 | else |
| 231 | echo "\e[32m[Not cloned yet]\e[0m"; | 236 | echo "\e[32m[Not cloned yet]\e[0m"; |
| 232 | fi | 237 | fi |
| 233 | else | 238 | else |
| 234 | cd $1 | 239 | cd "$1" || exit |
| 235 | if [[ -n $(git status --short) ]] &>/dev/null; then | 240 | if [[ -n $(git status --short) ]] &>/dev/null; then |
| 236 | echo "\e[36m[working]\e[0m" | 241 | echo "\e[36m[working]\e[0m" |
| 237 | else | 242 | else |
| 238 | [[ $(_blob_code $1) != $2 ]] 2>/dev/null && echo "\e[31m[outdated]\e[0m" | 243 | [[ $(_blob_code "$1") != "$2" ]] 2>/dev/null && echo "\e[31m[outdated]\e[0m" |
| 239 | [[ -n $(git cherry) ]] 2>/dev/null && echo "\e[31m[ahead]\e[0m" | 244 | [[ -n $(git cherry) ]] 2>/dev/null && echo "\e[31m[ahead]\e[0m" |
| 240 | fi | 245 | fi |
| 241 | fi | 246 | fi |
| 242 | } | 247 | } |
| 243 | 248 | ||
| 244 | # Show the list of gist, but not updated time | 249 | # Show the list of gist, but not updated time |
| 250 | # show username for starred gist | ||
| 245 | _show_list() { | 251 | _show_list() { |
| 246 | if [[ ! -e $INDEX ]]; then | 252 | if [[ ! -e $INDEX ]]; then |
| 247 | echo 'No local file found for last update, please run command:' | 253 | echo 'No local file found for last update, please run command:' |
| 248 | echo ' gist update' | 254 | echo ' gist update' |
| 249 | return 0 | 255 | return 0 |
| @@ -252,14 +258,15 @@ _show_list() { | |||
| 252 | [[ $mark == 's' ]] && filter='/^ *[^ s]/ d; /^$/ d' | 258 | [[ $mark == 's' ]] && filter='/^ *[^ s]/ d; /^$/ d' |
| 253 | 259 | ||
| 254 | sed -e "$filter" $INDEX \ | 260 | sed -e "$filter" $INDEX \ |
| 255 | | while read index link blob_code file_num comment_num author description; do | 261 | | while read -r index link blob_code file_num comment_num author description; do |
| 256 | [[ $1 == "s" ]] && local name=$author | 262 | [[ $mark == 's' ]] && local name=$author |
| 257 | local repo=$folder/$(echo $link | sed 's#.*/##') | 263 | #local repo; repo=$folder/$(echo $link | sed 's#.*/##') |
| 258 | local extra=$(_check_repo_status $repo $blob_code) | 264 | local repo; repo=$folder/${link##*/} |
| 265 | local extra; extra=$(_check_repo_status "$repo" "$blob_code") | ||
| 259 | [[ -z $extra ]] && extra="$file_num $comment_num" | 266 | [[ -z $extra ]] && extra="$file_num $comment_num" |
| 260 | 267 | ||
| 261 | echo -e "$(printf "% 3s" $index)" $link $name $extra $description \ | 268 | echo -e "$(printf "% 3s" "$index") $link $name $extra $description" \ |
| 262 | | cut -c -$(tput cols) | 269 | | cut -c -"$(tput cols)" |
| 263 | done | 270 | done |
| 264 | 271 | ||
| 265 | [[ $hint == 'true' ]] && echo -e '\nrun "gist fetch" to update gists or "gist help" for more details' > /dev/tty \ | 272 | [[ $hint == 'true' ]] && echo -e '\nrun "gist fetch" to update gists or "gist help" for more details' > /dev/tty \ |
| @@ -268,20 +275,20 @@ _show_list() { | |||
| 268 | 275 | ||
| 269 | # TODO support filenames, file contents | 276 | # TODO support filenames, file contents |
| 270 | _grep_content() { | 277 | _grep_content() { |
| 271 | _show_list | grep -i $1 | 278 | _show_list | grep -i "$1" |
| 272 | } | 279 | } |
| 273 | 280 | ||
| 274 | # Open Github repository import page | 281 | # Open Github repository import page |
| 275 | _import_to_github() { | 282 | _import_to_github() { |
| 276 | _gist_id $1 | 283 | _gist_id "$1" |
| 277 | echo put the folowing URL into web page: | 284 | echo put the folowing URL into web page: |
| 278 | echo -n git@github.com:$GIST_ID.git | 285 | echo -n "git@github.com:$GIST_ID.git" |
| 279 | python -mwebbrowser https://github.com/new/import | 286 | python -mwebbrowser https://github.com/new/import |
| 280 | } | 287 | } |
| 281 | 288 | ||
| 282 | _push_to_remote() { | 289 | _push_to_remote() { |
| 283 | _gist_id $1 | 290 | _gist_id "$1" |
| 284 | cd $folder/$GIST_ID && git add . \ | 291 | cd "$folder/$GIST_ID" && git add . \ |
| 285 | && git commit --allow-empty-message -m '' && git push origin master | 292 | && git commit --allow-empty-message -m '' && git push origin master |
| 286 | } | 293 | } |
| 287 | 294 | ||
| @@ -296,24 +303,23 @@ for gist in raw: | |||
| 296 | print(gist["comments"], end=" ") | 303 | print(gist["comments"], end=" ") |
| 297 | print(gist["owner"]["login"], end=" ") | 304 | print(gist["owner"]["login"], end=" ") |
| 298 | print(gist["description"]) | 305 | print(gist["description"]) |
| 299 | ' | 306 | ' |
| 300 | } | 307 | } |
| 301 | 308 | ||
| 302 | # TODO check if a user has no gist | ||
| 303 | # parse response from gists require | 309 | # parse response from gists require |
| 304 | _parse_response() { | 310 | _parse_response() { |
| 305 | _parse_gists \ | 311 | _parse_gists \ |
| 306 | | tac | sed -e 's/, /,/g' | nl -s' ' \ | 312 | | tac | sed -e 's/, /,/g' | nl -s' ' \ |
| 307 | | while read index link file_url_array public file_num comment_num author description; do | 313 | | while read -r index link file_url_array public file_num comment_num author description; do |
| 308 | local blob_code=$(echo $file_url_array | tr ',' '\n' | sed -E -e 's#.*raw/(.*)/.*#\1#' | sort | cut -c -7 | paste -s -d '-' -) | 314 | local blob_code; blob_code=$(echo "$file_url_array" | tr ',' '\n' | sed -E -e 's#.*raw/(.*)/.*#\1#' | sort | cut -c -7 | paste -s -d '-' -) |
| 309 | [[ $public == 'False' ]] && local mark=p | 315 | [[ $public == 'False' ]] && local mark=p |
| 310 | [[ -n $1 ]] && local index=$1 | 316 | [[ -n $1 ]] && local index=$1 |
| 311 | echo $mark$index $link $blob_code $file_num $comment_num $author $description | tr -d '"' | 317 | echo "$mark$index $link $blob_code $file_num $comment_num $author $description" | tr -d '"' |
| 312 | done | 318 | done |
| 313 | } | 319 | } |
| 314 | 320 | ||
| 315 | # TODO pagnation for more than 30 gists | 321 | # TODO pagnation for more than 100 gists |
| 316 | # TODO add files and date of a gist | 322 | # TODO add files and date of a gist |
| 317 | # get latest list of gists from Github API | 323 | # get latest list of gists from Github API |
| 318 | _fetch_gists() { | 324 | _fetch_gists() { |
| 319 | echo "fetching $user's gists from $GITHUB_API..." | 325 | echo "fetching $user's gists from $GITHUB_API..." |
| @@ -326,51 +332,61 @@ _fetch_gists() { | |||
| 326 | filter='/^[s]/ d; /^$/ d' | 332 | filter='/^[s]/ d; /^$/ d' |
| 327 | fi | 333 | fi |
| 328 | 334 | ||
| 329 | result=$(http_method GET $GITHUB_API/$route | mark=$mark _parse_response) | 335 | result=$(http_method GET $GITHUB_API/$route?per_page=100 | mark=$mark _parse_response) |
| 330 | [[ -z $result ]] && echo Failed to update gists && return 1 | 336 | [[ -z $result ]] && echo 'Not a single valid gist' && return 0 |
| 331 | 337 | ||
| 332 | sed -i'' -e "$filter" $INDEX && echo "$result" >> $INDEX | 338 | sed -i'' -e "$filter" $INDEX && echo "$result" >> $INDEX |
| 333 | mark=$mark _show_list | 339 | mark=$mark _show_list |
| 334 | 340 | ||
| 335 | [[ $auto_sync == 'true' ]] && (_sync_repos $1 > /dev/null 2>&1 &) | 341 | [[ $auto_sync == 'true' ]] && (_sync_repos "$1" > /dev/null 2>&1 &) |
| 342 | true | ||
| 336 | } | 343 | } |
| 337 | 344 | ||
| 345 | # TODO pagnation for more than 100 gists | ||
| 338 | _query_user() { | 346 | _query_user() { |
| 339 | local route="users/$1/gists" | 347 | local route="users/$1/gists" |
| 340 | result=$(http_method GET $GITHUB_API/$route | _parse_response) | 348 | result=$(http_method GET $GITHUB_API/$route?per_page=100 | _parse_response) |
| 341 | [[ -z $result ]] && echo "Failed to query $1's gists" && return 1 | 349 | [[ -z $result ]] && echo "Failed to query $1's gists" && return 1 |
| 342 | 350 | ||
| 343 | echo "$result" \ | 351 | echo "$result" \ |
| 344 | | while read index link blob_code file_num extra description; do | 352 | | while read -r index link blob_code file_num extra description; do |
| 345 | echo $link $file_num $extra $description | cut -c -$(tput cols) | 353 | echo "$link $file_num $extra $description" | cut -c -"$(tput cols)" |
| 346 | done | 354 | done |
| 347 | } | 355 | } |
| 348 | 356 | ||
| 349 | _blob_code() { | 357 | _blob_code() { |
| 350 | cd $1 && git ls-tree master | cut -d' ' -f3 | cut -c-7 | sort | paste -sd '-' | 358 | cd "$1" && git ls-tree master | cut -d' ' -f3 | cut -c-7 | sort | paste -sd '-' |
| 351 | } | 359 | } |
| 352 | 360 | ||
| 353 | # update local git repos | 361 | # update local git repos |
| 354 | # TODO support HTTPS protocol | ||
| 355 | _sync_repos() { | 362 | _sync_repos() { |
| 356 | # clone repos which are not in the local | 363 | # clone repos which are not in the local |
| 357 | comm -13 <(find $folder -maxdepth 1 -type d | sed -e '1d; s#.*/##' | sort) \ | 364 | comm -13 <(find $folder -maxdepth 1 -type d | sed -e '1d; s#.*/##' | sort) \ |
| 358 | <(cat $INDEX | cut -d' ' -f2 | sed -e 's#.*/##' | sort) \ | 365 | <(cut -d' ' -f2 < "$INDEX" | sed -e 's#.*/##' | sort) \ |
| 359 | | xargs -I{} --max-procs 8 git clone git@github.com:{}.git $folder/{} | 366 | | xargs -I{} --max-procs 8 git clone "$(_repo_url {})" $folder/{} |
| 360 | 367 | ||
| 361 | # pull if remote repo has different blob objects | 368 | # pull if remote repo has different blob objects |
| 362 | cat $INDEX | cut -d' ' -f2,3 \ | 369 | cut -d' ' -f2,3 < "$INDEX" \ |
| 363 | | while read url blob_code_remote; do | 370 | | while read -r url blob_code_remote; do |
| 364 | local repo=$folder/$(echo $url | sed -e 's#.*/##') | 371 | local repo; repo=$folder/${url##*/} |
| 365 | local blob_code_local=$(_blob_code $repo) | 372 | local blob_code_local; blob_code_local=$(_blob_code "$repo") |
| 366 | cd $repo \ | 373 | cd "$repo" \ |
| 367 | && [[ $blob_code_local != $blob_code_remote ]] \ | 374 | && [[ $blob_code_local != "$blob_code_remote" ]] \ |
| 368 | && [[ $(git rev-parse origin/master) == $(git rev-parse master) ]] \ | 375 | && [[ $(git rev-parse origin/master) == $(git rev-parse master) ]] \ |
| 369 | && git pull | 376 | && git pull |
| 370 | done | 377 | done |
| 371 | echo Everything is fine! | 378 | echo Everything is fine! |
| 372 | } | 379 | } |
| 373 | 380 | ||
| 381 | # get the url where to clone repo, take user and repo name as parameters | ||
| 382 | _repo_url() { | ||
| 383 | if [[ $protocol == 'ssh' ]]; then | ||
| 384 | echo "git@gist.github.com:$1.git" | ||
| 385 | else | ||
| 386 | echo "https://gist.github.com/$1.git" | ||
| 387 | fi | ||
| 388 | } | ||
| 389 | |||
| 374 | # get gist id from index files | 390 | # get gist id from index files |
| 375 | _gist_id() { | 391 | _gist_id() { |
| 376 | GIST_ID=$( (grep -hs '' $INDEX || true) | sed -n -e "/^$1 / p" | cut -d' ' -f2 | sed -E -e 's#.*/##') | 392 | GIST_ID=$( (grep -hs '' $INDEX || true) | sed -n -e "/^$1 / p" | cut -d' ' -f2 | sed -E -e 's#.*/##') |
| @@ -384,13 +400,11 @@ _gist_id() { | |||
| 384 | } | 400 | } |
| 385 | 401 | ||
| 386 | _goto_gist() { | 402 | _goto_gist() { |
| 387 | _gist_id $1 || return 1 | 403 | _gist_id "$1" || return 1 |
| 388 | 404 | ||
| 389 | if [[ ! -d $folder/$GIST_ID ]]; then | 405 | if [[ ! -d $folder/$GIST_ID ]]; then |
| 390 | echo 'Cloning gist as repo...' | 406 | echo 'Cloning gist as repo...' |
| 391 | git clone git@github.com:$GIST_ID.git $folder/$GIST_ID | 407 | if git clone "$(_repo_url "$GIST_ID")" "$folder/$GIST_ID"; then |
| 392 | |||
| 393 | if [[ $? -eq 0 ]]; then | ||
| 394 | echo 'Repo is cloned' > /dev/tty | 408 | echo 'Repo is cloned' > /dev/tty |
| 395 | else | 409 | else |
| 396 | echo 'Failed to clone the gist' > /dev/tty | 410 | echo 'Failed to clone the gist' > /dev/tty |
| @@ -398,18 +412,20 @@ _goto_gist() { | |||
| 398 | fi | 412 | fi |
| 399 | fi | 413 | fi |
| 400 | 414 | ||
| 401 | [[ $2 != '--no-action' ]] && cd $folder/$GIST_ID && eval "$action" | 415 | [[ $2 != '--no-action' ]] && cd "$folder/$GIST_ID" && eval "$action" |
| 402 | echo $folder/$GIST_ID | 416 | echo "$folder/$GIST_ID" |
| 403 | } | 417 | } |
| 404 | 418 | ||
| 405 | _delete_gist() { | 419 | _delete_gist() { |
| 406 | read -r -p "Delete gists above? [y/N] " response | 420 | if [[ $confirm != false ]]; then |
| 407 | response=${response,,} | 421 | read -r -p "Delete gists above? [y/N] " response |
| 408 | [[ ! $response =~ ^(yes|y)$ ]] && return 0 | 422 | response=${response,,} |
| 423 | [[ ! $response =~ ^(yes|y)$ ]] && return 0 | ||
| 424 | fi | ||
| 409 | 425 | ||
| 410 | for i in "$@"; do | 426 | for i in "$@"; do |
| 411 | _gist_id "$i" | 427 | _gist_id "$i" |
| 412 | http_method DELETE $GITHUB_API/gists/$GIST_ID \ | 428 | http_method DELETE "$GITHUB_API/gists/$GIST_ID" \ |
| 413 | && echo "$i" deleted \ | 429 | && echo "$i" deleted \ |
| 414 | && sed -E -i'' -e "/^$i / d" $INDEX | 430 | && sed -E -i'' -e "/^$i / d" $INDEX |
| 415 | done | 431 | done |
| @@ -418,9 +434,9 @@ _delete_gist() { | |||
| 418 | # remove repos which are not in user gists anymore | 434 | # remove repos which are not in user gists anymore |
| 419 | _clean_repos() { | 435 | _clean_repos() { |
| 420 | comm -23 <(find $folder -maxdepth 1 -type d | sed -e '1d; s#.*/##' | sort) \ | 436 | comm -23 <(find $folder -maxdepth 1 -type d | sed -e '1d; s#.*/##' | sort) \ |
| 421 | <(cat $INDEX 2> /dev/null | cut -d' ' -f2 | sed -e 's#.*/##' | sort) \ | 437 | <(cut -d' ' -f2 < "$INDEX" | sed -e 's#.*/##' | sort 2> /dev/null ) \ |
| 422 | | while read dir; do | 438 | | while read -r dir; do |
| 423 | mv $folder/$dir /tmp && echo move $folder/$dir to /tmp | 439 | mv $folder/"$dir" /tmp && echo move $folder/"$dir" to /tmp |
| 424 | done | 440 | done |
| 425 | } | 441 | } |
| 426 | 442 | ||
| @@ -437,7 +453,7 @@ print("updated_at:", raw["updated_at"]) | |||
| 437 | print("files:") | 453 | print("files:") |
| 438 | for file in raw["files"].keys(): | 454 | for file in raw["files"].keys(): |
| 439 | print(" ", file) | 455 | print(" ", file) |
| 440 | ' | 456 | ' |
| 441 | } | 457 | } |
| 442 | 458 | ||
| 443 | # equal to jq '.[] | {user: .user.login, created_at: .created_at, updated_at: .updated_at, body: .body}' | 459 | # equal to jq '.[] | {user: .user.login, created_at: .created_at, updated_at: .updated_at, body: .body}' |
| @@ -450,22 +466,23 @@ for comment in raw: | |||
| 450 | print("|", "created_at:", comment["created_at"]) | 466 | print("|", "created_at:", comment["created_at"]) |
| 451 | print("|", "updated_at:", comment["updated_at"]) | 467 | print("|", "updated_at:", comment["updated_at"]) |
| 452 | print("|", comment["body"]) | 468 | print("|", comment["body"]) |
| 453 | ' | 469 | ' |
| 454 | } | 470 | } |
| 455 | 471 | ||
| 456 | _show_detail() { | 472 | _show_detail() { |
| 457 | _gist_id $1 | 473 | _gist_id "$1" |
| 458 | http_method GET $GITHUB_API/gists/$GIST_ID \ | 474 | http_method GET "$GITHUB_API/gists/$GIST_ID" \ |
| 459 | | _parse_gist | 475 | | _parse_gist |
| 460 | 476 | ||
| 461 | http_method GET $GITHUB_API/gists/$GIST_ID/comments \ | 477 | http_method GET "$GITHUB_API/gists/$GIST_ID"/comments \ |
| 462 | | _parse_comment | 478 | | _parse_comment |
| 463 | } | 479 | } |
| 464 | 480 | ||
| 465 | # set filename/description/permission for a new gist | 481 | # set filename/description/permission for a new gist |
| 466 | _set_gist() { | 482 | _set_gist() { |
| 483 | files=() | ||
| 467 | public=True | 484 | public=True |
| 468 | while [[ -n $@ ]]; do case $1 in | 485 | while [[ -n "$*" ]]; do case $1 in |
| 469 | -d | --desc) | 486 | -d | --desc) |
| 470 | description="$2" | 487 | description="$2" |
| 471 | shift; shift;; | 488 | shift; shift;; |
| @@ -476,22 +493,22 @@ _set_gist() { | |||
| 476 | public=False | 493 | public=False |
| 477 | shift;; | 494 | shift;; |
| 478 | *) | 495 | *) |
| 479 | files="$1 $files" | 496 | files+=($1) |
| 480 | shift;; | 497 | shift;; |
| 481 | esac | 498 | esac |
| 482 | done | 499 | done |
| 483 | ls $files > /dev/null || return 1 | 500 | ls "${files[@]}" > /dev/null || return 1 |
| 484 | } | 501 | } |
| 485 | 502 | ||
| 486 | # Let user type the content of gist before setting filename | 503 | # Let user type the content of gist before setting filename |
| 487 | _new_file() { | 504 | _new_file() { |
| 488 | [[ -t 0 ]] && echo "Type a gist. <Ctrl-C> to cancel, <Ctrl-D> when done" > /dev/tty | 505 | [[ -t 0 ]] && echo "Type a gist. <Ctrl-C> to cancel, <Ctrl-D> when done" > /dev/tty |
| 489 | tmp_file=$(mktemp) | 506 | tmp_file=$(mktemp) |
| 490 | cat > $tmp_file | 507 | cat > "$tmp_file" |
| 491 | echo -e '\n' > /dev/tty | 508 | echo -e '\n' > /dev/tty |
| 492 | [[ -z $1 ]] && read -p 'Type file name: ' filename < /dev/tty | 509 | [[ -z $1 ]] && read -r -p 'Type file name: ' filename < /dev/tty |
| 493 | mv $tmp_file /tmp/$filename | 510 | mv "$tmp_file" /tmp/"$filename" |
| 494 | echo /tmp/$filename | 511 | echo /tmp/"$filename" |
| 495 | } | 512 | } |
| 496 | 513 | ||
| 497 | _gist_body(){ | 514 | _gist_body(){ |
| @@ -510,21 +527,21 @@ print(json.dumps({'public': $public, 'files': files_json, 'description': descrip | |||
| 510 | # create a new gist with files | 527 | # create a new gist with files |
| 511 | _create_gist() { | 528 | _create_gist() { |
| 512 | _set_gist "$@" || return 1 | 529 | _set_gist "$@" || return 1 |
| 513 | [[ -z $files ]] && files=$(_new_file $filename) | 530 | [[ -z ${files[*]} ]] && files+=($(_new_file "$filename")) |
| 514 | [[ -z $description ]] && read -p 'Type description: ' description < /dev/tty | 531 | [[ -z $description ]] && read -r -p 'Type description: ' description < /dev/tty |
| 515 | 532 | ||
| 516 | echo 'Creating a new gist...' | 533 | echo 'Creating a new gist...' |
| 517 | http_data=$(mktemp) | 534 | http_data=$(mktemp) |
| 518 | 535 | echo -e "${files[*]}\n$description" \ | |
| 519 | echo -e "$files\n$description" \ | 536 | | _gist_body > "$http_data" \ |
| 520 | | _gist_body > $http_data \ | ||
| 521 | && http_method POST $GITHUB_API/gists \ | 537 | && http_method POST $GITHUB_API/gists \ |
| 522 | | sed -e '1 s/^/[/; $ s/$/]/' \ | 538 | | sed -e '1 s/^/[/; $ s/$/]/' \ |
| 523 | | _parse_response $(( $(sed -e '/^s/ d' $INDEX | wc -l) +1 )) \ | 539 | | _parse_response $(( $(sed -e '/^s/ d' $INDEX | wc -l) +1 )) \ |
| 524 | | tee -a $INDEX \ | 540 | | tee -a $INDEX \ |
| 525 | | cut -d' ' -f2 | sed -E -e 's#.*/##' \ | 541 | | cut -d' ' -f2 | sed -E -e 's#.*/##' \ |
| 526 | | (xargs -I{} git clone git@github.com:{}.git $folder/{} &> /dev/null &) | 542 | | (xargs -I{} git clone "$(_repo_url {})" $folder/{} &> /dev/null &) |
| 527 | 543 | ||
| 544 | # shellcheck disable=2181 | ||
| 528 | if [[ $? -eq 0 ]]; then | 545 | if [[ $? -eq 0 ]]; then |
| 529 | echo 'Gist is created' | 546 | echo 'Gist is created' |
| 530 | hint=false _show_list | tail -1 | 547 | hint=false _show_list | tail -1 |
| @@ -534,21 +551,28 @@ _create_gist() { | |||
| 534 | } | 551 | } |
| 535 | 552 | ||
| 536 | # update description of a gist | 553 | # update description of a gist |
| 537 | # TODO use response to modify index file, do not fetch gists again | ||
| 538 | _edit_gist() { | 554 | _edit_gist() { |
| 539 | _gist_id $1 | 555 | _gist_id "$1" |
| 556 | |||
| 557 | if [[ -z $2 ]]; then | ||
| 558 | echo 'Type new description:' | ||
| 559 | read -e -r DESC < /dev/tty | ||
| 560 | else | ||
| 561 | DESC="$2" | ||
| 562 | fi | ||
| 540 | 563 | ||
| 541 | echo -n 'Type new description: ' | ||
| 542 | read DESC < /dev/tty | ||
| 543 | |||
| 544 | http_data=$(mktemp) | 564 | http_data=$(mktemp) |
| 545 | echo { \"description\": \"$(echo $DESC | sed -e 's/"/\\"/g')\" } > $http_data | 565 | echo '{' \"description\": \""${DESC//\"/\\\"}"\" '}' > "$http_data" |
| 546 | http_method PATCH $http_data $GITHUB_API/gists/$GIST_ID > /dev/null \ | 566 | new_record=$( http_method PATCH "$GITHUB_API/gists/$GIST_ID" \ |
| 547 | && hint=false _fetch_gists | grep -E "^[ ]+$1" | 567 | | sed -e '1 s/^/[/; $ s/$/]/' \ |
| 568 | | _parse_response "$1" ) | ||
| 569 | [[ -n $new_record ]] && sed -i'' -E -e "/^$1 / s^.+^$new_record^" $INDEX \ | ||
| 570 | && hint=false _show_list | grep -E "^[ ]+$1" \ | ||
| 571 | || echo 'Fail to modify gist description' | ||
| 548 | } | 572 | } |
| 549 | 573 | ||
| 550 | usage() { | 574 | usage() { |
| 551 | sed -E -n -e ' /^$/ q; 7,$ s/^# //p' $0 | 575 | sed -E -n -e ' /^$/ q; 7,$ s/^# //p' "$0" |
| 552 | } | 576 | } |
| 553 | 577 | ||
| 554 | _apply_config "$@" || exit 1 | 578 | _apply_config "$@" || exit 1 |
| @@ -565,7 +589,8 @@ case "$1" in | |||
| 565 | shift | 589 | shift |
| 566 | _create_gist "$@" ;; | 590 | _create_gist "$@" ;; |
| 567 | edit | e) | 591 | edit | e) |
| 568 | _edit_gist "$2" ;; | 592 | shift |
| 593 | _edit_gist "$@" ;; | ||
| 569 | sync | S) | 594 | sync | S) |
| 570 | _sync_repos ;; | 595 | _sync_repos ;; |
| 571 | detail | d) | 596 | detail | d) |
| @@ -594,7 +619,7 @@ case "$1" in | |||
| 594 | version) | 619 | version) |
| 595 | echo "Version $currentVersion" | 620 | echo "Version $currentVersion" |
| 596 | exit 0 ;; | 621 | exit 0 ;; |
| 597 | update) | 622 | update) |
| 598 | checkInternet || exit 1 | 623 | checkInternet || exit 1 |
| 599 | update | 624 | update |
| 600 | exit 0 | 625 | exit 0 |