[ZSH] Extract shared startup modules
Keep the server entrypoint focused on server policy while moving update checks, Antidote loading, interactive defaults, and prompt sourcing into reusable modules.
This commit is contained in:
+18
-182
@@ -1,18 +1,16 @@
|
|||||||
export PATH="/snap/bin:$HOME/.local/bin:$HOME/dotfiles/scripts:$PATH"
|
export PATH="/snap/bin:$HOME/.local/bin:$HOME/dotfiles/scripts:$PATH"
|
||||||
export XDG_CONFIG_HOME="$HOME/.config" # Fix nvim bug
|
export XDG_CONFIG_HOME="$HOME/.config"
|
||||||
|
|
||||||
|
|
||||||
[[ -z $SSH_AUTH_SOCK ]] || export FORWARD_SOCK=$SSH_AUTH_SOCK
|
[[ -z $SSH_AUTH_SOCK ]] || export FORWARD_SOCK=$SSH_AUTH_SOCK
|
||||||
|
|
||||||
[[ -f ~/.zsh/.powerline_config ]] && source ~/.zsh/.powerline_config
|
[[ -f ~/.zsh/.powerline_config ]] && source ~/.zsh/.powerline_config
|
||||||
|
|
||||||
if [[ -f ~/.zsh/.shared_config ]] && [[ "$SUDO_USER" != "fabian" ]] ; then
|
if [[ -f ~/.zsh/.shared_config && "$SUDO_USER" != "fabian" ]]; then
|
||||||
shared_config=1
|
shared_config=1
|
||||||
else
|
else
|
||||||
shared_config=0
|
shared_config=0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Workaround for HOME directory in sudo nvim (caused by snap)
|
# Work around snap's HOME handling for root.
|
||||||
if [[ "$USER" == "root" ]]; then
|
if [[ "$USER" == "root" ]]; then
|
||||||
if [[ ! -e /home/root ]]; then
|
if [[ ! -e /home/root ]]; then
|
||||||
ln -s /root/ /home/root
|
ln -s /root/ /home/root
|
||||||
@@ -20,214 +18,52 @@ if [[ "$USER" == "root" ]]; then
|
|||||||
ln -s /root/.config /home/root/.config
|
ln -s /root/.config /home/root/.config
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
[[ -f ~/.zsh/.shared_config ]] && touch ~/.config/nvim/.shared_config
|
||||||
|
|
||||||
if [[ -f ~/.zsh/.shared_config ]] ; then
|
source "${ZDOTDIR:-$HOME}/.zsh/lib/updates.zsh"
|
||||||
touch ~/.config/nvim/.shared_config
|
|
||||||
fi
|
|
||||||
|
|
||||||
# On shell start, bring ~/dotfiles up to date by fast-forwarding the CURRENT
|
if (( ! shared_config )); then
|
||||||
# branch to its upstream only. Never rebase or stash in the background: if the
|
|
||||||
# branch diverged or local edits block it, warn and leave it for a manual pull.
|
|
||||||
# Per-branch, so `server` on each device fast-forwards to origin/server.
|
|
||||||
update_dotfiles() {
|
|
||||||
local repo="$HOME/dotfiles"
|
|
||||||
local cache_dir="${ZDOTDIR:-$HOME}/.cache/zsh"
|
|
||||||
local notice_file="$cache_dir/dotfiles-update-notice"
|
|
||||||
local notice_tmp="$notice_file.$$.tmp"
|
|
||||||
# Bound the network call so a stalled fetch can't wedge this backgrounded
|
|
||||||
# (&!) job into a days-long orphan holding unreaped children. `timeout` is
|
|
||||||
# absent on macOS, so only use it when present. Disable ssh multiplexing so
|
|
||||||
# no daemonized mux master can inherit and keep our fds open past git's exit.
|
|
||||||
local -a TO; (( $+commands[timeout] )) && TO=(timeout -k 5 15)
|
|
||||||
GIT_SSH_COMMAND='ssh -o BatchMode=yes -o ConnectTimeout=5 -o ControlMaster=no -o ControlPath=none' \
|
|
||||||
$TO git -C "$repo" fetch --quiet </dev/null 2>/dev/null || return
|
|
||||||
git -C "$repo" rev-parse --abbrev-ref '@{u}' >/dev/null 2>&1 || return # no upstream
|
|
||||||
git -C "$repo" merge-base --is-ancestor '@{u}' HEAD 2>/dev/null && return # already current
|
|
||||||
git -C "$repo" merge --ff-only --quiet '@{u}' 2>/dev/null && return
|
|
||||||
local notice="⚠ dotfiles: $(git -C "$repo" symbolic-ref --short HEAD) can't fast-forward to @{u} — run: git -C ~/dotfiles pull"
|
|
||||||
mkdir -p "$cache_dir" || return
|
|
||||||
print -r -- "$notice" >| "$notice_tmp" || return
|
|
||||||
mv -f "$notice_tmp" "$notice_file"
|
|
||||||
}
|
|
||||||
|
|
||||||
update_dotfiles &!
|
|
||||||
|
|
||||||
if [ "$shared_config" -eq 0 ]; then
|
|
||||||
export GIT_AUTHOR_NAME="Fabian Ising"
|
export GIT_AUTHOR_NAME="Fabian Ising"
|
||||||
export GIT_AUTHOR_EMAIL="f.ising@fh-muenster.de"
|
export GIT_AUTHOR_EMAIL="f.ising@fh-muenster.de"
|
||||||
export GIT_COMMITTER_NAME=$GIT_AUTHOR_NAME
|
export GIT_COMMITTER_NAME=$GIT_AUTHOR_NAME
|
||||||
export GIT_COMMITTER_EMAIL=$GIT_AUTHOR_EMAIL
|
export GIT_COMMITTER_EMAIL=$GIT_AUTHOR_EMAIL
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# On shell start, check the security tools repo for upstream updates and queue a
|
static_file=${ZDOTDIR:-$HOME}/.cache/zsh/.zsh_plugins.zsh
|
||||||
# one-line notice if the checkout is behind. A precmd hook prints it between
|
if (( ! shared_config )); then
|
||||||
# commands, rather than letting this background job write across other startup
|
plugins_txt=${ZDOTDIR:-$HOME}/.zsh/.zsh_plugins.txt
|
||||||
# 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 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)
|
|
||||||
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=$(GIT_SSH_COMMAND='ssh -o BatchMode=yes -o ConnectTimeout=5 -o ControlMaster=no -o ControlPath=none' \
|
|
||||||
$TO $g ls-remote "$remote" "$mergeref" </dev/null 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"
|
|
||||||
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_update_notices() {
|
|
||||||
local cache_dir="${ZDOTDIR:-$HOME}/.cache/zsh"
|
|
||||||
local notice_file claimed_notice
|
|
||||||
for notice_file in "$cache_dir"/{dotfiles,tools}-update-notice; do
|
|
||||||
[[ -s "$notice_file" ]] || continue
|
|
||||||
claimed_notice="$notice_file.$$.show"
|
|
||||||
mv "$notice_file" "$claimed_notice" 2>/dev/null || continue
|
|
||||||
command cat "$claimed_notice"
|
|
||||||
command rm -f "$claimed_notice"
|
|
||||||
done
|
|
||||||
}
|
|
||||||
autoload -Uz add-zsh-hook
|
|
||||||
add-zsh-hook precmd show_update_notices
|
|
||||||
|
|
||||||
# Load Antidote
|
|
||||||
mkdir -p ${ZDOTDIR:-~}/.cache/zsh
|
|
||||||
static_file=${ZDOTDIR:-~}/.cache/zsh/.zsh_plugins.zsh
|
|
||||||
if [ $shared_config -eq 0 ]; then
|
|
||||||
plugins_txt=${ZDOTDIR:-~}/.zsh/.zsh_plugins.txt
|
|
||||||
# Vi mode
|
|
||||||
bindkey -v
|
bindkey -v
|
||||||
VI_MODE_SET_CURSOR=true
|
VI_MODE_SET_CURSOR=true
|
||||||
else
|
else
|
||||||
plugins_txt=${ZDOTDIR:-~}/.zsh/.zsh_plugins_shared.txt
|
plugins_txt=${ZDOTDIR:-$HOME}/.zsh/.zsh_plugins_shared.txt
|
||||||
static_file=${ZDOTDIR:-~}/.cache/zsh/.zsh_shared_plugins.zsh
|
static_file=${ZDOTDIR:-$HOME}/.cache/zsh/.zsh_shared_plugins.zsh
|
||||||
fi
|
|
||||||
# clone antidote if necessary
|
|
||||||
if ! [[ -e ${ZDOTDIR:-~}/.antidote ]]; then
|
|
||||||
git clone https://github.com/mattmc3/antidote.git ${ZDOTDIR:-~}/.antidote
|
|
||||||
fi
|
fi
|
||||||
|
source "${ZDOTDIR:-$HOME}/.zsh/lib/antidote.zsh"
|
||||||
|
|
||||||
#zstyle ':omz:plugins:docker' legacy-completion yes
|
|
||||||
zstyle ':completion:*:ssh:*' hosts off
|
|
||||||
zstyle ':completion:*:scp:*' hosts off
|
|
||||||
|
|
||||||
# Run rehash for external commands
|
|
||||||
zstyle ":completion:*:commands" rehash 1
|
|
||||||
# source antidote and load plugins from `${ZDOTDIR:-~}/.zsh_plugins.txt`
|
|
||||||
source ${ZDOTDIR:-~}/.antidote/antidote.zsh
|
|
||||||
antidote load ${plugins_txt} ${static_file}
|
|
||||||
export SSH_REAL_SOCK=$SSH_AUTH_SOCK
|
export SSH_REAL_SOCK=$SSH_AUTH_SOCK
|
||||||
[[ -z $FORWARD_SOCK ]] || export SSH_AUTH_SOCK=$FORWARD_SOCK
|
[[ -z $FORWARD_SOCK ]] || export SSH_AUTH_SOCK=$FORWARD_SOCK
|
||||||
|
|
||||||
setopt interactivecomments
|
source "${ZDOTDIR:-$HOME}/.zsh/lib/interactive.zsh"
|
||||||
|
|
||||||
# History options
|
|
||||||
HISTSIZE=100000 # Set the amount of lines you want saved
|
|
||||||
SAVEHIST=100000 # This is required to actually save them, needs to match with HISTSIZE
|
|
||||||
setopt EXTENDED_HISTORY # Write the history file in the ":start:elapsed;command" format.
|
|
||||||
setopt INC_APPEND_HISTORY # Write to the history file immediately, not when the shell exits.
|
|
||||||
setopt SHARE_HISTORY # Share history between all sessions.
|
|
||||||
setopt HIST_EXPIRE_DUPS_FIRST # Expire duplicate entries first when trimming history.
|
|
||||||
setopt HIST_IGNORE_DUPS # Don\'t record an entry that was just recorded again.
|
|
||||||
setopt HIST_IGNORE_ALL_DUPS # Delete old recorded entry if new entry is a duplicate.
|
|
||||||
setopt HIST_FIND_NO_DUPS # Do not display a line previously found.
|
|
||||||
setopt HIST_IGNORE_SPACE # Don\'t record an entry starting with a space.
|
|
||||||
setopt HIST_SAVE_NO_DUPS # Don\'t write duplicate entries in the history file.
|
|
||||||
setopt HIST_REDUCE_BLANKS # Remove superfluous blanks before recording entry.
|
|
||||||
# Clear screen by ctrl+q
|
|
||||||
bindkey '^q' clear-screen
|
|
||||||
|
|
||||||
(( $+commands[nvim] )) && alias vim=nvim
|
|
||||||
alias sudo='sudo '
|
|
||||||
alias cgrep="grep --color=always"
|
|
||||||
alias cdiff="git diff --color-words --no-index"
|
|
||||||
(( $+commands[nvim] )) && export EDITOR='nvim'
|
|
||||||
(( $+commands[nvim] )) && export VISUAL='nvim'
|
|
||||||
|
|
||||||
# Allow access to all libvirt vms
|
|
||||||
export LIBVIRT_DEFAULT_URI="qemu:///system"
|
export LIBVIRT_DEFAULT_URI="qemu:///system"
|
||||||
|
if (( ! shared_config )); then
|
||||||
alias ls="ls --color=always"
|
|
||||||
|
|
||||||
if [ "$shared_config" -eq 0 ]; then
|
|
||||||
# Use safecp/safemv from the tools-repo when available
|
|
||||||
(( $+commands[safecp] )) && alias cp=safecp
|
(( $+commands[safecp] )) && alias cp=safecp
|
||||||
(( $+commands[safemv] )) && alias mv=safemv
|
(( $+commands[safemv] )) && alias mv=safemv
|
||||||
(( $+commands[safescp] )) && alias scp=safescp
|
(( $+commands[safescp] )) && alias scp=safescp
|
||||||
fi
|
fi
|
||||||
|
|
||||||
delzip() {
|
|
||||||
unzip -Z -1 "$@" | xargs -I{} rm -rf {}
|
|
||||||
}
|
|
||||||
# mitmproxy
|
|
||||||
export MITMPROXY_SSLKEYLOGFILE="~/.mitmproxy/sslkeylogfile.txt"
|
|
||||||
|
|
||||||
[[ -f ~/.zsh/.mac_config ]] && source ~/.zsh/.mac_config
|
[[ -f ~/.zsh/.mac_config ]] && source ~/.zsh/.mac_config
|
||||||
|
|
||||||
# Workaround for async issues https://github.com/romkatv/powerlevel10k/issues/1554
|
if zmodload zsh/terminfo && (( terminfo[colors] >= 256 )) && (( ! shared_config )); then
|
||||||
unset ZSH_AUTOSUGGEST_USE_ASYNC
|
p10k_config=~/dotfiles/zsh/.p10k.zsh
|
||||||
|
|
||||||
# Powerlevel 10k
|
|
||||||
# Remove padding on right side
|
|
||||||
ZLE_RPROMPT_INDENT=0
|
|
||||||
|
|
||||||
# To customize prompt, run `p10k configure` or edit ~/dotfiles/zsh/.p10k.zsh.
|
|
||||||
function load_p10k() {
|
|
||||||
if zmodload zsh/terminfo && (( terminfo[colors] >= 256 )) && [ $shared_config -eq 0 ]; then
|
|
||||||
[[ ! -f ~/dotfiles/zsh/.p10k.zsh ]] || source ~/dotfiles/zsh/.p10k.zsh
|
|
||||||
else
|
else
|
||||||
[[ ! -f ~/dotfiles/zsh/.p10k_shared.zsh ]] || source ~/dotfiles/zsh/.p10k_shared.zsh
|
p10k_config=~/dotfiles/zsh/.p10k_shared.zsh
|
||||||
fi
|
fi
|
||||||
}
|
source "${ZDOTDIR:-$HOME}/.zsh/lib/prompt.zsh"
|
||||||
load_p10k
|
|
||||||
#
|
|
||||||
# This speeds up pasting w/ autosuggest
|
|
||||||
# https://github.com/zsh-users/zsh-autosuggestions/issues/238
|
|
||||||
pasteinit() {
|
|
||||||
OLD_SELF_INSERT=${${(s.:.)widgets[self-insert]}[2,3]}
|
|
||||||
zle -N self-insert url-quote-magic # I wonder if you'd need `.url-quote-magic`?
|
|
||||||
}
|
|
||||||
|
|
||||||
pastefinish() {
|
|
||||||
zle -N self-insert $OLD_SELF_INSERT
|
|
||||||
}
|
|
||||||
zstyle :bracketed-paste-magic paste-init pasteinit
|
|
||||||
zstyle :bracketed-paste-magic paste-finish pastefinish
|
|
||||||
# https://github.com/zsh-users/zsh-autosuggestions/issues/351
|
|
||||||
ZSH_AUTOSUGGEST_CLEAR_WIDGETS+=(bracketed-paste)
|
|
||||||
|
|
||||||
export LANG="en_US.UTF-8"
|
|
||||||
export LC_CTYPE="en_US.UTF-8"
|
|
||||||
export TIME_STYLE="long-iso"
|
|
||||||
|
|
||||||
[[ -f ~/.zsh/.user_config ]] && source ~/.zsh/.user_config
|
[[ -f ~/.zsh/.user_config ]] && source ~/.zsh/.user_config
|
||||||
[[ -f ~/.zsh/.virtual_env_config.zsh ]] && source ~/.zsh/.virtual_env_config.zsh
|
[[ -f ~/.zsh/.virtual_env_config.zsh ]] && source ~/.zsh/.virtual_env_config.zsh
|
||||||
[[ -f ~/.zsh/.local_config ]] && source ~/.zsh/.local_config
|
[[ -f ~/.zsh/.local_config ]] && source ~/.zsh/.local_config
|
||||||
[[ -f ~/.zsh/.os_config.zsh ]] && source ~/.zsh/.os_config.zsh
|
[[ -f ~/.zsh/.os_config.zsh ]] && source ~/.zsh/.os_config.zsh
|
||||||
|
|
||||||
# Remove duplicate entries added by inherited and machine-specific PATH config
|
|
||||||
# while preserving the first occurrence and therefore command precedence.
|
|
||||||
typeset -U path PATH
|
typeset -U path PATH
|
||||||
|
|||||||
@@ -0,0 +1,12 @@
|
|||||||
|
# Callers set plugins_txt and static_file before sourcing this module.
|
||||||
|
mkdir -p "${static_file:h}"
|
||||||
|
if [[ ! -e ${ZDOTDIR:-$HOME}/.antidote ]]; then
|
||||||
|
git clone https://github.com/mattmc3/antidote.git "${ZDOTDIR:-$HOME}/.antidote"
|
||||||
|
fi
|
||||||
|
|
||||||
|
zstyle ':completion:*:ssh:*' hosts off
|
||||||
|
zstyle ':completion:*:scp:*' hosts off
|
||||||
|
zstyle ':completion:*:commands' rehash 1
|
||||||
|
|
||||||
|
source "${ZDOTDIR:-$HOME}/.antidote/antidote.zsh"
|
||||||
|
antidote load "$plugins_txt" "$static_file"
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
setopt interactivecomments
|
||||||
|
|
||||||
|
HISTSIZE=100000
|
||||||
|
SAVEHIST=100000
|
||||||
|
setopt EXTENDED_HISTORY
|
||||||
|
setopt INC_APPEND_HISTORY
|
||||||
|
setopt SHARE_HISTORY
|
||||||
|
setopt HIST_EXPIRE_DUPS_FIRST
|
||||||
|
setopt HIST_IGNORE_DUPS
|
||||||
|
setopt HIST_IGNORE_ALL_DUPS
|
||||||
|
setopt HIST_FIND_NO_DUPS
|
||||||
|
setopt HIST_IGNORE_SPACE
|
||||||
|
setopt HIST_SAVE_NO_DUPS
|
||||||
|
setopt HIST_REDUCE_BLANKS
|
||||||
|
|
||||||
|
bindkey '^q' clear-screen
|
||||||
|
(( $+commands[nvim] )) && alias vim=nvim
|
||||||
|
(( $+commands[nvim] )) && export EDITOR=nvim VISUAL=nvim
|
||||||
|
alias sudo='sudo '
|
||||||
|
alias ls='ls --color=always'
|
||||||
|
alias cgrep='grep --color=always'
|
||||||
|
alias cdiff='git diff --color-words --no-index'
|
||||||
|
|
||||||
|
delzip() {
|
||||||
|
unzip -Z -1 "$@" | xargs -I{} rm -rf {}
|
||||||
|
}
|
||||||
|
export MITMPROXY_SSLKEYLOGFILE='~/.mitmproxy/sslkeylogfile.txt'
|
||||||
|
|
||||||
|
unset ZSH_AUTOSUGGEST_USE_ASYNC
|
||||||
|
export LANG='en_US.UTF-8'
|
||||||
|
export LC_CTYPE='en_US.UTF-8'
|
||||||
|
export TIME_STYLE='long-iso'
|
||||||
|
|
||||||
|
pasteinit() {
|
||||||
|
OLD_SELF_INSERT=${${(s.:.)widgets[self-insert]}[2,3]}
|
||||||
|
zle -N self-insert url-quote-magic
|
||||||
|
}
|
||||||
|
pastefinish() {
|
||||||
|
zle -N self-insert "$OLD_SELF_INSERT"
|
||||||
|
}
|
||||||
|
zstyle :bracketed-paste-magic paste-init pasteinit
|
||||||
|
zstyle :bracketed-paste-magic paste-finish pastefinish
|
||||||
|
ZSH_AUTOSUGGEST_CLEAR_WIDGETS+=(bracketed-paste)
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
# Callers select p10k_config before sourcing this module.
|
||||||
|
ZLE_RPROMPT_INDENT=0
|
||||||
|
[[ -z "$p10k_config" || ! -f "$p10k_config" ]] || source "$p10k_config"
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
# Background repository maintenance shared by desktop and server shells.
|
||||||
|
|
||||||
|
update_dotfiles() {
|
||||||
|
local repo="$HOME/dotfiles"
|
||||||
|
local cache_dir="${ZDOTDIR:-$HOME}/.cache/zsh"
|
||||||
|
local notice_file="$cache_dir/dotfiles-update-notice"
|
||||||
|
local notice_tmp="$notice_file.$$.tmp"
|
||||||
|
local -a TO; (( $+commands[timeout] )) && TO=(timeout -k 5 15)
|
||||||
|
GIT_SSH_COMMAND='ssh -o BatchMode=yes -o ConnectTimeout=5 -o ControlMaster=no -o ControlPath=none' \
|
||||||
|
$TO git -C "$repo" fetch --quiet </dev/null 2>/dev/null || return
|
||||||
|
git -C "$repo" rev-parse --abbrev-ref '@{u}' >/dev/null 2>&1 || return
|
||||||
|
git -C "$repo" merge-base --is-ancestor '@{u}' HEAD 2>/dev/null && return
|
||||||
|
git -C "$repo" merge --ff-only --quiet '@{u}' 2>/dev/null && return
|
||||||
|
local notice="⚠ dotfiles: $(git -C "$repo" symbolic-ref --short HEAD) can't fast-forward to @{u} — run: git -C ~/dotfiles pull"
|
||||||
|
mkdir -p "$cache_dir" || return
|
||||||
|
print -r -- "$notice" >| "$notice_tmp" || return
|
||||||
|
mv -f "$notice_tmp" "$notice_file"
|
||||||
|
}
|
||||||
|
update_dotfiles &!
|
||||||
|
|
||||||
|
check_tools_repo() {
|
||||||
|
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"
|
||||||
|
local -a TO; (( $+commands[timeout] )) && TO=(timeout -k 5 10)
|
||||||
|
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
|
||||||
|
mergeref=$($g config "branch.$branch.merge" 2>/dev/null) || return
|
||||||
|
remote_sha=$(GIT_SSH_COMMAND='ssh -o BatchMode=yes -o ConnectTimeout=5 -o ControlMaster=no -o ControlPath=none' \
|
||||||
|
$TO $g ls-remote "$remote" "$mergeref" </dev/null 2>/dev/null | awk '{print $1}')
|
||||||
|
local_sha=$($g rev-parse HEAD 2>/dev/null)
|
||||||
|
[[ -n "$remote_sha" && -n "$local_sha" ]] || return
|
||||||
|
[[ "$remote_sha" == "$local_sha" ]] && return
|
||||||
|
$g merge-base --is-ancestor "$remote_sha" HEAD 2>/dev/null && return
|
||||||
|
[[ -w "$repo/.git" ]] && cmd="git -C $repo pull" || cmd="sudo git -C $repo pull"
|
||||||
|
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_update_notices() {
|
||||||
|
local cache_dir="${ZDOTDIR:-$HOME}/.cache/zsh"
|
||||||
|
local notice_file claimed_notice
|
||||||
|
for notice_file in "$cache_dir"/{dotfiles,tools}-update-notice; do
|
||||||
|
[[ -s "$notice_file" ]] || continue
|
||||||
|
claimed_notice="$notice_file.$$.show"
|
||||||
|
mv "$notice_file" "$claimed_notice" 2>/dev/null || continue
|
||||||
|
command cat "$claimed_notice"
|
||||||
|
command rm -f "$claimed_notice"
|
||||||
|
done
|
||||||
|
}
|
||||||
|
autoload -Uz add-zsh-hook
|
||||||
|
add-zsh-hook precmd show_update_notices
|
||||||
Reference in New Issue
Block a user