bootstrap/dup

190 lines
4.4 KiB
Bash
Executable File

#!/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] [<targets>]"
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