aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authortypebrook <typebrook@gmail.com>2020-01-20 11:53:00 +0800
committertypebrook <typebrook@gmail.com>2020-01-20 11:53:00 +0800
commit456d5d41eeca37a595980ec3ba8e9411e0dfb63b (patch)
tree9c20dd885e2ff9d5402611ae91c7341826b579c1
parent0078e7e9e1e1ab46833cb108df11dd4f4aa8c4b9 (diff)
update
-rwxr-xr-xgist221
1 files changed, 149 insertions, 72 deletions
diff --git a/gist b/gist
index 9a869f9..55c9ab8 100755
--- a/gist
+++ b/gist
@@ -5,7 +5,7 @@
5# https://gist.github.com/typebrook/b0d2e7e67aa50298fdf8111ae7466b56 5# https://gist.github.com/typebrook/b0d2e7e67aa50298fdf8111ae7466b56
6# 6#
7# 7#
8# This script host your gists as local Github repo 8# This script host your gists as local cloned git repo
9# It works under GNU with jq and curl, both are easy to get in most cases 9# It works under GNU with jq and curl, both are easy to get in most cases
10# 10#
11# Use the following commands to manage your gists: 11# Use the following commands to manage your gists:
@@ -18,31 +18,42 @@
18# 18#
19# * clone gist repos which are not in local 19# * clone gist repos which are not in local
20# * pull master branch if a local repo is behind its remote 20# * pull master branch if a local repo is behind its remote
21# gist [sync | s] 21# gist (sync | S)
22# 22#
23# * Go to local gist repo 23# * Go to local gist repo
24# gist <number_of_gist_in_list> 24# . gist <number_of_gist_in_list>
25# 25#
26# * create a new gist with a file and description 26# * create a new gist with files
27# gist [create | c] <filename> "<description>" 27# gist (new | n) [-d | --desc "<gist-description>"] <files>...
28#
29# * create a new gist with STDIN
30# gist (new | n) [-d | --desc "<gist-description>"] [-f | --file <file>] < <file-with-content>
28# 31#
29# * show the detail of a gist 32# * show the detail of a gist
30# gist [detail | d] <number_of_gist_in_list> 33# gist (detail | d) <gist_index>
31# 34#
32# * edit a gist description 35# * edit a gist description
33# gist [edit | e] <number_of_gist_in_list> 36# gist (edit | e) <gist_index>
34# 37#
35# * delete a gist 38# * delete a gist
36# gist [delete | D] <number_of_gist_in_list> 39# gist (delete | D) <gist_index>...
37# 40#
38# * clean removed gists in local 41# * clean removed gists in local
39# gist [clean | C] 42# gist (clean | C)
40 43#
44# * update a gist
45# Since now a gist is a local cloned repo
46# It is your business to do git commit and git push
47#
41# * show this help message 48# * show this help message
42# gist [help | h] 49# gist (help | h)
43 50
44# define your environmemnts here 51# define your environmemnts here
45# TODO support auth prompt 52# TODO support auth prompt, remove personal info here
53# TODO error handling, unit test
54# TODO parallel branch works with json parsing on python
55# TODO parallel branch works with wget and other stuff
56# completion
46#------------------- 57#-------------------
47github_api_token=$(cat $SETTING_DIR/tokens/github) 58github_api_token=$(cat $SETTING_DIR/tokens/github)
48user=typebrook 59user=typebrook
@@ -53,32 +64,68 @@ github_api=https://api.github.com
53auth_header="Authorization: token $github_api_token" 64auth_header="Authorization: token $github_api_token"
54mkdir -p $folder 65mkdir -p $folder
55index=$folder/index 66index=$folder/index
67starred=$folder/starred
56 68
57# Validate settings. 69# Validate settings.
58[ "$TRACE" ] && set -x 70[ "$TRACE" ] && set -x
59 71
60# Show the list of gist, but not updated time 72# Show the list of gist, but not updated time
73# TODO show git status outdated
61_show_list() { 74_show_list() {
62 cat $index | cut -d' ' -f1-2,4- 75 if [[ ! -e $1 ]]; then
76 echo No local file found for last update
77 echo Please run command:
78 echo " gist update"
79 exit 0
80 fi
81 cat $1 |\
82 while read line_num link file_url_array file_num extra description; do
83 repo=$folder/$(echo $link | sed 's#.*/##')
84
85 # if repo is not yet cloned, show green message "Sync Now"
86 cd $repo 2>/dev/null || extra="\e[32m[Sync Now]\e[0m"
87 # if there are some changes in git index or working directory, show blue message "working"
88 [[ -n $(git status --short) ]] 2>/dev/null && extra="\e[36m[working]\e[0m"
89 # if there is a commit not yet push, show red message "ahead"
90 [[ -n $(git cherry) ]] 2>/dev/null && extra="\e[31m[ahead]\e[0m"
91
92 echo -e $line_num $link $file_num $extra $(echo $description | cut -c -60)
93 done
63} 94}
64 95
65# get the list of gists 96# get the list of gists
66# TODO support secret gist 97# TODO support secret gist
67_update() { 98_update() {
68 curl -s -H "$auth_header" $github_api/users/$user/gists |\ 99 echo "fetching from api.github.com..."
100 echo
101 list_file=$index
102 route="users/$user/gists"
103 mark=""
104 [[ "$1" =~ ^(star|s)$ ]] && list_file=$starred && route="gists/starred" && mark="s"
105
106 curl -s -H "$auth_header" $github_api/$route |\
107 _parse_response | nl -s' ' | sed -E "s/^ */$mark/" > $list_file && \
108 _show_list $list_file
109 (_sync_repos $1 > /dev/null 2>&1 &)
110}
111
112# TODO check if a user create a very first gist
113_parse_response() {
69 jq '.[] | "\(.html_url) \([.files[] | .raw_url]) \(.files | keys | length) \(.comments) \(.description)"' |\ 114 jq '.[] | "\(.html_url) \([.files[] | .raw_url]) \(.files | keys | length) \(.comments) \(.description)"' |\
70 tac | nl |\ 115 tac |\
71 while read line_num link file_url_array file_num comment_num description; do 116 while read link file_url_array file_num comment_num description; do
72 blob_code=$(echo $file_url_array | jq -r '.[]' | sed -r 's#.*raw/(.*)/.*#\1#' | sort | cut -c -7 | paste -sd '-') 117 blob_code=$(echo $file_url_array | jq -r '.[]' | sed -E 's#.*raw/(.*)/.*#\1#' | sort | cut -c -7 | paste -sd '-')
73 echo $line_num $link $blob_code $file_num $comment_num $(echo $description | cut -c -70) | tr -d '"' 118 echo $link $blob_code $file_num $comment_num $description | tr -d '"'
74 done > $index && \ 119 done
75 _show_list
76} 120}
77 121
78_sync_repos() { 122_sync_repos() {
123 list_file=$index
124 [[ "$1" == "--star" ]] && list_file=$starred && route="gists/starred"
125
79 # clone repos which are not in the local 126 # clone repos which are not in the local
80 comm -13 <(find $folder -maxdepth 1 -type d | sed '1d; s#.*/##' | sort) \ 127 comm -13 <(find $folder -maxdepth 1 -type d | sed '1d; s#.*/##' | sort) \
81 <(cat $index | cut -d' ' -f2 | sed 's#.*/##' | sort) |\ 128 <(cat $list_file | cut -d' ' -f2 | sed 's#.*/##' | sort) |\
82 xargs -I{} git clone git@github.com:{}.git $folder/{} 129 xargs -I{} git clone git@github.com:{}.git $folder/{}
83 130
84 # pull if remote repo has different blob objects 131 # pull if remote repo has different blob objects
@@ -96,27 +143,32 @@ _sync_repos() {
96} 143}
97 144
98_gist_id() { 145_gist_id() {
99 cat $index | sed -n "$1"p | cut -d' ' -f2 | sed -r 's#.*/##' 146 GIST_ID=$(cat $index $starred | sed -n "/^$1 / p" | cut -d' ' -f2 | sed -E 's#.*/##')
100} 147 if [[ -z $GIST_ID ]]; then
101 148 echo -e "Not a valid index: \e[31m$1\e[0m"
102_goto_gist() { 149 echo Use the index number in the first column instead:
103 gist_num=$(wc -l $index | cut -d' ' -f1)
104 if [[ ! "$1" =~ [0-9]+ ]] || (( $1 > $gist_num )); then
105 echo Not a valid gist number: $1
106 echo Use the number in the first column instead:
107 echo 150 echo
108 _show_list 151 _show_list "$index $starred"
109 return 0 152 exit 1
110 fi 153 fi
154}
111 155
112 GIST_ID=$(_gist_id $1) 156# FIXME error handling
157_goto_gist() {
158 _gist_id $1
113 echo This gist is at $folder/$GIST_ID 159 echo This gist is at $folder/$GIST_ID
114 cd $folder/$GIST_ID && tig --all 2> /dev/null 160 echo -e "You can run the following command to jump to this directory: \n"
161 echo -e " \e[32m. gist $1\e[0m"
162 echo
163 cd $folder/$GIST_ID && ls && tig --all 2> /dev/null
115} 164}
116 165
117_delete_gist() { 166_delete_gist() {
118 GIST_ID=$(_gist_id $1) 167 for i in "$@"; do
119 curl -X DELETE -s -H "$auth_header" $github_api/gists/$GIST_ID && \ 168 _gist_id "$i"
169 curl -X DELETE -s -H "$auth_header" $github_api/gists/$GIST_ID && \
170 echo "$i" deleted
171 done
120 _update 172 _update
121} 173}
122 174
@@ -129,78 +181,103 @@ _clean_repos() {
129 done 181 done
130} 182}
131 183
132# TODO star count 184# TODO format with simple text
133_show_detail() { 185_show_detail() {
134 GIST_ID=$(_gist_id $1) 186 _gist_id $1
135 curl -s -H "$auth_header" $github_api/gists/$GIST_ID |\ 187 curl -s -H "$auth_header" $github_api/gists/$GIST_ID |\
136 jq '{site: .html_url, description: .description, API: .url, created_at: .created_at, updated_at: .updated_at, files: (.files | keys)}' 188 jq '{site: .html_url, description: .description, public: .public, API: .url, created_at: .created_at, updated_at: .updated_at, files: (.files | keys)}'
137 189
138 curl -s -H "$auth_header" $github_api/gists/$GIST_ID/comments |\ 190 curl -s -H "$auth_header" $github_api/gists/$GIST_ID/comments |\
139 jq '.[] | {user: .user.login, created_at: .created_at, updated_at: .updated_at, body: .body}' 191 jq '.[] | {user: .user.login, created_at: .created_at, updated_at: .updated_at, body: .body}'
140} 192}
141 193
194_new_file() {
195 [[ -t 0 ]] && echo "Type a gist. <Ctrl-C> to cancel, <Ctrl-D> when done" > /dev/tty
196 tmp_file=$(mktemp)
197 cat > $tmp_file
198 echo
199 [[ -z "$1" ]] && echo -en '\nType file name: ' > /dev/tty && read filename
200 mv $tmp_file /tmp/$filename
201 echo /tmp/$filename
202}
203
204_set_gist() {
205 while [[ "$1" =~ ^- && ! "$1" == "--" ]]; do case $1 in
206 -d | --desc)
207 description="$2"
208 shift; shift;;
209 -f | --file)
210 filename="$2"
211 shift; shift;;
212 esac
213 done
214 if [[ "$1" == '--' ]]; then shift; fi
215 files=$@
216}
217
142# create a new gist with files 218# create a new gist with files
219# FIXME error handling if gist is not created
143_create_gist() { 220_create_gist() {
144 echo -n 'description: ' 221 _set_gist "$@"
145 read DESC 222 [[ -z $files ]] && files=$(_new_file $filename)
223 [[ -z $description ]] && echo -en '\nDescription: ' && read description
146 224
147 echo $@ | tr " " "\n" |\ 225 for file in $files; do
148 while read file; do
149 FILE=$(basename $file) 226 FILE=$(basename $file)
150 jq --arg FILE "$FILE" '. as $content | { ($FILE): {content: $content} }' -Rs $file 227 jq --arg FILE "$FILE" '. as $content | { ($FILE): {content: $content} }' -Rs $file
151 done |\ 228 done |\
152 jq --slurp --arg DESC "$DESC" '{ 229 jq --slurp --arg DESC "$description" '{
153 public: true, 230 public: true,
154 files: add, 231 files: add,
155 description: ($DESC) 232 description: ($DESC)
156 }' |\ 233 }' |\
157 curl -s -H "$auth_header" --data @- $github_api/gists > /dev/null && \ 234 curl -H "$auth_header" --data @- $github_api/gists |\
158 _update && _sync_repos 235 sed '1 s/^/[/; $ s/$/]/' |\
236 _parse_response |\
237 sed -E "s/^/$(( $(wc -l $index | cut -d' ' -f1) + 1 )) /" >> $index && \
238 echo Gist created
239 echo
240 _show_list $index | tail -1
159} 241}
160 242
161# update description of a gist 243# update description of a gist
162_edit_gist() { 244_edit_gist() {
163 GIST_ID=$(_gist_id $1) 245 _gist_id $1
164 246
165 jq -n --arg DESC "$2" '{ description: ($DESC) }' |\ 247 echo -n 'Type new description: '
248 read DESC
249 jq -n --arg DESC "$DESC" '{ description: ($DESC) }' |\
166 curl -X PATCH -H "$auth_header" --data @- $github_api/gists/$GIST_ID > /dev/null && \ 250 curl -X PATCH -H "$auth_header" --data @- $github_api/gists/$GIST_ID > /dev/null && \
167 _update 251 _update
168} 252}
169 253
170_help_message() { 254_help_message() {
171 sed -r -n ' /^$/ q; 8,$ s/^#//p' $0 255 sed -E -n ' /^$/ q; 8,$ s/^#//p' $0
172} 256}
173 257
174case "$1" in 258case "$1" in
175 "") 259 "")
176 _show_list 260 _show_list $index ;;
177 ;; 261 star | s)
178 create | c) 262 _show_list $starred ;;
179 shift;
180 _create_gist $@
181 ;;
182 edit | e)
183 _edit_gist "$2" "$3"
184 ;;
185 update | u) 263 update | u)
186 _update 264 _update "$2" ;;
187 ;; 265 new | n)
188 sync | s) 266 shift
189 _sync_repos 267 _create_gist "$@" ;;
190 ;; 268 edit | e)
269 _edit_gist "$2" ;;
270 sync | S)
271 _sync_repos ;;
191 detail | d) 272 detail | d)
192 _show_detail "$2" 273 _show_detail "$2" ;;
193 ;;
194 delete | D) 274 delete | D)
195 _delete_gist "$2" 275 shift
196 ;; 276 _delete_gist "$@" ;;
197 clean | C) 277 clean | C)
198 _clean_repos 278 _clean_repos ;;
199 ;;
200 help | h) 279 help | h)
201 _help_message 280 _help_message ;;
202 ;;
203 *) 281 *)
204 _goto_gist "$1" 282 _goto_gist "$1" ;;
205 ;;
206esac 283esac