diff --git a/zsh/.zshrc b/zsh/.zshrc index a1ec16c..308cbb3 100644 --- a/zsh/.zshrc +++ b/zsh/.zshrc @@ -48,6 +48,34 @@ if [ "$shared_config" -eq 0 ]; then export GIT_COMMITTER_EMAIL=$GIT_AUTHOR_EMAIL fi +# 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: +# - `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 + for repo in /opt/tools "$HOME/tools" "$HOME/tools/tools-repo"; do + local -a g=(git -c 'safe.directory=*' -C "$repo") + $g rev-parse --is-inside-work-tree >/dev/null 2>&1 || continue + branch=$($g symbolic-ref --short HEAD 2>/dev/null) || return + remote=$($g config "branch.$branch.remote" 2>/dev/null) || return # no upstream + mergeref=$($g config "branch.$branch.merge" 2>/dev/null) || return + remote_sha=$($g ls-remote "$remote" "$mergeref" 2>/dev/null | awk '{print $1}') + local_sha=$($g rev-parse HEAD 2>/dev/null) + [[ -n "$remote_sha" && -n "$local_sha" ]] || return # remote unreachable + [[ "$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" + return + done +} +check_tools_repo &! + # Load Antidote mkdir -p ${ZDOTDIR:-~}/.cache/zsh static_file=${ZDOTDIR:-~}/.cache/zsh/.zsh_plugins.zsh