feat: add user scripts (backup-menu, ssh-pick, proj) and backup reminder

This commit is contained in:
Dmitry
2026-05-13 19:39:32 +03:00
parent 28914ea128
commit babe53d929
5 changed files with 183 additions and 8 deletions
+4 -8
View File
@@ -133,14 +133,6 @@ alias ns='npm start'
alias nt='npm test'
# ═══ Утилиты ═══════════════════════════════════════════════
alias reload='source ~/.config/zsh/.zshrc'
alias path='echo $PATH | tr ":" "\n"'
alias h='history'
alias c='clear'
alias x='exit'
alias rsend='sudo rsync -avhP --stats'
alias wakemac='ssh vps "wakeonlan -i 192.168.1.255 FC:34:97:E1:08:E9"'
alias zshrc='${EDITOR} ~/.config/zsh/.zshrc'
alias reload='source ~/.config/zsh/.zshrc'
alias path='echo $PATH | tr ":" "\n"'
@@ -150,6 +142,10 @@ alias x='exit'
alias rsend='sudo rsync -avhP --stats'
alias wakemac='ssh vps "wakeonlan -i 192.168.1.255 FC:34:97:E1:08:E9"'
# ═══ Пользовательские скрипты ══════════════════════════════
alias bm='backup-menu'
alias sp='ssh-pick'
# Использовать bat вместо cat, если установлен
if command -v bat &>/dev/null; then
alias cat='bat'
+47
View File
@@ -266,6 +266,53 @@ sshp-restart() {
}
# _backup_reminder - проверить давность последнего бэкапа (вызывается из .zshrc)
_backup_reminder() {
local state_file="${XDG_STATE_HOME:-$HOME/.local/state}/backup-last-run"
local threshold=$(( 2 * 24 * 3600 )) # 2 дня в секундах
local now
now=$(date +%s)
if [[ ! -f "$state_file" ]]; then
print -P "%F{yellow}⚠ Бэкап не запускался. Запусти: backup-menu%f"
return
fi
local last
last=$(cat "$state_file")
local diff=$(( now - last ))
if (( diff > threshold )); then
local days=$(( diff / 86400 ))
print -P "%F{yellow}⚠ Последний бэкап: ${days} дн. назад. Запусти: backup-menu%f"
fi
}
# proj - перейти в проект через fzf
proj() {
local base="${PROJECTS_DIR:-$HOME/Documents/Projects}"
if [[ ! -d "$base" ]]; then
echo "Projects dir not found: $base"
return 1
fi
local target
if command -v fzf &>/dev/null; then
target=$(find "$base" -maxdepth 2 -mindepth 1 -type d \
\( -name .git -o -name node_modules -o -name .venv \) -prune \
-o -type d -print \
| sed "s|$base/||" \
| fzf --prompt "proj > " --height=40% --reverse) || return 0
elif [[ -n "$1" ]]; then
target="$1"
else
ls "$base"
return 0
fi
cd "$base/$target"
}
activate() {
local venv_dir=""
if [[ -d ".venv" ]]; then
+3
View File
@@ -34,3 +34,6 @@ source "${ZSH_CONFIG_DIR}/prompt.zsh"
# ═══ Fastfetch ══════════════════════════════════════════════
[[ -z "$TMUX" && "$TERM_PROGRAM" == "kitty" ]] && fastfetch
# ═══ Напоминания ════════════════════════════════════════════
(( ${+functions[_backup_reminder]} )) && _backup_reminder
+77
View File
@@ -0,0 +1,77 @@
#!/usr/bin/env bash
# backup-menu — interactive resticprofile menu
set -euo pipefail
PROFILES=(dotfiles projects vaults files pictures)
STATE_FILE="${XDG_STATE_HOME:-$HOME/.local/state}/backup-last-run"
_profile_label() {
local profile=$1
local last
last=$(resticprofile -n "$profile" snapshots --json 2>/dev/null \
| python3 -c "
import sys, json
try:
snaps = json.load(sys.stdin)
if snaps:
t = snaps[-1]['time'][:16].replace('T', ' ')
print(f'last: {t}')
else:
print('no snapshots')
except:
print('?')
" 2>/dev/null || echo "?")
printf "%-16s %s" "$profile" "$last"
}
_run_backup() {
local profile=$1
echo "▶ resticprofile -n $profile backup"
resticprofile -n "$profile" backup
mkdir -p "$(dirname "$STATE_FILE")"
date +%s > "$STATE_FILE"
}
_run_forget() {
local profile=$1
echo "▶ resticprofile -n $profile forget"
resticprofile -n "$profile" forget
}
_show_snapshots() {
local profile=$1
resticprofile -n "$profile" snapshots 2>&1 | less
}
main() {
if ! command -v fzf &>/dev/null; then
echo "fzf not found"
exit 1
fi
# Build profile list with last run info
local lines=()
for p in "${PROFILES[@]}"; do
lines+=("$(_profile_label "$p")")
done
local selected
selected=$(printf '%s\n' "${lines[@]}" | fzf \
--prompt "backup > " \
--header "Enter — запустить бэкап | Ctrl-F — forget | Ctrl-S — снапшоты" \
--bind "ctrl-f:become(echo '__forget__'$(echo {} | awk '{print $1}'))" \
--bind "ctrl-s:become(echo '__snaps__'$(echo {} | awk '{print $1}'))" \
--no-sort) || exit 0
local profile
profile=$(echo "$selected" | awk '{print $1}')
case "$selected" in
__forget__*) _run_forget "${selected#__forget__}" ;;
__snaps__*) _show_snapshots "${selected#__snaps__}" ;;
*) _run_backup "$profile" ;;
esac
}
main "$@"
+52
View File
@@ -0,0 +1,52 @@
#!/usr/bin/env bash
# ssh-pick — выбрать SSH-хост через fzf
set -euo pipefail
SSH_CONFIG_DIR="${HOME}/.ssh/config.d"
SSH_CONFIG="${HOME}/.ssh/config"
_list_hosts() {
local configs=()
if [[ -d "$SSH_CONFIG_DIR" ]]; then
configs=("$SSH_CONFIG_DIR"/*.conf)
fi
[[ -f "$SSH_CONFIG" ]] && configs+=("$SSH_CONFIG")
for f in "${configs[@]}"; do
[[ -f "$f" ]] || continue
awk '/^Host [^*]/{
sub(/^Host /, "")
n = split($0, hosts, " ")
for (i = 1; i <= n; i++) print hosts[i]
}' "$f"
done | sort -u
}
main() {
if ! command -v fzf &>/dev/null; then
echo "fzf not found"
exit 1
fi
local hosts
hosts=$(_list_hosts)
if [[ -z "$hosts" ]]; then
echo "No SSH hosts found"
exit 1
fi
local selected
selected=$(echo "$hosts" | fzf \
--prompt "ssh > " \
--header "Enter — подключиться | Ctrl-C — выйти" \
--height=40% \
--reverse) || exit 0
echo "▶ ssh $selected"
exec ssh "$selected"
}
main "$@"