diff --git a/zsh/.zshrc b/zsh/.zshrc index 667005c..7895f47 100644 --- a/zsh/.zshrc +++ b/zsh/.zshrc @@ -27,16 +27,21 @@ update_dotfiles() { update_dotfiles &! -# On shell start, check the security tools repo for upstream updates and print a -# one-line notice if the checkout is behind. Notify only (never auto-pull). This -# stays read-only so it works even when the repo lives in root-owned /opt/tools: +# On shell start, check the security tools repo for upstream updates and queue a +# one-line notice if the checkout is behind. A precmd hook prints it between +# commands, rather than letting this background job write across other startup +# output or a prompt that is already being edited. Notify only (never auto-pull). +# The check stays read-only so it works even in root-owned /opt/tools: # - `safe.directory=*` sidesteps git's "dubious ownership" refusal on a repo # owned by root, which would otherwise fail every git command. # - `ls-remote` queries the remote without writing into .git (a normal user # can't write a root-owned .git, so `fetch` would fail there). # Uses the first candidate that is a git checkout; covers global and per-user layouts. check_tools_repo() { - local repo branch remote mergeref remote_sha local_sha cmd + local repo branch remote mergeref remote_sha local_sha cmd notice + local cache_dir="${ZDOTDIR:-$HOME}/.cache/zsh" + local notice_file="$cache_dir/tools-update-notice" + local notice_tmp="$notice_file.$$.tmp" # See update_dotfiles: bound the network probe (timeout, absent on macOS) and # disable ssh multiplexing so a stalled ls-remote can't orphan this &! job. local -a TO; (( $+commands[timeout] )) && TO=(timeout -k 5 10) @@ -53,11 +58,27 @@ check_tools_repo() { [[ "$remote_sha" == "$local_sha" ]] && return # already current $g merge-base --is-ancestor "$remote_sha" HEAD 2>/dev/null && return # remote is an ancestor: ahead/equal (also true if we lack the object -> falls through to "behind") [[ -w "$repo/.git" ]] && cmd="git -C $repo pull" || cmd="sudo git -C $repo pull" - print -u2 "⬆ tools: updates available in $repo — run: $cmd" + notice="⬆ tools: updates available in $repo — run: $cmd" + mkdir -p "$cache_dir" || return + print -r -- "$notice" >| "$notice_tmp" || return + mv -f "$notice_tmp" "$notice_file" return done } check_tools_repo &! + +show_tools_repo_notice() { + local cache_dir="${ZDOTDIR:-$HOME}/.cache/zsh" + local notice_file="$cache_dir/tools-update-notice" + local claimed_notice="$notice_file.$$.show" + [[ -s "$notice_file" ]] || return + mv "$notice_file" "$claimed_notice" 2>/dev/null || return + command cat "$claimed_notice" + command rm -f "$claimed_notice" +} +autoload -Uz add-zsh-hook +add-zsh-hook precmd show_tools_repo_notice + export LC_OSC52=1 # Load Antidote