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 |