feat: add user scripts (backup-menu, ssh-pick, proj) and backup reminder
This commit is contained in:
@@ -133,14 +133,6 @@ alias ns='npm start'
|
|||||||
alias nt='npm test'
|
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 zshrc='${EDITOR} ~/.config/zsh/.zshrc'
|
||||||
alias reload='source ~/.config/zsh/.zshrc'
|
alias reload='source ~/.config/zsh/.zshrc'
|
||||||
alias path='echo $PATH | tr ":" "\n"'
|
alias path='echo $PATH | tr ":" "\n"'
|
||||||
@@ -150,6 +142,10 @@ alias x='exit'
|
|||||||
alias rsend='sudo rsync -avhP --stats'
|
alias rsend='sudo rsync -avhP --stats'
|
||||||
alias wakemac='ssh vps "wakeonlan -i 192.168.1.255 FC:34:97:E1:08:E9"'
|
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, если установлен
|
# Использовать bat вместо cat, если установлен
|
||||||
if command -v bat &>/dev/null; then
|
if command -v bat &>/dev/null; then
|
||||||
alias cat='bat'
|
alias cat='bat'
|
||||||
|
|||||||
@@ -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() {
|
activate() {
|
||||||
local venv_dir=""
|
local venv_dir=""
|
||||||
if [[ -d ".venv" ]]; then
|
if [[ -d ".venv" ]]; then
|
||||||
|
|||||||
@@ -34,3 +34,6 @@ source "${ZSH_CONFIG_DIR}/prompt.zsh"
|
|||||||
|
|
||||||
# ═══ Fastfetch ══════════════════════════════════════════════
|
# ═══ Fastfetch ══════════════════════════════════════════════
|
||||||
[[ -z "$TMUX" && "$TERM_PROGRAM" == "kitty" ]] && fastfetch
|
[[ -z "$TMUX" && "$TERM_PROGRAM" == "kitty" ]] && fastfetch
|
||||||
|
|
||||||
|
# ═══ Напоминания ════════════════════════════════════════════
|
||||||
|
(( ${+functions[_backup_reminder]} )) && _backup_reminder
|
||||||
|
|||||||
Executable
+77
@@ -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 "$@"
|
||||||
Executable
+52
@@ -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 "$@"
|
||||||
Reference in New Issue
Block a user