install.sh: merge PERSONAL_DIRS contents instead of wholesale replace
The previous deploy_one() did `mv $HOME/<dir> $BACKUP_DIR/<dir>` then `cp -a $YADR_DIR/<dir> $HOME/<dir>` for every entry in PERSONAL_DIRS. For dirs the repo only partially populates (notably .local — repo only tracks .local/bin/), this swept away unrelated user data: the most recent re-bootstrap moved ~/.local/share/fonts/ (Intel One Mono, Open Gorton, Roboto Mono, GALLAUDET, code128) into the timestamped backup, making them appear missing. Rework deploy logic: - deploy_file: copies one file/symlink, backing up only the conflicting destination (if any). Idempotent via paths_equivalent() so re-runs with no changes produce no output and no spurious backups. - deploy_dir: walks the repo's tree for that dir and deploys each leaf via deploy_file. Files in $HOME the repo doesn't know about are left untouched. Subdirs are mkdir'd as needed. Also: track the personal fonts at .local/share/fonts/ so they redeploy on every install, and run fc-cache -f at the end so apps see them without a logout/login. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+74
-14
@@ -30,7 +30,11 @@ PERSONAL_FILES=(
|
|||||||
.zprofile .zshenv .zshrc
|
.zprofile .zshenv .zshrc
|
||||||
)
|
)
|
||||||
|
|
||||||
# Directories deployed wholesale to $HOME/<dir>/.
|
# Directories whose contents are merged into $HOME/<dir>/, file by file. Files
|
||||||
|
# the repo provides replace conflicting on-disk versions (with the displaced
|
||||||
|
# version preserved in $BACKUP_DIR); files outside the repo's tree are left
|
||||||
|
# untouched. This deliberately avoids wholesale-replacing $HOME/.local etc.,
|
||||||
|
# which would sweep away unrelated user data (fonts, app state, ...).
|
||||||
PERSONAL_DIRS=(
|
PERSONAL_DIRS=(
|
||||||
.fonts .irssi .nano .themes .local .mplayer
|
.fonts .irssi .nano .themes .local .mplayer
|
||||||
)
|
)
|
||||||
@@ -83,31 +87,80 @@ else
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
# 3. Deploy personal dotfiles
|
# 3. Deploy personal dotfiles
|
||||||
backup_one() {
|
|
||||||
local src_name="$1"
|
# Move $HOME/<rel> aside into $BACKUP_DIR, preserving its sub-path.
|
||||||
local dst="$HOME/$src_name"
|
backup_one_path() {
|
||||||
|
local rel="$1"
|
||||||
|
local dst="$HOME/$rel"
|
||||||
if [ -e "$dst" ] || [ -L "$dst" ]; then
|
if [ -e "$dst" ] || [ -L "$dst" ]; then
|
||||||
mkdir -p "$BACKUP_DIR/$(dirname "$src_name")"
|
mkdir -p "$BACKUP_DIR/$(dirname "$rel")"
|
||||||
mv "$dst" "$BACKUP_DIR/$src_name"
|
mv "$dst" "$BACKUP_DIR/$rel"
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
deploy_one() {
|
# Returns 0 iff $1 and $2 are equivalent (same symlink target, or identical
|
||||||
local name="$1"
|
# regular-file content). Used to make re-runs idempotent: unchanged files get
|
||||||
local src="$YADR_DIR/$name"
|
# skipped instead of needlessly backed up.
|
||||||
local dst="$HOME/$name"
|
paths_equivalent() {
|
||||||
|
local a="$1" b="$2"
|
||||||
|
if [ -L "$a" ] && [ -L "$b" ]; then
|
||||||
|
[ "$(readlink "$a")" = "$(readlink "$b")" ]
|
||||||
|
elif [ -L "$a" ] || [ -L "$b" ]; then
|
||||||
|
return 1
|
||||||
|
elif [ -f "$a" ] && [ -f "$b" ]; then
|
||||||
|
cmp -s "$a" "$b"
|
||||||
|
else
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Deploy one file or symlink at $YADR_DIR/<rel> to $HOME/<rel>. If a different
|
||||||
|
# file/symlink is already at the destination, it's moved into $BACKUP_DIR first.
|
||||||
|
deploy_file() {
|
||||||
|
local rel="$1"
|
||||||
|
local src="$YADR_DIR/$rel"
|
||||||
|
local dst="$HOME/$rel"
|
||||||
if [ ! -e "$src" ] && [ ! -L "$src" ]; then
|
if [ ! -e "$src" ] && [ ! -L "$src" ]; then
|
||||||
return
|
return
|
||||||
fi
|
fi
|
||||||
backup_one "$name"
|
if paths_equivalent "$src" "$dst"; then
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
backup_one_path "$rel"
|
||||||
mkdir -p "$(dirname "$dst")"
|
mkdir -p "$(dirname "$dst")"
|
||||||
cp -a "$src" "$dst"
|
cp -a "$src" "$dst"
|
||||||
info "$name"
|
info "$rel"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Deploy a directory by walking its tree and deploying each file/symlink in
|
||||||
|
# turn. Directories get mkdir'd; existing entries inside $HOME/<rel> that the
|
||||||
|
# repo doesn't know about are left alone. This is the merge semantics that
|
||||||
|
# protects e.g. $HOME/.local/share/fonts from being clobbered when the repo
|
||||||
|
# only tracks $HOME/.local/bin.
|
||||||
|
deploy_dir() {
|
||||||
|
local rel="$1"
|
||||||
|
local src="$YADR_DIR/$rel"
|
||||||
|
if [ ! -d "$src" ] || [ -L "$src" ]; then
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
mkdir -p "$HOME/$rel"
|
||||||
|
local sub sub_rel src_path
|
||||||
|
while IFS= read -r -d '' sub; do
|
||||||
|
sub="${sub#./}"
|
||||||
|
[ "$sub" = "." ] && continue
|
||||||
|
sub_rel="$rel/$sub"
|
||||||
|
src_path="$YADR_DIR/$sub_rel"
|
||||||
|
if [ -d "$src_path" ] && [ ! -L "$src_path" ]; then
|
||||||
|
mkdir -p "$HOME/$sub_rel"
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
deploy_file "$sub_rel"
|
||||||
|
done < <(cd "$src" && find . -mindepth 1 -print0)
|
||||||
}
|
}
|
||||||
|
|
||||||
log "Deploying personal dotfiles"
|
log "Deploying personal dotfiles"
|
||||||
for f in "${PERSONAL_FILES[@]}"; do deploy_one "$f"; done
|
for f in "${PERSONAL_FILES[@]}"; do deploy_file "$f"; done
|
||||||
for d in "${PERSONAL_DIRS[@]}"; do deploy_one "$d"; done
|
for d in "${PERSONAL_DIRS[@]}"; do deploy_dir "$d"; done
|
||||||
|
|
||||||
# .local/bin/claude is a relative symlink to ../share/claude/versions/...
|
# .local/bin/claude is a relative symlink to ../share/claude/versions/...
|
||||||
# If that target isn't present on this machine, remove the dangling link so
|
# If that target isn't present on this machine, remove the dangling link so
|
||||||
@@ -137,6 +190,13 @@ if [ -d "$HOME/.local/bin" ]; then
|
|||||||
find "$HOME/.local/bin" -maxdepth 1 -type f -exec chmod +x {} \; 2>/dev/null || true
|
find "$HOME/.local/bin" -maxdepth 1 -type f -exec chmod +x {} \; 2>/dev/null || true
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# 5. Refresh font cache so newly-deployed .fonts/ and .local/share/fonts/
|
||||||
|
# entries are visible to apps without a logout/login.
|
||||||
|
if have fc-cache; then
|
||||||
|
log "Refreshing font cache"
|
||||||
|
fc-cache -f >/dev/null 2>&1 || warn "fc-cache returned non-zero; continuing"
|
||||||
|
fi
|
||||||
|
|
||||||
echo
|
echo
|
||||||
log "Done."
|
log "Done."
|
||||||
if [ -d "$BACKUP_DIR" ]; then
|
if [ -d "$BACKUP_DIR" ]; then
|
||||||
|
|||||||
Reference in New Issue
Block a user