#!/bin/bash set -eu PULL_BASE="https://git.adamgoldsmith.name" DOTFILES_PULL_BASE="${PULL_BASE}/dotfiles" BOOTSTRAP_URL="${PULL_BASE}/adam/bootstrap.git" function sync_urls() { cd "$(dirname ${BASH_SOURCE[0]})" git remote set-url origin "$BOOTSTRAP_URL" git remote set-url --push --delete origin '.*' || true for dir in */ do git -C "$dir" remote set-url origin "$DOTFILES_PULL_BASE/${dir%/}.git" git -C "$dir" remote set-url --push --delete origin '.*' || true done } function do_get() { target="$1" if [ -d "$target" ] then echo "$target already exists, not getting" else echo "Getting $target" git clone "$DOTFILES_PULL_BASE/$target.git" --recurse-submodules fi } function do_pull() { dir="$1" function git_in_dir() { stdbuf -oL git -C "$dir" $@ } if [ "$stashAndSync" = true ] then git_in_dir pull --rebase --autostash git_in_dir push else git_in_dir pull fi } function do_pull_maybe_quiet() { function pull_header_line() { echo "$(tput $1)}$(tput sgr0) $(tput $2)$3$(tput sgr0): $4" } name="$1" dir="${2:-$name}" git_out="$(do_pull $dir 2>&1)" git_status=$? first_line="${git_out%%$'\n'*}" if [ $git_status -ne 0 ] then pull_header_line "setaf 1 bold" "setaf 1 bold" "$name" "$git_out" else case "$first_line" in "Already up to date.") unpushed_commits="$(git -C "$dir" rev-list @{upstream}..HEAD --count)" if [[ "$quiet" != "true" ]] then if [[ "$unpushed_commits" == "0" ]] then pull_header_line "setaf 4" bold "$name" "Up to date" else pull_header_line "setaf 6" "setaf 6 bold" "$name" "Up to date, $unpushed_commits unpushed commits" fi fi ;; Updating*) if [[ "$quiet" != "true" ]] then pull_header_line "setaf 4" bold "$name" "$first_line" git -C "${dir}" log --graph --color \ --format='%C(yellow)%h%C(reset) %s %C(cyan)(%cr)%C(reset)' \ ${first_line##Updating } \ | sed 's/^/ /' fi ;; *) pull_header_line "setaf 5 bold" "setaf 5 bold" "$name" "$git_out" esac fi } function run_script() { script="$1"; shift targets="$@" for target in $targets do if [ -e "$target/$script" ] then [[ "$quiet" == true ]] || echo "Running $target/$script" "$target/$script" ${quiet:+-q} fi done } function maybe_stow() { targets="$@" if [ "$stow" = true ] then run_script PRESTOW "$targets" stow -t"$HOME" --ignore="^PRESTOW$" --ignore="^POSTSTOW$" $targets run_script POSTSTOW "$targets" fi } quiet=false stow=true bootstrap=false stashAndSync=false while [ "$#" -gt 0 ] do case $1 in -ns | --no-stow) stow=false shift ;; -bs | --bootstrap) bootstrap=true shift ;; -s | --stash-and-sync) stashAndSync=true shift ;; -q | --quiet) quiet=true shift ;; --sync-urls) sync_urls exit ;; --) shift break ;; -?*) echo "Usage: $0 [-ns|--no-stow] [-bs|bootstrap] []" exit 1 ;; *) break esac done if [ "$bootstrap" = true ] then git clone "$BOOTSTRAP_URL" .dotfiles cd .dotfiles git remote set-url origin "$BOOTSTRAP_URL" else cd "$(dirname ${BASH_SOURCE[0]})" fi if [ "$#" -gt 0 ] then targets="$@" for target in $targets do do_get "$target" done maybe_stow "$targets" elif [ "$bootstrap" != true ] then do_pull_maybe_quiet .dotfiles . targets="$(find * -maxdepth 0 -type d -execdir test -e "{}/.git" \; -print)" if type parallel &> /dev/null then export quiet export -f do_pull do_pull_maybe_quiet parallel --max-args 1 do_pull_maybe_quiet ::: $targets else for dir in $targets do do_pull_maybe_quiet "$dir" done fi maybe_stow $targets fi