adding gitsnips.sh
This commit is contained in:
parent
cd2ed4866b
commit
de577c1263
1 changed files with 214 additions and 0 deletions
214
gitsnips.sh
Executable file
214
gitsnips.sh
Executable file
|
|
@ -0,0 +1,214 @@
|
|||
#!/usr/bin/env bash
|
||||
#
|
||||
# Backup GitLab snippets to combined repo using git subtrees
|
||||
#
|
||||
# Required:
|
||||
#
|
||||
# - GitLab personal API token with read_api privilege
|
||||
# - Automated git project for storing snippets
|
||||
# - curl, git, jq, find, mktemp
|
||||
#
|
||||
# tl;dr
|
||||
#
|
||||
# 1. Create GitLab API token with 'read_api' access (private snippets)
|
||||
# 2. Create a new private gitlab project, then clone and configure
|
||||
#
|
||||
# git clone git@gitlab.com:username/snippets.git
|
||||
# cd snippets
|
||||
# git config user.name "username"
|
||||
# git config user.email "username@email.com"
|
||||
#
|
||||
# 3. If using multiple GitLab accounts/SSH keys:
|
||||
#
|
||||
# git config core.sshCommand "ssh -i ~/.ssh/username -F /dev/null"
|
||||
#
|
||||
# 4. Specify the token and project directory with '-t ... -d ...'
|
||||
#
|
||||
# ./gitsnips.sh -t ABCDEF1234 -d ../snippets/ -p
|
||||
#
|
||||
# 5. Review the above changes and `git push` the results when ready
|
||||
#
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
_VERSION="0.0.3"
|
||||
_NAME=$(basename "${0}")
|
||||
|
||||
# usage
|
||||
function usage() {
|
||||
echo "${_NAME} version ${_VERSION}"
|
||||
echo
|
||||
echo "Usage: ${_NAME} [OPTIONS...]"
|
||||
echo
|
||||
echo " Options:"
|
||||
echo " -d <dir> Git project directory (default: ./)"
|
||||
echo " -t <string> GitLab token (read_api)"
|
||||
echo " -i <file> Markdown index file (default: INDEX.md)"
|
||||
echo " -s <file> Snippets JSON file (default: snippets.json)"
|
||||
echo " -p Prune removed snippets (git rm -r)"
|
||||
echo " -q Suppress output (quiet)"
|
||||
echo " -V Version of program"
|
||||
echo " -h This help text"
|
||||
echo
|
||||
}
|
||||
|
||||
# defaults
|
||||
declare _GITDIR="./"
|
||||
declare _TOKEN=""
|
||||
declare _MDIDX="INDEX.md"
|
||||
declare _SNJSON="snippets.json"
|
||||
declare _PRUNE=0
|
||||
declare _VERBOSE=1
|
||||
|
||||
# user input
|
||||
while getopts "d:t:i:s:pqVh" opt; do
|
||||
case "$opt" in
|
||||
d)
|
||||
_GITDIR="${OPTARG}" ;;
|
||||
t)
|
||||
_TOKEN="${OPTARG}" ;;
|
||||
i)
|
||||
_MDIDX="${OPTARG}" ;;
|
||||
s)
|
||||
_SNJSON="${OPTARG}" ;;
|
||||
p)
|
||||
_PRUNE=1 ;;
|
||||
q)
|
||||
_VERBOSE=0 ;;
|
||||
V)
|
||||
echo "${_NAME} version ${_VERSION}"
|
||||
exit 0 ;;
|
||||
h)
|
||||
usage
|
||||
exit 0 ;;
|
||||
*)
|
||||
echo "Unrecognized option: $OPTARG (Run '$_NAME -h' for help)"
|
||||
exit 1 ;;
|
||||
esac
|
||||
done
|
||||
shift $((OPTIND-1))
|
||||
|
||||
# handy for verbose/quiet
|
||||
function noise {
|
||||
local _MSG="$*"
|
||||
if [[ ${_VERBOSE} -eq 1 ]]; then
|
||||
echo "${_MSG}"
|
||||
fi
|
||||
}
|
||||
|
||||
# loop for checking apps
|
||||
function checkapp() {
|
||||
local _XAPPX="$1"
|
||||
if [[ -z "$(command -v ${_XAPPX} 2>/dev/null)" ]]; then
|
||||
noise "Application ${_XAPPX} not found, exiting."
|
||||
exit 99
|
||||
fi
|
||||
}
|
||||
|
||||
# loop for checking directories
|
||||
function checkdir() {
|
||||
local _XDIRX="$1"
|
||||
if [[ ! -d "${_XDIRX}" ]]; then
|
||||
noise "Directory ${_XDIRX} not found, exiting."
|
||||
exit 98
|
||||
fi
|
||||
if [[ ! -w "${_XDIRX}" ]]; then
|
||||
noise "Directory ${_XDIRX} not writable, exiting."
|
||||
exit 97
|
||||
fi
|
||||
_GDIRG="${_XDIRX%/}/.git"
|
||||
if [[ ! -d "${_GDIRG}" ]]; then
|
||||
noise "Directory ${_XDIRX} is not a git project, exiting."
|
||||
exit 96
|
||||
fi
|
||||
}
|
||||
|
||||
# ensure we can run properly
|
||||
function preflight() {
|
||||
# apps
|
||||
checkapp curl
|
||||
checkapp jq
|
||||
# dirs
|
||||
checkdir "${_GITDIR}"
|
||||
# token
|
||||
if [[ -z "${_TOKEN}" ]]; then
|
||||
noise "Token length zero; valid token required, exiting."
|
||||
exit 9
|
||||
fi
|
||||
}
|
||||
|
||||
# this could exit
|
||||
preflight
|
||||
|
||||
# prep for work
|
||||
noise "Using ${_GITDIR} as git repository"
|
||||
pushd "${_GITDIR}" >/dev/null
|
||||
|
||||
# fetch latest index
|
||||
noise "Fetching latest snippet index"
|
||||
curl --silent --header "PRIVATE-TOKEN: ${_TOKEN}" \
|
||||
"https://gitlab.com/api/v4/snippets?per_page=65534" \
|
||||
| jq > "${_SNJSON}"
|
||||
|
||||
git add "${_SNJSON}"
|
||||
git commit -q -m "snippet list update" "${_SNJSON}"
|
||||
|
||||
# generate list of IDs
|
||||
noise "Extracting list of snippets with jq"
|
||||
# create an array string [1234]="title" for each item...
|
||||
IDLIST=$(jq -r '.[] | "[\(.id)]=\"\(.title)\""' "${_SNJSON}")
|
||||
# ...adding () around it creates a natural array input string
|
||||
declare -A IDARRAY=$(echo "(${IDLIST})")
|
||||
|
||||
# human friendly index
|
||||
# - 'git subtree' needs a clean working directory
|
||||
_TMPIDX=$(mktemp)
|
||||
echo -e "# Snippet Index\n" > "${_TMPIDX}"
|
||||
|
||||
# loop the IDs and either update or add
|
||||
IDSORTED=$(echo "${!IDARRAY[@]}" | tr ' ' '\n' | sort -n | tr '\n' ' ')
|
||||
# do not quote IDSORTED below
|
||||
for id in ${IDSORTED}; do
|
||||
if [[ -d "./${id}" ]]; then
|
||||
noise "Updating snippet ${id}"
|
||||
git subtree pull -q -P "${id}" -m "Updating ${id}" \
|
||||
"git@gitlab.com:snippets/${id}.git" HEAD
|
||||
else
|
||||
noise "Adding snippet ${id}"
|
||||
git subtree add -q -P "${id}" -m "Adding ${id}" \
|
||||
"git@gitlab.com:snippets/${id}.git" HEAD
|
||||
fi
|
||||
echo " * [${id}](${id}) ${IDARRAY[$id]}" >> "${_TMPIDX}"
|
||||
# be nice to gitlab
|
||||
sleep 1
|
||||
done
|
||||
|
||||
# commit the updated Markdown index
|
||||
noise "Building ${_MDIDX}"
|
||||
mv -f "${_TMPIDX}" "${_MDIDX}"
|
||||
git add "${_MDIDX}"
|
||||
git commit -q -m "markdown index update" "${_MDIDX}"
|
||||
|
||||
# prune stale items
|
||||
if [[ ${_PRUNE} -eq 1 ]]; then
|
||||
noise "Pruning stale snippets"
|
||||
_RGX='^[0-9]+$'
|
||||
# this gives a list of top level dirs without "./" or any hidden subdirs
|
||||
_LDIRS=$(find ./ -mindepth 1 -maxdepth 1 -type d -not -path '*/\.*' -printf '%P\n')
|
||||
for dir in ${_LDIRS}; do
|
||||
if [[ ! ${dir} =~ ${_RGX} ]]; then
|
||||
# directory is not a number
|
||||
noise "Directory ${dir} is NaN, skipping"
|
||||
continue
|
||||
fi
|
||||
if [[ ! ${IDARRAY[$dir]+_} ]]; then
|
||||
# if dir is not an array key, remove it
|
||||
noise "Pruning ${dir} not in snippet index"
|
||||
git rm -r ${dir}
|
||||
git commit -q -m "Removing ${dir}" ${dir}
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
# back to where we started
|
||||
popd >/dev/null
|
||||
noise "Done - review results and push updates to origin as appropriate"
|
||||
Reference in a new issue