#!/bin/bash # Установка райса на чистую Fedora (в том числе без Hyprland). # # ./install.sh визуал (Hyprland, DMS, шрифт, терминал) + SSH-меню и всё, что ему нужно + конфиги # ./install.sh --full + остальные инструменты (OCR и др.) и приложения (Chrome, Telegram, … через Flatpak) # ./install.sh --dry-run только показать, что будет сделано (ничего не меняет) # ./install.sh --yes не задавать вопросов # ./install.sh --no-packages / --no-config пропустить этап # # Скрипт можно запускать повторно: существующие конфиги не затираются, а переносятся в *.bak-<время>. set -euo pipefail REPO=$(cd "$(dirname "$0")" && pwd) CFG=${XDG_CONFIG_HOME:-$HOME/.config} TS=$(date +%Y%m%d-%H%M%S) DRY=0; ASSUME_YES=0; FULL=0; DO_PKG=1; DO_CONFIG=1 COPRS=(sachesi/hyprland avengemedia/dms) # --- визуальная часть (по умолчанию) --- # Hyprland нет в репозиториях Fedora, он и его утилиты идут из COPR sachesi/hyprland PKGS_HYPR=(hyprland hypridle hyprpolkitagent hyprland-guiutils xdg-desktop-portal-hyprland xdg-desktop-portal-gtk) # DMS (панель, лаунчер, уведомления, блокировка, обои, тема) из COPR avengemedia/dms PKGS_SHELL=(dms) # шрифт панели и терминал, wl-clipboard и brightnessctl нужны панели и затемнению экрана PKGS_VISUAL=(jetbrains-mono-fonts kitty wl-clipboard brightnessctl) # SSH-меню (Mod+S): fzf — интерфейс, tmux — broadcast и Alt+T, openssh-clients — ssh-copy-id, python3 — разбор # ~/.ssh/config, libnotify — уведомления, micro — правка конфига (Alt+E), nautilus — SFTP (Alt+F); # jq — Alt+Tab и «показать или запустить» (Mod+B/T/K); iputils, less, xdg-utils — пинг, вывод и браузер PKGS_MENU=(fzf tmux jq python3 openssh-clients libnotify micro nautilus iputils less xdg-utils) # --- только с --full --- PKGS_TOOLS=(hyprpicker hyprlock cliphist playerctl grim slurp keepassxc nm-connection-editor network-manager-applet pavucontrol fuzzel flatpak tesseract tesseract-langpack-eng tesseract-langpack-rus ImageMagick) FLATPAKS=(com.google.Chrome org.telegram.desktop org.remmina.Remmina com.nextcloud.desktopclient.nextcloud) c_hi=$'\e[1;38;2;233;30;99m'; c_dim=$'\e[2m'; c_err=$'\e[31m'; c_off=$'\e[0m' step() { printf '\n%s==> %s%s\n' "$c_hi" "$*" "$c_off"; } info() { printf ' %s\n' "$*"; } warn() { printf '%s!! %s%s\n' "$c_err" "$*" "$c_off" >&2; } die() { warn "$*"; exit 1; } run() { if [ $DRY = 1 ]; then printf ' %s$ %s%s\n' "$c_dim" "$*" "$c_off"; else "$@"; fi; } ask() { [ $ASSUME_YES = 1 ] && return 0; local v; read -r -p " $1 [Y/n] " v; [[ ! $v =~ ^[nNнН] ]]; } while [ $# -gt 0 ]; do case "$1" in --dry-run) DRY=1 ;; --yes|-y) ASSUME_YES=1 ;; --full) FULL=1 ;; --no-packages) DO_PKG=0 ;; --no-config) DO_CONFIG=0 ;; -h|--help) sed -n '2,10p' "$0" | sed 's/^# \{0,1\}//'; exit 0 ;; *) die "неизвестный параметр: $1 (см. --help)" ;; esac shift done # ---------- проверки ---------- step "Проверки" [ "$(id -u)" -ne 0 ] || die "запускайте от обычного пользователя, sudo скрипт вызовет сам" for d in hypr dms/plugins/networkEditor systemd/user kitty; do [ -e "$REPO/$d" ] || die "в репозитории нет $d (запускайте install.sh из корня hyprland-rising)" done . /etc/os-release 2>/dev/null || true info "система: ${PRETTY_NAME:-unknown}" info "режим: $([ $FULL = 1 ] && echo 'полный (+ инструменты и приложения)' || echo 'визуал + SSH-меню')" if [ "${ID:-}" != fedora ]; then warn "это не Fedora: пакетный этап рассчитан на dnf и COPR" [ $DO_PKG = 1 ] && { ask "продолжить всё равно?" || exit 1; } elif [ "${VERSION_ID:-}" != 44 ]; then warn "райс собирался на Fedora 44, у вас ${VERSION_ID:-?}: COPR может не иметь сборок под эту версию" [ $DO_PKG = 1 ] && { ask "продолжить?" || exit 1; } fi [ $DO_PKG = 1 ] && ! command -v sudo >/dev/null && die "нужен sudo" [ $DRY = 1 ] && info "режим --dry-run: ничего не будет изменено" # ---------- пакеты ---------- if [ $DO_PKG = 1 ]; then step "Репозитории COPR: ${COPRS[*]}" info "COPR — сторонние репозитории, пакеты в них никем не проверяются." ask "подключить?" || die "без них Hyprland и DMS не установить (этап можно пропустить: --no-packages)" for c in "${COPRS[@]}"; do run sudo dnf copr enable -y "$c"; done step "Hyprland" run sudo dnf -y install "${PKGS_HYPR[@]}" step "DankMaterialShell" run sudo dnf -y install "${PKGS_SHELL[@]}" step "Шрифт, терминал и базовые утилиты оформления" run sudo dnf -y install "${PKGS_VISUAL[@]}" step "SSH-меню и навигация по окнам" run sudo dnf -y install "${PKGS_MENU[@]}" if [ $FULL = 1 ]; then step "Остальные инструменты (OCR, скриншоты, пипетка и т. д.)" run sudo dnf -y install --skip-unavailable "${PKGS_TOOLS[@]}" step "Flatpak-приложения: ${FLATPAKS[*]}" info "Chrome, Telegram, Remmina и клиент Nextcloud используются в бинах и автозапуске." if ask "установить?"; then run flatpak remote-add --user --if-not-exists flathub https://dl.flathub.org/repo/flathub.flatpakrepo run flatpak install --user -y flathub "${FLATPAKS[@]}" fi fi fi # ---------- конфиги ---------- backup() { [ -e "$1" ] || [ -L "$1" ] && run mv "$1" "$1.bak-$TS" && info "старое сохранено: $1.bak-$TS" || true; } if [ $DO_CONFIG = 1 ]; then step "Конфиги → $CFG" run mkdir -p "$CFG/dms/plugins" "$CFG/systemd/user" "$CFG/kitty" backup "$CFG/hypr" run cp -a "$REPO/hypr" "$CFG/hypr" run chmod +x "$CFG"/hypr/scripts/*.sh "$CFG"/hypr/scripts/*.py info "hypr/ (hyprland.lua, hypridle.conf, scripts, справка)" if [ -f "$REPO/dms/settings.json" ]; then backup "$CFG/dms/settings.json" run cp -a "$REPO/dms/settings.json" "$CFG/dms/settings.json" info "dms/settings.json (панель, тема)" fi if [ $FULL = 1 ]; then backup "$CFG/dms/plugins/networkEditor" run cp -a "$REPO/dms/plugins/networkEditor" "$CFG/dms/plugins/networkEditor" info "плагин DMS networkEditor (кнопка nm-connection-editor)" fi # плагин: в полном режиме включаем, в визуальном убираем его кнопку из панели (редактора там нет) if [ $DRY = 1 ]; then info "${c_dim}\$ networkEditor: $([ $FULL = 1 ] && echo включить || echo 'убрать кнопку из панели') (dms/settings.json, plugin_settings.json)${c_off}" else python3 - "$CFG/dms" "$FULL" <<'PY' import json, os, sys base, full = sys.argv[1], sys.argv[2] == "1" sp, pp = os.path.join(base, "settings.json"), os.path.join(base, "plugin_settings.json") if full: d = json.load(open(pp)) if os.path.exists(pp) else {} d.setdefault("networkEditor", {})["enabled"] = True json.dump(d, open(pp, "w"), indent=2) elif os.path.exists(sp): s = json.load(open(sp)) for bar in s.get("barConfigs", []): for k in ("leftWidgets", "centerWidgets", "rightWidgets"): if k in bar: bar[k] = [w for w in bar[k] if not (isinstance(w, dict) and w.get("id") == "networkEditor")] json.dump(s, open(sp, "w"), indent=2, ensure_ascii=False) PY fi backup "$CFG/kitty/kitty.conf" run cp -a "$REPO/kitty/kitty.conf" "$CFG/kitty/kitty.conf" info "kitty/kitty.conf" run cp -a "$REPO/systemd/user/hyprland-session.target" "$CFG/systemd/user/" run systemctl --user daemon-reload || warn "systemctl --user недоступен (нет пользовательской сессии systemd): выполните daemon-reload после входа" info "systemd/user/hyprland-session.target (нужен порталам: выбор файлов, демонстрация экрана)" # каталог под ControlMaster, который использует ~/.ssh/config run install -d -m 700 "$HOME/.ssh" "$HOME/.ssh/sockets" fi # ---------- итог ---------- step "Готово" cat <