#!/usr/bin/env sh # POSIX shell implementation of Gitrect # # Operate on a tempfile and generate a listing of: # # prefix-trim-directory,remote=URL,... # # For all directories found in $WORKDIR # Operate on tempfile TEMPFILE="/tmp/gitrect.temp.$(xxd -l6 -p /dev/urandom)" touch $TEMPFILE # Reset all variables that might be set DEFAULT_STATE="$HOME/.local/share/git/repolist" WORKDIR="$HOME/.code" verbose=0 # Variables to be evaluated as shell arithmetic should be initialized to a default or validated beforehand. noconfirm=0 if [ ! $(command -v git) ]; then echo "git command not found. git must be installed and available in \$PATH to continue" exit 1 fi usage="$(basename "$0") [-h] [-v -w WORKDIR -f FILE] where: -w set the working directory (default: ${WORKDIR}) -f set the git list file (default: ${DEFAULT_STATE}) -y yes to all prompts (no confirmation) -h show this help text -v verbose output (multiple flags increase verbosity) (ex: '-v -v') " while :; do case $1 in -h | -\? | --help) # Call a "show_help" function to display a synopsis, then exit. echo "$usage" exit ;; -f) # Takes an option argument, ensuring it has been specified. if [ -n "$2" ]; then DEFAULT_STATE=$2 shift fi ;; -f=?*) DEFAULT_STATE=${1#*=} # Delete everything up to "=" and assign the remainder. ;; -f=) # Handle the case of an empty --file= printf 'ERROR: "-f" requires a non-empty option argument.\n' >&2 exit 1 ;; -w) # Takes an option argument, ensuring it has been specified. if [ -n "$2" ]; then WORKDIR=$2 shift fi ;; -w=?*) WORKDIR=${1#*=} # Delete everything up to "=" and assign the remainder. ;; -w=) # Handle the case of an empty --file= printf 'ERROR: "-w" requires a non-empty option argument.\n' >&2 exit 1 ;; -y) noconfirm=1 ;; -v) verbose=$((verbose + 1)) # Each -v argument adds 1 to verbosity. ;; --) # End of all options. shift break ;; -?*) printf 'WARN: Unknown option (ignored): %s\n' "$1" >&2 ;; *) # Default case: If no more options then break out of the loop. break ;; esac shift done # Make sure local state folder is available if [ ! -d "$HOME/.local/share" ]; then if [ $verbose -gt 0 ]; then echo "Creating directory: $HOME/.local/share" fi mkdir -p ~/.local/share fi # Rest of the program here. # If there are input files (for example) that follow the options, they # will remain in the "$@" positional parameters. if [ "$(command -v fd)" ]; then LIST=$(eval "fd -I -H -t d '\.git$' ${WORKDIR}") else LIST=$(eval "find -type d -name \.git ${WORKDIR}") fi # for each directory, create a line in TEMPFILE equivalent to: # short/path/here,origin=url1,upstream=url2,... # for dirpath in $LIST; do # shortpath trims the working directory prefix and the '.git' suffix from the directory shortpath=$(eval "echo $dirpath | sed -e 's,${WORKDIR}/,,' -e 's,/\.git/,,'") if [ $verbose -gt 1 ]; then echo "Repository found: ${shortpath}" >&2 fi cd "${dirpath}/.." # change into the parent of the git directory rems=$(eval "git remote") # list all remotes len_rems=${#rems} if [ $len_rems -lt 1 ]; then # If the list of remotes is zero, skip this folder continue fi # We haven't skipped the path, so write it to the file printf "%s" $shortpath >>$TEMPFILE for r in $rems; do url=$(eval "git remote get-url ${r}") printf ",%s=%s" $r $url >>$TEMPFILE if [ $verbose -gt 1 ]; then echo "remote: ${r} ${url} " >&2 fi done printf "\n" >>$TEMPFILE done # Sort results sort -o ${TEMPFILE} ${TEMPFILE} diffval=$(eval "diff -b ${DEFAULT_STATE} ${TEMPFILE}") if [ $? -eq 0 ]; then if [ $verbose -gt 0 ]; then echo "No change. Configuration already up to date." >&2 fi # Cleanup temp file rm "${TEMPFILE}" else if [ $verbose -gt 0 ]; then echo "Diff between current and updated state: " >&2 echo "$diffval" >&2 fi if [ $noconfirm -ne 0 ]; then # Overwite origiaal with the new mv "${TEMPFILE}" "${DEFAULT_STATE}" else printf 'Accept changes (y/n)? \n' old_stty_cfg=$(stty -g) stty raw -echo answer=$(while ! head -c 1 | grep -i '[ny]'; do true; done) stty $old_stty_cfg if [ "$answer" != "${answer#[Yy]}" ]; then echo "Updating file..." # Overwite origiaal with the new mv "${TEMPFILE}" "${DEFAULT_STATE}" else echo "Discarding changes..." rm "${TEMPFILE}" fi fi fi