#!/usr/bin/env bash # # Author: Hsieh Chin Fan (typebrook) # License: MIT # https://gist.github.com/typebrook/b0d2e7e67aa50298fdf8111ae7466b56 # # # This script host your gists as local Github repo # It works under GNU with jq and curl, both are easy to get in most cases # # Use the following commands to manage your gists: # # * update your gists list with Github API # gist [update | u] # # * list your gists with format: [number] [url] [file_num] [comment_num] [short description] # gist # # * clone gist repos which are not in local # * pull master branch if a local repo is behind its remote # gist [sync | s] # # * Go to local gist repo # gist # # * create a new gist with a file and description # gist [create | c] "" # # * show the detail of a gist # gist [detail | d] # # * edit a gist description # gist [edit | e] # # * delete a gist # gist [delete | D] # # * clean removed gists in local # gist [clean | C] # * show this help message # gist [help | h] # define your environmemnts here # TODO support auth prompt #------------------- github_api_token=$(cat $SETTING_DIR/tokens/github) user=typebrook folder=~/git/gist #------------------- github_api=https://api.github.com auth_header="Authorization: token $github_api_token" mkdir -p $folder index=$folder/index # Validate settings. [ "$TRACE" ] && set -x # Show the list of gist, but not updated time _show_list() { cat $index |\ while read line_num link file_url_array file_num extra description; do repo=$folder/$(echo $link | sed 's#.*/##') # if there is something need to commit cd $repo && [[ -n $(git status --short) ]] && extra="\e[36m[working]\e[0m" echo -e $line_num $link $file_num $extra $description done } # get the list of gists # TODO show git status outdated/ahead/working # TODO support secret gist _update() { curl -s -H "$auth_header" $github_api/users/$user/gists |\ jq '.[] | "\(.html_url) \([.files[] | .raw_url]) \(.files | keys | length) \(.comments) \(.description)"' |\ tac | nl |\ while read line_num link file_url_array file_num comment_num description; do blob_code=$(echo $file_url_array | jq -r '.[]' | sed -r 's#.*raw/(.*)/.*#\1#' | sort | cut -c -7 | paste -sd '-') echo $line_num $link $blob_code $file_num $comment_num $(echo $description | cut -c -70) | tr -d '"' done > $index && \ _show_list (_sync_repos > /dev/null 2>&1 &) } _sync_repos() { # clone repos which are not in the local comm -13 <(find $folder -maxdepth 1 -type d | sed '1d; s#.*/##' | sort) \ <(cat $index | cut -d' ' -f2 | sed 's#.*/##' | sort) |\ xargs -I{} git clone git@github.com:{}.git $folder/{} # pull if remote repo has different blob objects cat $index | cut -d' ' -f2,3 |\ while read url blob_code_remote; do repo=$folder/$(echo $url | sed 's#.*/##') blob_code_local=$(cd $repo && git ls-tree master | cut -d' ' -f3 | cut -c-7 | sort | paste -sd '-') cd $repo && \ [[ $blob_code_local != $blob_code_remote ]] && \ [[ $(git rev-parse origin/master) == $(git rev-parse master) ]] && \ git pull done echo Everything is fine! } _gist_id() { cat $index | sed -n "$1"p | cut -d' ' -f2 | sed -r 's#.*/##' } _goto_gist() { gist_num=$(wc -l $index | cut -d' ' -f1) if [[ ! "$1" =~ [0-9]+ ]] || (( $1 > $gist_num )); then echo Not a valid gist number: $1 echo Use the number in the first column instead: echo _show_list return 0 fi GIST_ID=$(_gist_id $1) echo This gist is at $folder/$GIST_ID cd $folder/$GIST_ID && tig --all 2> /dev/null } _delete_gist() { GIST_ID=$(_gist_id $1) curl -X DELETE -s -H "$auth_header" $github_api/gists/$GIST_ID && \ _update } # remove repos which are not in user gists anymore _clean_repos() { comm -23 <(find $folder -maxdepth 1 -type d | sed '1d; s#.*/##' | sort) \ <(cat $index | cut -d' ' -f2 | sed 's#.*/##' | sort) |\ while read dir; do mv $folder/$dir /tmp && echo move $folder/$dir to /tmp done } # TODO star count _show_detail() { GIST_ID=$(_gist_id $1) curl -s -H "$auth_header" $github_api/gists/$GIST_ID |\ jq '{site: .html_url, description: .description, API: .url, created_at: .created_at, updated_at: .updated_at, files: (.files | keys)}' curl -s -H "$auth_header" $github_api/gists/$GIST_ID/comments |\ jq '.[] | {user: .user.login, created_at: .created_at, updated_at: .updated_at, body: .body}' } # create a new gist with files _create_gist() { echo -n 'description: ' read DESC echo $@ | tr " " "\n" |\ while read file; do FILE=$(basename $file) jq --arg FILE "$FILE" '. as $content | { ($FILE): {content: $content} }' -Rs $file done |\ jq --slurp --arg DESC "$DESC" '{ public: true, files: add, description: ($DESC) }' |\ curl -s -H "$auth_header" --data @- $github_api/gists > /dev/null && \ _update && _sync_repos } # update description of a gist _edit_gist() { GIST_ID=$(_gist_id $1) jq -n --arg DESC "$2" '{ description: ($DESC) }' |\ curl -X PATCH -H "$auth_header" --data @- $github_api/gists/$GIST_ID > /dev/null && \ _update } _help_message() { sed -r -n ' /^$/ q; 8,$ s/^#//p' $0 } case "$1" in "") _show_list ;; create | c) shift; _create_gist $@ ;; edit | e) _edit_gist "$2" "$3" ;; update | u) _update ;; sync | s) _sync_repos ;; detail | d) _show_detail "$2" ;; delete | D) _delete_gist "$2" ;; clean | C) _clean_repos ;; help | h) _help_message ;; *) _goto_gist "$1" ;; esac