aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authortypebrook <typebrook@gmail.com>2020-01-27 23:28:00 +0800
committertypebrook <typebrook@gmail.com>2020-01-27 23:28:00 +0800
commit507e32d7f867db0c44d6f20adae6d30b15eb9584 (patch)
treec43e012ce1cb5b81f74ca3e8e74bad05bde088ec
parentb7ce476f3eb425754427445901ff813925fffdd8 (diff)
updateOTP
-rwxr-xr-xgist182
1 files changed, 100 insertions, 82 deletions
diff --git a/gist b/gist
index da30e4b..f0816e5 100755
--- a/gist
+++ b/gist
@@ -45,10 +45,12 @@
45# Since now a gist is a local cloned repo 45# Since now a gist is a local cloned repo
46# It is your business to do git commit and git push 46# It is your business to do git commit and git push
47# 47#
48# * configuration
49# gist (config | c) [token <value>] [user <value>] [folder <value>]
50#
48# * show this help message 51# * show this help message
49# gist (help | h) 52# gist (help | h)
50 53
51# TODO pipe syntax fix
52# TODO error handling, unit test 54# TODO error handling, unit test
53# TODO parallel branch works with json parsing on python 55# TODO parallel branch works with json parsing on python
54# TODO parallel branch works with wget and other stuff 56# TODO parallel branch works with wget and other stuff
@@ -56,35 +58,41 @@
56 58
57# Validate settings. 59# Validate settings.
58config=~/.config/gistrc 60config=~/.config/gistrc
61set -eo pipefail
59[ "$TRACE" ] && set -x 62[ "$TRACE" ] && set -x
60 63
61# TODO error handling while password is not true 64# TODO error handling while password is not true
65# TODO support access token from input or web
62_auth() { 66_auth() {
63 data="{\"scopes\":[\"gist\"], \"note\": \"gist-$(date -u +'%Y-%m-%dT%H:%M:%SZ')\"}" 67 local data="{\"scopes\":[\"gist\"], \"note\": \"gist-$(date -u +'%Y-%m-%dT%H:%M:%SZ')\"}"
64 read -p "Github username: " user 68 read -p "Github username: " user < /dev/tty
65 read -sp "Github password: " password 69 read -sp "Github password: " password < /dev/tty
66 mkdir -p ~/.config && umask 0077 && echo user=$user > $config 70 mkdir -p ~/.config && umask 0077 && echo user=$user > $config
67 71
68 curl https://api.github.com/authorizations \ 72 curl -i https://api.github.com/authorizations \
69 --user "$user:$password" \ 73 --user "$user:$password" \
70 --data "$data" > /dev/null 74 --data "$data"
71 75
72 read -p "2-factor code: " OTP 76 read -p "2-factor code: " OTP < /dev/tty
73 curl https://api.github.com/authorizations \ 77 curl https://api.github.com/authorizations \
74 --user "$user:$password" -H "X-GitHub-OTP: $OTP" \ 78 --user "$user:$password" -H "X-GitHub-OTP: $OTP" \
75 --data "$data" |\ 79 --data "$data" \
76 sed '1 s/[^{]//g' | jq -r .token |\ 80 | sed '1 s/[^{]//g' | jq -r .token \
77 sed 's/^/token=/' >> $config 81 | sed 's/^/token=/' >> $config
78} 82}
79 83
80while ! source $config; do 84case "$1" in
81 _auth 85 config | c) ;;
82done 86 *)
87 while ! source $config 2> /dev/null || [[ -z "$token" ]] || [[ -z "$user" ]]; do
88 _auth
89 done;;
90esac
83 91
84github_api=https://api.github.com 92github_api=https://api.github.com
85auth_header="Authorization: token $token" 93auth_header="Authorization: token $token"
86 94
87[[ -z "$folder" ]] && folder=~/git/gist 95[[ -z "$folder" ]] && folder=~/gist
88mkdir -p $folder 96mkdir -p $folder
89index=$folder/index 97index=$folder/index
90starred=$folder/starred 98starred=$folder/starred
@@ -99,96 +107,105 @@ _show_list() {
99 echo " gist update" 107 echo " gist update"
100 exit 0 108 exit 0
101 fi 109 fi
102 cat $1 |\ 110 cat $1 \
103 while read line_num link file_url_array file_num extra description; do 111 | while read line_num link file_url_array file_num extra description; do
104 repo=$folder/$(echo $link | sed 's#.*/##') 112 local repo=$folder/$(echo $link | sed 's#.*/##')
113 local occupy=0
114
115 # if repo is not yet cloned, show green message "Not cloned yet"
116 [[ ! -d $repo ]] && extra="\e[32m[Not cloned yet]\e[0m" && occupy=17
105 117
106 # if repo is not yet cloned, show green message "Sync Now"
107 cd $repo 2>/dev/null || extra="\e[32m[Sync Now]\e[0m"
108 # if there are some changes in git index or working directory, show blue message "working" 118 # if there are some changes in git index or working directory, show blue message "working"
109 [[ -n $(git status --short) ]] 2>/dev/null && extra="\e[36m[working]\e[0m" 119 [[ -n $(cd $repo && git status --short) ]] 2>/dev/null && extra="\e[36m[working]\e[0m" && occupy=10
110 # if there is a commit not yet push, show red message "ahead" 120 # if there is a commit not yet push, show red message "ahead"
111 [[ -n $(git cherry) ]] 2>/dev/null && extra="\e[31m[ahead]\e[0m" 121 [[ -n $(cd $repo && git cherry) ]] 2>/dev/null && extra="\e[31m[ahead]\e[0m" && occupy=8
112 122
113 echo -e $line_num $link $file_num $extra $(echo $description | cut -c -60) 123 echo -e $line_num $link $file_num $extra $(echo $description | cut -c -$(( 60 - $occupy )) )
114 done 124 done
115} 125}
116 126
117# get the list of gists 127# get the list of gists
118# TODO support secret gist
119_update() { 128_update() {
120 echo "fetching from api.github.com..." 129 echo "fetching from api.github.com..."
121 echo 130 echo
122 list_file=$index 131 local list_file=$index
123 route="users/$user/gists" 132 local route="users/$user/gists"
124 mark="" 133 local mark=""
125 [[ "$1" =~ ^(star|s)$ ]] && list_file=$starred && route="gists/starred" && mark="s" 134 [[ "$1" =~ ^(star|s)$ ]] && list_file=$starred && route="gists/starred" && mark="s"
126 135
127 curl -s -H "$auth_header" $github_api/$route |\ 136 curl -s -H "$auth_header" $github_api/$route \
128 _parse_response | nl -s' ' | sed -E "s/^ */$mark/" > $list_file && \ 137 | _parse_response | nl -s' ' | sed -E "s/^ */$mark/" > $list_file \
129 _show_list $list_file 138 && _show_list $list_file \
139 || echo Fail to update gists
140
130 if [[ $auto_sync != "false" ]]; then (_sync_repos $1 > /dev/null 2>&1 &); fi 141 if [[ $auto_sync != "false" ]]; then (_sync_repos $1 > /dev/null 2>&1 &); fi
131} 142}
132 143
133# TODO check if a user create a very first gist 144# TODO check if a user create a very first gist
134_parse_response() { 145_parse_response() {
135 jq '.[] | "\(.html_url) \([.files[] | .raw_url]) \(.files | keys | length) \(.comments) \(.description)"' |\ 146 jq '.[] | "\(.html_url) \([.files[] | .raw_url]) \(.files | keys | length) \(.comments) \(.description)"' \
136 tac |\ 147 | tac \
137 while read link file_url_array file_num comment_num description; do 148 | while read link file_url_array file_num comment_num description; do
138 blob_code=$(echo $file_url_array | jq -r '.[]' | sed -E 's#.*raw/(.*)/.*#\1#' | sort | cut -c -7 | paste -sd '-') 149 local blob_code=$(echo $file_url_array | jq -r '.[]' | sed -E 's#.*raw/(.*)/.*#\1#' | sort | cut -c -7 | paste -sd '-')
139 echo $link $blob_code $file_num $comment_num $description | tr -d '"' 150 echo $link $blob_code $file_num $comment_num $description | tr -d '"'
140 done 151 done
141} 152}
142 153
143_sync_repos() { 154_sync_repos() {
144 list_file=$index 155 local list_file=$index
145 [[ "$1" == "--star" ]] && list_file=$starred && route="gists/starred" 156 [[ "$1" =~ ^(star|s)$ ]] && list_file=$starred && route="gists/starred"
146 157
147 # clone repos which are not in the local 158 # clone repos which are not in the local
148 comm -13 <(find $folder -maxdepth 1 -type d | sed '1d; s#.*/##' | sort) \ 159 comm -13 <(find $folder -maxdepth 1 -type d | sed '1d; s#.*/##' | sort) \
149 <(cat $list_file | cut -d' ' -f2 | sed 's#.*/##' | sort) |\ 160 <(cat $list_file | cut -d' ' -f2 | sed 's#.*/##' | sort) \
150 xargs -I{} git clone git@github.com:{}.git $folder/{} 161 | xargs -I{} git clone git@github.com:{}.git $folder/{}
151 162
152 # pull if remote repo has different blob objects 163 # pull if remote repo has different blob objects
153 cat $index | cut -d' ' -f2,3 |\ 164 cat $index | cut -d' ' -f2,3 \
154 while read url blob_code_remote; do 165 | while read url blob_code_remote; do
155 repo=$folder/$(echo $url | sed 's#.*/##') 166 local repo=$folder/$(echo $url | sed 's#.*/##')
156 blob_code_local=$(cd $repo && git ls-tree master | cut -d' ' -f3 | cut -c-7 | sort | paste -sd '-') 167 local blob_code_local=$(cd $repo && git ls-tree master | cut -d' ' -f3 | cut -c-7 | sort | paste -sd '-')
157 168 cd $repo \
158 cd $repo && \ 169 && [[ $blob_code_local != $blob_code_remote ]] \
159 [[ $blob_code_local != $blob_code_remote ]] && \ 170 &&[[ $(git rev-parse origin/master) == $(git rev-parse master) ]] \
160 [[ $(git rev-parse origin/master) == $(git rev-parse master) ]] && \ 171 && git pull
161 git pull
162 done 172 done
163 echo Everything is fine! 173 echo Everything is fine!
164} 174}
165 175
166_gist_id() { 176_gist_id() {
167 GIST_ID=$(cat $index $starred | sed -n "/^$1 / p" | cut -d' ' -f2 | sed -E 's#.*/##') 177 GIST_ID=$(cat $index $starred 2> /dev/null | sed -n "/^$1 / p" | cut -d' ' -f2 | sed -E 's#.*/##')
168 if [[ -z "$GIST_ID" ]]; then 178 if [[ -z "$GIST_ID" ]]; then
169 echo -e "Not a valid index: \e[31m$1\e[0m" 179 echo -e "Not a valid index: \e[31m$1\e[0m"
170 echo Use the index number in the first column instead: 180 echo Use the index number in the first column instead:
171 echo 181 echo
172 _show_list "$index $starred" 182 _show_list "$index"
173 exit 1 183 exit 1
174 fi 184 fi
175} 185}
176 186
177# FIXME error handling, if repo not cloned yet
178_goto_gist() { 187_goto_gist() {
179 _gist_id $1 188 _gist_id $1
189
190 if [[ ! -d $folder/$GIST_ID ]]; then
191 echo 'Cloning gist as repo...'
192 git clone git@github.com:$GIST_ID.git $folder/$GIST_ID \
193 && echo 'Repo is cloned' \
194 || echo 'Failed to clone the gist'
195 fi
196
180 echo This gist is at $folder/$GIST_ID 197 echo This gist is at $folder/$GIST_ID
181 echo -e "You can run the following command to jump to this directory: \n" 198 echo -e "You can run the following command to jump to this directory: \n"
182 echo -e " \e[32m. gist $1\e[0m" 199 echo -e " \e[32m. gist $1\e[0m\n"
183 echo
184 cd $folder/$GIST_ID && ls && tig --all 2> /dev/null 200 cd $folder/$GIST_ID && ls && tig --all 2> /dev/null
185} 201}
186 202
203# TODO only remove deleted line
187_delete_gist() { 204_delete_gist() {
188 for i in "$@"; do 205 for i in "$@"; do
189 _gist_id "$i" 206 _gist_id "$i"
190 curl -X DELETE -s -H "$auth_header" $github_api/gists/$GIST_ID && \ 207 curl -X DELETE -s -H "$auth_header" $github_api/gists/$GIST_ID \
191 echo "$i" deleted 208 && echo "$i" deleted
192 done 209 done
193 _update 210 _update
194} 211}
@@ -196,8 +213,8 @@ _delete_gist() {
196# remove repos which are not in user gists anymore 213# remove repos which are not in user gists anymore
197_clean_repos() { 214_clean_repos() {
198 comm -23 <(find $folder -maxdepth 1 -type d | sed '1d; s#.*/##' | sort) \ 215 comm -23 <(find $folder -maxdepth 1 -type d | sed '1d; s#.*/##' | sort) \
199 <(cat $index | cut -d' ' -f2 | sed 's#.*/##' | sort) |\ 216 <(cat $index $starred 2> /dev/null | cut -d' ' -f2 | sed 's#.*/##' | sort) \
200 while read dir; do 217 | while read dir; do
201 mv $folder/$dir /tmp && echo move $folder/$dir to /tmp 218 mv $folder/$dir /tmp && echo move $folder/$dir to /tmp
202 done 219 done
203} 220}
@@ -205,11 +222,11 @@ _clean_repos() {
205# TODO format with simple text 222# TODO format with simple text
206_show_detail() { 223_show_detail() {
207 _gist_id $1 224 _gist_id $1
208 curl -s -H "$auth_header" $github_api/gists/$GIST_ID |\ 225 curl -s $github_api/gists/$GIST_ID \
209 jq '{site: .html_url, description: .description, public: .public, API: .url, created_at: .created_at, updated_at: .updated_at, files: (.files | keys)}' 226 | jq '{site: .html_url, description: .description, public: .public, API: .url, created_at: .created_at, updated_at: .updated_at, files: (.files | keys)}'
210 227
211 curl -s -H "$auth_header" $github_api/gists/$GIST_ID/comments |\ 228 curl -s $github_api/gists/$GIST_ID/comments \
212 jq '.[] | {user: .user.login, created_at: .created_at, updated_at: .updated_at, body: .body}' 229 | jq '.[] | {user: .user.login, created_at: .created_at, updated_at: .updated_at, body: .body}'
213} 230}
214 231
215_set_gist() { 232_set_gist() {
@@ -223,6 +240,7 @@ _set_gist() {
223 esac 240 esac
224 done 241 done
225 if [[ "$1" == '--' ]]; then shift; fi 242 if [[ "$1" == '--' ]]; then shift; fi
243 # TODO could be simplified?
226 files="$@" && echo $files | xargs ls > /dev/null || exit 1 244 files="$@" && echo $files | xargs ls > /dev/null || exit 1
227} 245}
228 246
@@ -231,32 +249,34 @@ _new_file() {
231 tmp_file=$(mktemp) 249 tmp_file=$(mktemp)
232 cat > $tmp_file 250 cat > $tmp_file
233 echo -e '\n' > /dev/tty 251 echo -e '\n' > /dev/tty
234 [[ -z "$1" ]] && echo -n 'Type file name: ' > /dev/tty && read filename 252 [[ -z "$1" ]] && read -p 'Type file name: ' filename < /dev/tty
235 mv $tmp_file /tmp/$filename 253 mv $tmp_file /tmp/$filename
236 echo /tmp/$filename 254 echo /tmp/$filename
237} 255}
238 256
239# create a new gist with files 257# create a new gist with files
240# FIXME error handling if gist is not created, file doesn't exist 258# TODO support secret gist
241_create_gist() { 259_create_gist() {
242 _set_gist "$@" 260 _set_gist "$@"
243 [[ -z "$files" ]] && files=$(_new_file $filename) 261 [[ -z "$files" ]] && files=$(_new_file $filename)
244 [[ -z "$description" ]] && echo -n 'Type description: ' && read description 262 [[ -z "$description" ]] && read -p 'Type description: ' description < /dev/tty
245 263
246 for file in $files; do 264 for file in $files; do
247 FILE=$(basename $file) 265 FILE=$(basename $file)
248 jq --arg FILE "$FILE" '. as $content | { ($FILE): {content: $content} }' -Rs $file 266 jq --arg FILE "$FILE" '. as $content | { ($FILE): {content: $content} }' -Rs $file
249 done |\ 267 done \
250 jq --slurp --arg DESC "$description" '{ 268 | jq --slurp --arg DESC "$description" '{
251 public: true, 269 public: true,
252 files: add, 270 files: add,
253 description: ($DESC) 271 description: ($DESC)
254 }' |\ 272 }' \
255 curl -H "$auth_header" --data @- $github_api/gists |\ 273 | curl -s -H "$auth_header" --data @- $github_api/gists \
256 sed '1 s/^/[/; $ s/$/]/' |\ 274 | sed '1 s/^/[/; $ s/$/]/' \
257 _parse_response |\ 275 | _parse_response \
258 sed -E "s/^/$(( $(wc -l $index | cut -d' ' -f1) + 1 )) /" >> $index && \ 276 | sed -E "s/^/$(( $(wc -l $index | cut -d' ' -f1) + 1 )) /" >> $index \
259 echo -e '\nGist created' 277 && echo -e '\nGist created' \
278 || echo 'Fail to create gist'
279
260 _show_list $index | tail -1 280 _show_list $index | tail -1
261} 281}
262 282
@@ -265,10 +285,10 @@ _edit_gist() {
265 _gist_id $1 285 _gist_id $1
266 286
267 echo -n 'Type new description: ' 287 echo -n 'Type new description: '
268 read DESC 288 read DESC < /dev/tty
269 jq -n --arg DESC "$DESC" '{ description: ($DESC) }' |\ 289 jq -n --arg DESC "$DESC" '{ description: ($DESC) }' \
270 curl -X PATCH -H "$auth_header" --data @- $github_api/gists/$GIST_ID > /dev/null && \ 290 | curl -X PATCH -H "$auth_header" --data @- $github_api/gists/$GIST_ID > /dev/null \
271 _update 291 && _update
272} 292}
273 293
274_help_message() { 294_help_message() {
@@ -277,20 +297,19 @@ _help_message() {
277 297
278_cases() { 298_cases() {
279 if [[ $1 == 'token' ]]; then 299 if [[ $1 == 'token' ]]; then
280 [[ ${#2} -eq 40 ]] && echo token=$2 ||\ 300 [[ ${#2} -eq 40 ]] && echo $1=$2 \
281 echo Invalid token format, it is not 40 chars '\n' > /dev/tty 301 || echo -e Invalid token format, it is not 40 chars '\n' > /dev/tty
282 elif [[ $1 == 'auto_sync' ]]; then 302 elif [[ $1 == 'auto_sync' ]]; then
283 [[ $2 == 'false' ]] && echo $1=$2 ||\ 303 [[ $2 == 'false' ]] && echo $1=$2 \
284 echo $1=true 304 || echo $1=true
285 elif [[ $1 == 'folder' ]]; then 305 elif [[ $1 == 'folder' ]]; then
286 [[ -n "$2" ]] && echo $1=$2 ||\ 306 [[ -n "$2" ]] && echo $1=$2 \
287 echo $1=~/gist 307 || echo $1=~/gist
288 elif [[ $1 == 'user' ]]; then 308 elif [[ $1 == 'user' ]]; then
289 echo $1=$2 309 echo $1=$2
290 fi 310 fi
291} 311}
292 312
293# TODO consider the case that $2 is empty -> remove original setting
294_configure() { 313_configure() {
295 [[ -z "$@" ]] && (vim $config) && exit 0 314 [[ -z "$@" ]] && (vim $config) && exit 0
296 target=$(_cases "$@") 315 target=$(_cases "$@")
@@ -299,7 +318,6 @@ _configure() {
299 cat $config 318 cat $config
300} 319}
301 320
302
303case "$1" in 321case "$1" in
304 "") 322 "")
305 _show_list $index ;; 323 _show_list $index ;;