#!/usr/bin/env sh here="$(readlink -f "$0")" && here="${here%/*}" && CDPATH= cd "$here" || exit #remote="https://github.com/notwa/rc/archive/master.tar.gz" remote="https://eaguru.guru/git/notwa/rc/archive/master.tar.gz" # NOTE: this script only updates files in subdirectories. # it does not update itself! warn() { printf >&2 %s\\n "$*" } do_clean() { true; } clean() { do_clean || warn 'update: failed to remove temporary files' do_clean() { true; } } die() { warn "update:" "$@" clean exit 1 } ! [ -d .git ] || die "you don't need this script when you have .git!" ! [ -e _new ] || die '"_new" already exists, please remove it before updating' backup="backup-$(date -u +%s)" || die 'failed to determine date' if ! [ -e sh/obtain ]; then url=https://eaguru.guru/git/notwa/rc/raw/branch/master/sh/obtain if curl 2>&-; [ $? = 2 ]; then acquire() { curl -fsS -m45 -o- "$*"; } elif wget 2>&-; [ $? = 1 ]; then acquire() { wget -qt1 -T45 -O- "$*"; } else die '"sh/obtain" missing, curl and wget missing as well' fi mkdir -p sh || die 'failed to create "sh" directory' acquire "$url" > sh/obtain && chmod +x sh/obtain || die 'failed to acquire "sh/obtain"' fi dummy() { :; } preload=dummy (. sh/obtain) || die 'failed to import "sh/obtain"' . sh/obtain || exit __obtain_prep do_clean() { rm dummy; } if ! __obtain_url https://eaguru.guru/t/dummy > dummy; then __obtain_bootstrap || die __obtain_url https://eaguru.guru/t/dummy > dummy || die fi do_clean() { rm dummy dummy.sha256sum; } printf >dummy.sha256sum '%s *%s\n' \ 1b577383bcfb9f191c785497f4ac34a8fb546807bd1094ef65d0ce9a5a63423e dummy || die 'failed to write file' sha256sum -c dummy.sha256sum >/dev/null || die 'failed to validate dummy file' clean do_clean() { rm update.tar.gz; } __obtain_url "$remote" > update.tar.gz || die 'failed to download new version' do_clean() { rm -r update.tar.gz _new_$$; } mkdir _new_$$ || die 'failed to create temporary directory' tar zxf update.tar.gz -C _new_$$ || die 'failed to extract update files' rm update.tar.gz || die 'failed to remove archive file' rename() { if [ -d _new_$$/rc-master ] then mv _new_$$/rc-master _new else mv _new_$$/rc _new fi } do_clean() { if [ -d _new ]; then rm -r _new_$$ _new; else rm -r _new_$$; fi; } rename || die 'failed to move update files' do_clean() { rm -r _new _new_$$; } rmdir _new_$$ || die discover() { find "$1" "_new/$1" -type f -exec sha256sum -- {} + } different() { awk ' { k = substr($0, 67) sub("^_new/", "", k) if (a[k]) { if (a[k] != $1) print k delete a[k] } else a[k] = $1 } END {for (k in a) print k}' } do_clean() { rm -r _new; } desire() { case "$1" in (*.bak) false;; (*/.git/*) false;; (vim/.netrwhist/*) false;; (vim/backup/*) false;; (vim/bundle/*) false;; (vim/swp/*) false;; (vim/undo/*) false;; (*) true esac } backup() { for f; do if ! [ -d "$backup/${f%/*}" ]; then mkdir -p -- "$backup/${f%/*}" || die 'failed to create backup directory' fi ! [ -f "$backup/$f" ] || die 'backup file already exists' cp -- "$f" "$backup/$f" || die 'failed to create backup file' done } for d in home sh vim; do discover "$d" > _new/hashes.txt || die 'failed to find new files' different < _new/hashes.txt > _new/updates.txt || die 'failed to compare files' LC_ALL=C sort < _new/updates.txt > _new/sorted.txt || die 'failed to sort file paths' while read -r f; do desire "$f" || continue if [ -f "_new/$f" ] && ! [ -f "$f" ]; then warn " + $f" cp -p "_new/$f" "$f" elif ! [ -f "_new/$f" ] && [ -f "$f" ]; then warn " - $f" elif [ "_new/$f" -nt "$f" ]; then # NOTE: this does not play well with git --patch. # don't use this script when you have git! warn " * $f" backup "$f" cp -p "_new/$f" "$f" elif [ "_new/$f" -ot "$f" ]; then warn " / $f" #else warn " = $f" fi done < _new/sorted.txt done clean