From 44c0f614f238001d4231781c7ec7eca79b24a1bd Mon Sep 17 00:00:00 2001 From: Dmitry Date: Wed, 13 May 2026 20:35:43 +0300 Subject: [PATCH] feat: add clean-system script with fzf multi-select (cs alias) --- dot_config/zsh/config/aliases.zsh | 1 + dot_local/bin/executable_clean-system | 143 ++++++++++++++++++++++++++ 2 files changed, 144 insertions(+) create mode 100644 dot_local/bin/executable_clean-system diff --git a/dot_config/zsh/config/aliases.zsh b/dot_config/zsh/config/aliases.zsh index e45e398..a0af150 100644 --- a/dot_config/zsh/config/aliases.zsh +++ b/dot_config/zsh/config/aliases.zsh @@ -145,6 +145,7 @@ alias wakemac='ssh vps "wakeonlan -i 192.168.1.255 FC:34:97:E1:08:E9"' # ═══ Пользовательские скрипты ══════════════════════════════ alias bm='backup-menu --all' alias sp='ssh-pick' +alias cs='clean-system' # Быстрое обновление системы (для разных дистрибутивов) if command -v apt &>/dev/null; then diff --git a/dot_local/bin/executable_clean-system b/dot_local/bin/executable_clean-system new file mode 100644 index 0000000..b0aaca5 --- /dev/null +++ b/dot_local/bin/executable_clean-system @@ -0,0 +1,143 @@ +#!/usr/bin/env bash +# clean-system — безопасная интерактивная очистка системы + +set -euo pipefail + +_size() { + du -sh "$1" 2>/dev/null | cut -f1 || echo "0" +} + +_freed() { + local before=$1 after=$2 + # оба в байтах через numfmt + local b a + b=$(numfmt --from=iec "$before" 2>/dev/null || echo 0) + a=$(numfmt --from=iec "$after" 2>/dev/null || echo 0) + local diff=$(( b - a )) + (( diff > 0 )) && numfmt --to=iec "$diff" || echo "0" +} + +# ── Задачи очистки ─────────────────────────────────────────── +# Формат: "id|описание|команда|путь_для_размера" + +declare -A TASK_CMD TASK_PATH TASK_DESC + +_register() { + local id=$1 desc=$2 path=$3; shift 3 + TASK_DESC[$id]="$desc" + TASK_PATH[$id]="$path" + TASK_CMD[$id]="$*" +} + +_register pacman-cache \ + "Pacman кеш (оставить 2 версии)" \ + "/var/cache/pacman/pkg" \ + sudo paccache -rk2 + +_register paru-cache \ + "Paru build кеш" \ + "$HOME/.cache/paru" \ + paru -Sc --noconfirm + +_register uv-cache \ + "uv (Python) кеш" \ + "$HOME/.cache/uv" \ + uv cache clean + +_register npm-cache \ + "npm кеш" \ + "$HOME/.npm" \ + npm cache clean --force + +_register cargo-cache \ + "Cargo registry (скачанные крейты)" \ + "$HOME/.cargo/registry" \ + rm -rf "$HOME/.cargo/registry/cache" "$HOME/.cargo/registry/src" + +_register restic-cache \ + "Restic старые кеши" \ + "$HOME/.cache/restic" \ + restic cache --cleanup + +_register thumbnails \ + "Кеш миниатюр" \ + "$HOME/.cache/thumbnails" \ + rm -rf "$HOME/.cache/thumbnails" + +_register journal \ + "Systemd journal (оставить 2 недели)" \ + "" \ + journalctl --vacuum-time=2weeks + +_register pip-cache \ + "pip кеш" \ + "$HOME/.cache/pip" \ + pip3 cache purge + +_register zsh-compdump \ + "Zsh completion cache (пересоздастся автоматически)" \ + "" \ + bash -c 'rm -f "$HOME"/.config/zsh/.zcompdump*' + +# ── Построение меню ────────────────────────────────────────── + +main() { + if ! command -v fzf &>/dev/null; then + echo "fzf not found" + exit 1 + fi + + local ORDERED=(pacman-cache paru-cache uv-cache npm-cache cargo-cache + restic-cache thumbnails journal pip-cache zsh-compdump) + + local lines=() + for id in "${ORDERED[@]}"; do + local size="" + local path="${TASK_PATH[$id]}" + if [[ -n "$path" && ( -d "$path" || -f "$path" ) ]]; then + size=$(_size "$path") + else + size="—" + fi + lines+=("$(printf "%-14s %6s %s" "$id" "$size" "${TASK_DESC[$id]}")") + done + + local selected + selected=$(printf '%s\n' "${lines[@]}" | fzf \ + --multi \ + --prompt "clean > " \ + --header "Пробел — выбрать | Enter — запустить | Ctrl-A — выбрать всё" \ + --bind "ctrl-a:select-all" \ + --reverse \ + --height=50%) || exit 0 + + [[ -z "$selected" ]] && exit 0 + + local total_freed=0 + + while IFS= read -r line; do + local id + id=$(echo "$line" | awk '{print $1}') + local path="${TASK_PATH[$id]}" + + local before="" + [[ -n "$path" && ( -d "$path" || -f "$path" ) ]] && before=$(_size "$path") + + echo "" + echo "▶ ${TASK_DESC[$id]}" + eval "${TASK_CMD[$id]}" || true + + if [[ -n "$path" && -n "$before" ]]; then + local after + after=$(_size "$path") + local freed + freed=$(_freed "$before" "$after") + echo " → освобождено: $freed" + fi + done <<< "$selected" + + echo "" + echo "Готово." +} + +main "$@"