dotfiles/.config/shell/bin/upd

189 lines
4.7 KiB
Bash
Executable file
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/bin/sh
# Update dotfiles and some other common repositories.
# This script accepts no arguments, but accepts additional repositories through the REPOS_TO_UPDATE environment variable
set -eu
#
# Setup functions and variables
#
# global name of script
script="${0##*/}"
cleanup() {
exit
}
# update_list_append from https://superuser.com/questions/39751/add-directory-to-path-if-its-not-already-there
# checks if a path is already in the PATH and if it exists
update_list_append() {
if [ -d "$1" ]; then
# shellcheck disable=SC3010
if command '[[' > /dev/null 2>&1 && [[ ":$REPOS_TO_UPDATE:" != *":$1:"* ]]; then
REPOS_TO_UPDATE="${REPOS_TO_UPDATE:+"$REPOS_TO_UPDATE:"}$1"
else
REPOS_TO_UPDATE="$REPOS_TO_UPDATE:$1"
fi
fi
}
# Do the arguments contain a search?
# Usage: contains search "${array[@]}"
contains() {
search="$1"; shift
split="$1"; shift
array="$1"; shift
ifs="$IFS"
IFS="$split"
for str in $array; do
if [ "$str" = "$search" ]; then
IFS="$ifs"
return 0
fi
done
IFS="$ifs"
return 1
}
# Shorten the repo name to use a ~ for the home dir instead of the absolute path
pretty_path() {
arg="$1"
case "$arg" in
# If the arg starts with our home dir,
"$HOME"*)
# replace the home dir part with a ~
printf '~%s' "$(printf '%s' "$arg" | sed -E 's/^.{'"${#HOME}"'}//')"
;;
# Otherwise,
*)
# Just print the arg
printf '%s' "${arg}"
;;
esac | # Pass through some other filters
sed -E 's_/+$__' | # Remove trailing slash
tr -s '/' # Remove duplicate slashes
}
# Warn about incomplete changes to a repository
do_checks() {
repo_pretty="$1"
shift
# Uncommitted changes
if ! "$@" diff --quiet; then
echo "${yellow}Warning: Working tree for $repo_pretty is dirty${nc}"
fi
# Unpushed changes
unpushed="$("$@" for-each-ref --format=" %(refname:short) %(push:track)" refs/heads)"
if echo "$unpushed" | grep -Fq ahead; then
printf '%s' "${yellow}Warning: Unpushed commits in $repo_pretty on branches:"
printf '%s' "$unpushed" | tr '\n' ','
echo "${nc}"
fi
}
do_pull() {
update_dotfiles="${update_dotfiles:-false}"
# Which repos have we updated so far
updated=''
#
# Main loop: `git pull` everything mentioned in the REPOS_TO_UPDATE variable
#
repo=''
for repo in "$@"; do
if [ -n "$repo" ]; then
repo_pretty="$(pretty_path "$repo")"
repo="$(realpath "$repo" 2>/dev/null)"
repo="$(git -C "$repo" rev-parse --show-toplevel 2> /dev/null || true)"
if [ -n "$repo" ]; then
if ! contains "$repo" ':' "$updated"; then
# Pull the repository
echo " Pulling ${green}$repo_pretty${nc}"
if ! timeout 10 git -C "$repo" pull; then
exit=$#
if [ "$ignore_git_errors" != true ]; then
return "$exit"
fi
fi
updated="$repo:$updated"
# Warn about incomplete changes to a repository
do_checks "$repo_pretty" git -C "$repo"
did_updates=true
if [ "$update_dotfiles" = 'false' ]; then
echo
fi
fi
fi
fi
done
# update dotfiles repo separately bc it's a bare repo
if [ "$update_dotfiles" = true ]; then
# check for dotfiles updates
${did_updates:-false} && echo
echo " Updating ${green}dotfiles${nc}"
dotfiles pull
do_checks "$(dotfiles rev-parse --git-dir)" dotfiles
fi
}
main() {
trap cleanup INT
# Check for git
if ! command -v git > /dev/null; then
echo "$script: git is not installed, please install git and try again" >&2
exit 1
fi
# Set colors
if command -v tput > /dev/null; then
yellow="$(tput setaf 3)"
green="$(tput setaf 2)"
nc="$(tput sgr0)"
elif [ -n "$TERMUX_VERSION" ]; then
yellow=""
green=""
nc="(B"
fi
# Default repos to update
ignore_git_errors=false
if [ $# = 0 ]; then
# Default paths to check
REPOS_TO_UPDATE="${REPOS_TO_UPDATE:-}"
set -- "$@" \
"${DOCS_DIR:-}" \
"$HOME/bin" \
"${NIXOS_DIR:-}" \
"$HOME/code/faust-ideas" \
"$HOME/code/nixvim-config" \
"$HOME/.config/nvim"
split="$IFS"
IFS=':'
for dir in $REPOS_TO_UPDATE; do
set -- "$dir" "$@"
done
IFS="$split"
update_dotfiles=true
else
ignore_git_errors="${IGNORE_GIT_ERRORS:-true}"
fi
do_pull "$@"
}
main "$@"