From dcb5ec9713a192c5e754a81d628e44f5c240b211 Mon Sep 17 00:00:00 2001 From: Oscar Wallberg Date: Thu, 23 Apr 2026 21:38:56 +0200 Subject: [PATCH] refactor(setup): idempotent symlinks/copies, diff flag, flat COPIES --- setup.sh | 95 +++++++++++++++++++++++++++++++------------------------- 1 file changed, 52 insertions(+), 43 deletions(-) diff --git a/setup.sh b/setup.sh index 6c6de87..1490571 100755 --- a/setup.sh +++ b/setup.sh @@ -15,6 +15,7 @@ PRINT_HELP=false FORCE=false REMOVE_EXISTING=false IGNORE_EXISTING=false +DIFF=false ERROR=false # Define packages @@ -77,8 +78,9 @@ SYMLINKS=( typeset -a COPIES COPIES=( ".codex/config.toml" - ".config/gtk-3.0" - ".config/gtk-4.0" + ".config/gtk-3.0/bookmarks" + ".config/gtk-3.0/settings.ini" + ".config/gtk-4.0/settings.ini" ".gtkrc-2.0" ) @@ -95,7 +97,7 @@ typeset -A SYMLINK_MAP SYMLINK_MAP[zsh/rc]=".zshrc" error() { - msg="$1" + local msg="$@" ERROR=true echo "Error: $msg" >&2 } @@ -117,10 +119,10 @@ remove_symlink() { echo "Removing symlink: $link -> $src" rm "$link" elif test -e "$link"; then - error "object to be removed is not a symlink:" - error "${link}: $(stat -c '%F' -- "$link")" + error "object to be removed is not a symlink:" \ + "${link}: $(stat -c '%F' -- "$link")" - return 1 + return 0 fi } @@ -141,14 +143,12 @@ create_symlink() { rel_dst="$2" if test -z "$rel_src"; then - error "missing src argument:" - error "$0 $@" + error "missing src argument: $0 $@" return 1 fi if test -z "$rel_dst"; then - error "missing dst argument:" - error "$0 $@" + error "missing dst argument: $0 $@" return 1 fi @@ -157,8 +157,7 @@ create_symlink() { dst_parent="$(dirname -- "$dst")" if ! test -e "$src"; then - error "the following source path does not exist:" - error "$src" + error "the following source path does not exist: $src" return 1 fi @@ -168,26 +167,26 @@ create_symlink() { fi if test -L "$dst"; then + if test "$(readlink -f -- "$dst")" = "$src"; then + return 0 + fi + if $FORCE; then - if test "$(readlink -f "$dst")" != "$src"; then - remove_symlink "$2" - else - return 0 - fi + remove_symlink "$rel_dst" elif $IGNORE_EXISTING; then return 0 else - error "symbolic link already exists:" - error "$dst" - return 1 + error "symlink exists but points elsewhere:" \ + "$dst -> $(readlink -f -- "$dst")" + return 0 fi elif test -e "$dst"; then - error "path already exists that is not a symlink:" - error "${dst}: $(stat -c '%F' -- "$dst")" - return 1 + error "path already exists but is not a symlink:" \ + "${dst}: $(stat -c '%F' -- "$dst")" + return 0 fi - echo "Creating link: $dst -> $rel_src" + echo "Creating link: $dst -> $src" ln -s "$src" "$dst" } @@ -206,14 +205,12 @@ copy_item() { rel_dst="$2" if test -z "$rel_src"; then - error "missing src argument:" - error "$0 $@" + error "missing src argument: $0 $@" return 1 fi if test -z "$rel_dst"; then - error "missing dst argument:" - error "$0 $@" + error "missing dst argument: $0 $@" return 1 fi @@ -221,9 +218,8 @@ copy_item() { dst="${DEST_DIR}/$rel_dst" dst_parent="$(dirname -- "$dst")" - if ! test -e "$src"; then - error "the following source path does not exist:" - error "$src" + if ! test -f "$src"; then + error "source is not a regular file: $src" return 1 fi @@ -233,19 +229,26 @@ copy_item() { fi if test -e "$dst"; then + if cmp -s "$src" "$dst"; then + return 0 + fi + + if $DIFF; then + diff -u "$dst" "$src" || true + fi + if $FORCE; then remove_path "$dst" elif $IGNORE_EXISTING; then return 0 else - error "path already exists:" - error "${dst}" - return 1 + error "file already exists and differs: ${dst}" + return 0 fi fi echo "Copying item: from $rel_src to ${dst_parent}/" - cp -r "$src" "${dst_parent}/" + cp "$src" "${dst_parent}/" } create_all_symlinks() { @@ -270,8 +273,7 @@ install_system_file() { rel="$1" if test -z "$rel"; then - error "missing path argument:" - error "$0 $@" + error "missing path argument: $0 $@" return 1 fi @@ -280,8 +282,7 @@ install_system_file() { dst_parent="$(dirname -- "$dst")" if ! test -e "$src"; then - error "the following source path does not exist:" - error "$src" + error "the following source path does not exist: $src" return 1 fi @@ -295,14 +296,17 @@ install_system_file() { return 0 fi + if $DIFF; then + sudo diff -u "$dst" "$src" || true + fi + if $FORCE; then echo "Overwriting: $dst" elif $IGNORE_EXISTING; then return 0 else - error "system file already exists and differs (use --force to overwrite):" - error "$dst" - return 1 + error "system file already exists and differs: $dst" + return 0 fi fi @@ -319,7 +323,7 @@ install_all_system_files() { check_terminfo() { if ! infocmp tmux-256color > /dev/null; then error "Missing terminfo for tmux-256color. Try installing ncurses-term." - return 1 + return 0 fi } @@ -332,6 +336,7 @@ print_help() { echo " -f, --force Overwrite any existing links" echo " -i, --ignore-existing Ignore existing symlinks" echo " -r, --remove-existing Remove any existing symlinks" + echo " -d, --diff Show unified diff when a managed file differs" } while [ $# -gt 0 ]; do @@ -352,6 +357,10 @@ while [ $# -gt 0 ]; do IGNORE_EXISTING=true shift ;; + -d|--diff) + DIFF=true + shift + ;; *) error "unknown option: $1" PRINT_HELP=true