aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authortypebrook <typebrook@gmail.com>2020-02-19 10:15:46 +0800
committertypebrook <typebrook@gmail.com>2020-02-19 10:15:46 +0800
commite2ab9b1cb9485d851fafa06cee09a0cea863aa6b (patch)
treea51316e7ceed916ea29b004781040a839f9ba4a0
parentcf18a16d5237c10a104fe48c3f30f5c89f67e88f (diff)
update
-rwxr-xr-xgist251
1 files changed, 138 insertions, 113 deletions
diff --git a/gist b/gist
index acb0066..4f7847b 100755
--- a/gist
+++ b/gist
@@ -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
46folder=~/gist && mkdir -p $folder 46folder=~/gist && mkdir -p $folder
47action="${EDITOR:-vi} ." 47action="${EDITOR:-vi} ."
48auto_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
50auto_sync=true # automatically clone the gist repo
51protocol=https
50 52
51# Shell configuration 53# Shell configuration
52set -o pipefail 54set -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
73http_method() { 75http_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"])
437print("files:") 453print("files:")
438for file in raw["files"].keys(): 454for 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
550usage() { 574usage() {
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