#!/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 # 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. 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] Set remotes and pull new changes where: -w set the working directory (default: ${WORKDIR}) -f set the git list file (default: ${DEFAULT_STATE}) -h show this help text -v increase output verbosity " 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 ;; -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 # If there are input files (for example) that follow the options, they # will remain in the "$@" positional parameters. FS_SEPARATOR="/" # We aren't going to run on windows. while read -r line; do dir=$(echo "$line" | cut -d, -f 1) remlist=$(echo "$line" | cut -d, -f 2-) clone=0 #False if [ $verbose -gt 0 ]; then echo "Operating on ${WORKDIR}${FS_SEPARATOR}${dir}" fi if [ ! -d "${WORKDIR}${FS_SEPARATOR}${dir}" ]; then #clone repo clone=$((clone + 1)) # Set true mkdir -p "${WORKDIR}${FS_SEPARATOR}${dir}" fi cd "${WORKDIR}${FS_SEPARATOR}${dir}" || exit if [ $clone -gt 0 ]; then git init fi if [ $verbose -gt 1 ]; then echo "Remote list: ${remlist}" fi echo "${remlist}" | awk -F ',' '{for (i = 1; i <= NF; i++) {printf "%s \n", $i}; printf "\n"}' | while read -r r || [ -n "$r" ]; do remoteName=$(echo "$r" | awk -F'=' '{print $1}') # Just get the remote name # Allow for blank / newlines during processing if [ "${remoteName}" = "" ]; then continue; fi if [ -d .git/refs/remotes/"$remoteName" ]; then if [ $verbose -gt 0 ]; then echo "Setting remote ${r}" fi echo "$r" | awk -F'=' '{ print $1, $2; }' | xargs -n 2 git remote set-url else if [ $verbose -gt 0 ]; then echo "Adding remote ${r}" fi echo "$r" | awk -F'=' '{ print $1, $2; }' | xargs -n 2 git remote add fi done if [ $clone -gt 0 ]; then git fetch --all rev=$(git ls-remote origin | grep HEAD | cut -f 1) if [ $verbose -gt 0 ]; then echo "Rev: ${rev}" fi br=$(git ls-remote origin | grep "${rev}" | grep -v HEAD | cut -f 2 | cut -d / -f 3 | head -n 1) if [ "$verbose" -gt 0 ]; then echo "Branch: ${br}" fi git switch "$br" fi done <"$DEFAULT_STATE" # Update all remotes if we have the fetchgit command if [ "$(command -v fetchgit)" ]; then find "$WORKDIR" -name ".git" -exec fetchgit {} \; fi