# Functions used for interactive installation of new changes to running system # vim: ft=sh # Ask if given section should be installed # First argument is name (take care not to use special characters for regulard # expression) and second argument is a question ask() { local ignore_file=".ignore-$(hostname)" [ -f "$ignore_file" ] && grep -q "^$1$" "$ignore_file" && return 1 if $FORCE; then echo "\e[1;34m$2\e[0m" # Fall trough with 0 exit (always yes) else echo -e -n "\e[1;34m$2? (Y/n) \e[0m" local reply read -r reply echo "$reply" | grep -qE '^[Yy]?$' fi } dodiff() { if [ -d "$2" ]; then # If we just copying some file to directory OUT=$2/$(basename "$1") else OUT=$2 fi if ! [ -f "$OUT" ]; then echo -e "\e[1;33mNot installed:\e[0m $1 => $OUT" if ask "Install?"; then doinst "$1" "$OUT" fi return fi if cmp "$1" "$OUT" >/dev/null 2>&1; then echo -e "\e[1;32mNo difference detected:\e[0m $OUT" return fi if $FORCE; then doinst "$1" "$OUT" else nvim -d "$1" "$OUT" fi } # Managing two git trees with master has small inconvenience that git allows only # single branch checkout in all work trees, so as it sets now git will execute all # commands not on deployed tree but on tree in this repository, so we need specify # work tree on command line every time we want target deployed work tree. gitrepo_relink() { local GITD="gitdir: $PWD/.git$(sed "s/^gitdir: [./]*git//" "$1")" # We check that we are pointing to correct path just because of making message correct if ! grep -q "$GITD" "$2"; then echo -e "\e[1;34mPointing git repository $2 to this repository\e[0m" echo "$GITD" > "$2" fi # else probably not a git repository or who knows. } checkdiff() { # Iterate trough source directory but ignore any git repositories # Note that it's design decision to not iterate trough target directory. if [ -d "$1" ]; then # This is check if we have correct inst command basically. If it is # directory than it have to have trailing slash to ensure that no # additional directory is created. if ! echo "$1" | grep -qE '/$'; then echo -e "\e[1;31mERROR: Directory without trailing slash detected:\e[0m $1" exit 1 fi # Got trough all files ignoring git repositories for f in `find "$1" \( -type d -exec test -e '{}'/.git \; \) -prune -o -type f -print`; do F="${f#$1}" dodiff "$1/$F" "$2/$F" done # Check if we have all directories ignoring those in git repositories for d in `find "$1" -type d -print -exec test -e '{}'/.git \; -prune`; do D="${d#$1}" if [ ! -d "$2/$D" ]; then echo -e "\e[1;33mDirectory not installed:\e[0m $1/$D => $2/$D" if ask "Install?"; then doinst "$1/$D/" "$2/$D" fi fi done # Now checkout git repositories for g in `find "$1" -type d -exec test -e '{}'/.git \; -print -prune`; do G="$2/${g#$1}" gitrepo_relink "$g/.git" "$G/.git" # Always reling .git just to be sure PREV="$(pwd)" cd "$G" # Check if we have any change at all if git --work-tree=. diff --exit-code -s; then echo -e "\e[1;32mNo difference detected in git:\e[0m $G" else echo -e "\e[0;32mCheckout of git repository:\e[0m $G" # Checkout all files to HEAD git --work-tree=. checkout -f HEAD # Update all submodules git --work-tree=. submodule update --recursive fi cd "$PREV" done else dodiff "$1" "$2" fi } doinst() { echo -e "\e[1;34mrsync -rlpt $1 $2\e[0m" mkdir -p "$(dirname "$2")" rsync -rlpt $1 $2 # Now edit all .git files in target directory for g in `find "$1" -name '.git' -type f`; do gitrepo_relink "$g" "$2/${g#$1}" done } inst() { if [ ! -e "$1" ]; then echo "Missing file to be installed: $1" >&2 fi if [ -e "$2" ]; then # If output exists, execute diff instead checkdiff $1 $2 return fi doinst $1 $2 } # gpg encrypted install ginst() { if [ -z "$PASS" ]; then PASS="$(gpg --batch --decrypt pass.gpg)" fi # TODO probably we should be sure that file will be always removed local TMP="$(mktemp myconfigs.XXXXXXXXXX)" gpg --batch --passphase "$PASS" --output "$TMP" --decrypt "$1" inst "$TMP" "$2" gpg --batch --passphase "$PASS" --output "$1" --encrypt "$TMP" }