install.sh 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394
  1. #!/bin/bash
  2. # --- НАСТРОЙКИ ---
  3. # Цвета для вывода
  4. GREEN="\033[1;32m"
  5. YELLOW="\033[1;33m"
  6. RED="\033[1;31m"
  7. NC="\033[0m" # No Color
  8. # Путь к этому скрипту и его папке
  9. SCRIPT_DIR=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" &>/dev/null && pwd)
  10. # Имена файлов с пакетами
  11. PACMAN_PKGS="pkglist.txt"
  12. AUR_PKGS="aurlist.txt"
  13. # --- НАСТРОЙКИ СИМЛИНКОВ (Имена папок в репозитории) ---
  14. CONFIG_DIR_NAME="config"
  15. HOME_DIR_NAME="home"
  16. SYSTEM_DIR_NAME="system"
  17. # --- ХЕЛПЕРЫ ---
  18. msg() {
  19. echo -e "${GREEN}[INFO]${NC} $1"
  20. }
  21. warn() {
  22. echo -e "${YELLOW}[WARN]${NC} $1"
  23. }
  24. err() {
  25. echo -e "${RED}[ERROR]${NC} $1"
  26. }
  27. # --- ФУНКЦИИ ---
  28. # 1. Установка YAY (AUR Helper)
  29. install_yay() {
  30. if ! command -v yay &>/dev/null; then
  31. msg "YAY не найден. Установка YAY..."
  32. if ! pacman -Q git &>/dev/null || ! pacman -Q base-devel &>/dev/null; then
  33. sudo pacman -S --needed git base-devel
  34. fi
  35. rm -rf /tmp/yay
  36. git clone https://aur.archlinux.org/yay.git /tmp/yay
  37. (cd /tmp/yay && makepkg -si --noconfirm)
  38. rm -rf /tmp/yay
  39. msg "YAY установлен."
  40. else
  41. msg "YAY уже установлен."
  42. fi
  43. }
  44. # 2. Установка пакетов (Pacman и YAY)
  45. install_packages() {
  46. msg "Сбор пакетов для установки..."
  47. # Основные пакеты
  48. local pacman_args=$(sed 's/#.*//' "$SCRIPT_DIR/$PACMAN_PKGS" | grep -vE '^\s*$' | xargs)
  49. local aur_args=$(sed 's/#.*//' "$SCRIPT_DIR/$AUR_PKGS" | grep -vE '^\s*$' | xargs)
  50. # --- Поиск и выбор дополнительных пакетов ---
  51. local optional_pacman_lists=($(find "$SCRIPT_DIR" -maxdepth 1 -name "pkglist-*.txt" ! -name "$PACMAN_PKGS"))
  52. local optional_aur_lists=($(find "$SCRIPT_DIR" -maxdepth 1 -name "aurlist-*.txt" ! -name "$AUR_PKGS"))
  53. if [ ${#optional_pacman_lists[@]} -gt 0 ] || [ ${#optional_aur_lists[@]} -gt 0 ]; then
  54. warn "Найдены дополнительные списки пакетов:"
  55. for list in "${optional_pacman_lists[@]}"; do echo " -> $(basename "$list") (Pacman)"; done
  56. for list in "${optional_aur_lists[@]}"; do echo " -> $(basename "$list") (AUR)"; done
  57. read -p "Хотите выбрать пакеты из этих списков для установки? [y/N]: " choice < /dev/tty
  58. if [[ "$choice" == "y" || "$choice" == "Y" ]]; then
  59. for list in "${optional_pacman_lists[@]}"; do
  60. read -p " -> Установить из '$(basename "$list")'? [y/N]: " list_choice < /dev/tty
  61. if [[ "$list_choice" == "y" || "$list_choice" == "Y" ]]; then
  62. pacman_args+=" $(sed 's/#.*//' "$list" | grep -vE '^\s*$' | xargs)"
  63. fi
  64. done
  65. for list in "${optional_aur_lists[@]}"; do
  66. read -p " -> Установить из '$(basename "$list")'? [y/N]: " list_choice < /dev/tty
  67. if [[ "$list_choice" == "y" || "$list_choice" == "Y" ]]; then
  68. aur_args+=" $(sed 's/#.*//' "$list" | grep -vE '^\s*$' | xargs)"
  69. fi
  70. done
  71. fi
  72. fi
  73. # --- Установка пакетов Pacman ---
  74. if [[ ! -z "$pacman_args" ]]; then
  75. msg "Установка пакетов из Pacman..."
  76. sudo pacman -S --needed $pacman_args
  77. else
  78. msg "Список Pacman для установки пуст."
  79. fi
  80. # --- Установка пакетов AUR ---
  81. if [[ ! -z "$aur_args" ]]; then
  82. msg "Проверка и установка YAY..."
  83. install_yay
  84. msg "Установка пакетов из AUR..."
  85. yay -S --needed $aur_args
  86. else
  87. msg "Список AUR для установки пуст."
  88. fi
  89. msg "Установка пакетов завершена."
  90. }
  91. # 3. (НОВАЯ) Рекурсивная функция линковки
  92. link_item() {
  93. local src="$1"
  94. local dest="$2"
  95. # Проверка источника
  96. if [ ! -e "$src" ]; then
  97. return
  98. fi
  99. # 1. Если цель существует и это директория (и не симлинк)
  100. # И источник тоже директория
  101. # -> РЕКУРСИЯ (MERGE)
  102. if [ -d "$dest" ] && [ ! -L "$dest" ] && [ -d "$src" ]; then
  103. # msg " [DIR] Вход в $dest"
  104. for child in "$src"/*; do
  105. [ -e "$child" ] || continue
  106. local child_name=$(basename "$child")
  107. link_item "$child" "$dest/$child_name"
  108. done
  109. return
  110. fi
  111. # 2. Если цель существует (файл или симлинк)
  112. if [ -e "$dest" ] || [ -L "$dest" ]; then
  113. # Если это уже правильный симлинк - пропускаем
  114. if [ -L "$dest" ]; then
  115. local current_target=$(readlink -f "$dest")
  116. local source_absolute=$(readlink -f "$src")
  117. if [ "$current_target" == "$source_absolute" ]; then
  118. # msg " [OK] $dest уже указывает на правильный файл"
  119. return
  120. fi
  121. fi
  122. # Если это файл или неправильный симлинк - бэкап
  123. warn " [BACKUP] $dest существует. Бэкап -> $dest.bak"
  124. mv "$dest" "$dest.bak"
  125. fi
  126. # 3. Создаем симлинк
  127. # Создаем родительскую папку, если её нет (например для ~/.config/foo/bar)
  128. mkdir -p "$(dirname "$dest")"
  129. ln -sfn "$src" "$dest"
  130. msg " [LINK] $dest -> $src"
  131. }
  132. # 4. Создание символических ссылок (Обновлено)
  133. link_dotfiles() {
  134. msg "Создание символических ссылок..."
  135. # ВАЖНО: Предварительно создаем критические системные папки.
  136. # Это заставит функцию link_item использовать режим MERGE (рекурсию) для них,
  137. # вместо создания симлинка на всю папку.
  138. msg " -> Подготовка структуры папок..."
  139. mkdir -p "$HOME/.config"
  140. mkdir -p "$HOME/.local/share"
  141. mkdir -p "$HOME/.local/state"
  142. mkdir -p "$HOME/.local/bin"
  143. # mkdir -p "$HOME/bin" # Если используется
  144. # --- 1. Линкуем файлы в $HOME (из папки 'home') ---
  145. msg " -> Обработка '$HOME_DIR_NAME'..."
  146. local source_dir="$SCRIPT_DIR/$HOME_DIR_NAME"
  147. if [ -d "$source_dir" ]; then
  148. for item_path in "$source_dir"/*; do
  149. [ -e "$item_path" ] || continue # Пропуск, если папка пуста
  150. local item_name=$(basename "$item_path")
  151. # Вызываем рекурсивную функцию
  152. link_item "$item_path" "$HOME/$item_name"
  153. done
  154. fi
  155. # --- 2. Линкуем файлы в $HOME/.config (из папки 'config') ---
  156. msg " -> Обработка '$CONFIG_DIR_NAME'..."
  157. source_dir="$SCRIPT_DIR/$CONFIG_DIR_NAME"
  158. if [ -d "$source_dir" ]; then
  159. for item_path in "$source_dir"/*; do
  160. [ -e "$item_path" ] || continue
  161. local item_name=$(basename "$item_path")
  162. link_item "$item_path" "$HOME/.config/$item_name"
  163. done
  164. fi
  165. msg "Симлинки обработаны."
  166. }
  167. # 5. Проверка текущей конфигурации
  168. check_config() {
  169. msg "Проверка установленных пакетов Pacman..."
  170. local missing_pacman=0
  171. # Ищем pkglist.txt и pkglist-*.txt
  172. for f in $(find "$SCRIPT_DIR" -maxdepth 1 -name "pkglist*.txt"); do
  173. while IFS= read -r line || [[ -n "$line" ]]; do
  174. local pkg=$(echo "$line" | sed 's/#.*//' | xargs)
  175. if [[ -z "$pkg" ]]; then continue; fi
  176. if [[ "$pkg" == "xorg" ]]; then continue; fi
  177. if ! pacman -Q "$pkg" &>/dev/null; then
  178. warn " -> Не найден (Pacman, из $(basename "$f")): $pkg"
  179. missing_pacman=1
  180. fi
  181. done < "$f"
  182. done
  183. if [ $missing_pacman -eq 0 ]; then msg "Все пакеты Pacman установлены."; fi
  184. msg "Проверка установленных пакетов AUR..."
  185. local missing_aur=0
  186. for f in $(find "$SCRIPT_DIR" -maxdepth 1 -name "aurlist*.txt"); do
  187. while IFS= read -r line || [[ -n "$line" ]]; do
  188. local pkg=$(echo "$line" | sed 's/#.*//' | xargs)
  189. if [[ -z "$pkg" ]]; then continue; fi
  190. if ! pacman -Q "$pkg" &>/dev/null; then
  191. warn " -> Не найден (AUR, из $(basename "$f")): $pkg"
  192. missing_aur=1
  193. fi
  194. done < "$f"
  195. done
  196. if [ $missing_aur -eq 0 ]; then msg "Все пакеты AUR установлены."; fi
  197. msg "Проверка симлинков (выборочная)..."
  198. # Просто проверим наличие ссылок для корневых элементов
  199. local source_dir="$SCRIPT_DIR/$HOME_DIR_NAME"
  200. if [ -d "$source_dir" ]; then
  201. for item_path in "$source_dir"/*; do
  202. [ -e "$item_path" ] || continue
  203. local item_name=$(basename "$item_path")
  204. # Если это папка .local, проверяем глубже
  205. if [ "$item_name" == ".local" ]; then
  206. if [ ! -d "$HOME/.local" ]; then warn " -> Папка $HOME/.local отсутствует!"; fi
  207. elif [ ! -e "$HOME/$item_name" ]; then
  208. warn " -> Элемент не найден: $HOME/$item_name"
  209. fi
  210. done
  211. fi
  212. msg "Проверка завершена."
  213. }
  214. # 6. Проверка драйверов
  215. check_drivers() {
  216. msg "Проверка оборудования и рекомендации по драйверам..."
  217. if ! command -v lspci &>/dev/null; then
  218. warn "Команда lspci не найдена. Установите пакет 'pciutils'."
  219. return
  220. fi
  221. local vga=$(lspci -k | grep -A 2 -E "(VGA|3D)")
  222. if echo "$vga" | grep -iq "NVIDIA"; then
  223. warn "Найдена карта NVIDIA. Рекомендуемые пакеты:"
  224. warn " -> nvidia (или nvidia-lts, nvidia-dkms)"
  225. warn " -> lib32-nvidia-utils"
  226. elif echo "$vga" | grep -iq "Intel"; then
  227. msg "Найдена карта Intel. Рекомендуемые пакеты:"
  228. msg " -> mesa, lib32-mesa, vulkan-intel"
  229. elif echo "$vga" | grep -iq "AMD"; then
  230. msg "Найдена карта AMD/ATI. Рекомендуемые пакеты:"
  231. msg " -> mesa, lib32-mesa, vulkan-radeon"
  232. fi
  233. if lspci -k | grep -iq "broadcom"; then
  234. warn "Найден чип Broadcom. Возможно нужен: broadcom-wl-dkms"
  235. fi
  236. }
  237. # 7. Применение системных конфигов
  238. apply_system_configs() {
  239. msg "--- РЕЖИМ: ПРИМЕНЕНИЕ СИСТЕМНЫХ КОНФИГОВ ---"
  240. local system_source_dir="$SCRIPT_DIR/$SYSTEM_DIR_NAME"
  241. if [ ! -d "$system_source_dir" ]; then
  242. err "Папка '$system_source_dir' не найдена."
  243. return 1
  244. fi
  245. find "$system_source_dir" -type f | while read -r source_file; do
  246. local rel_path=${source_file#$system_source_dir/}
  247. local target_file="/$rel_path"
  248. msg "Конфиг: $rel_path"
  249. if [ ! -f "$target_file" ]; then
  250. warn " Файл '$target_file' не существует в системе."
  251. read -p " Скопировать? [y/N]: " choice < /dev/tty
  252. if [[ "$choice" =~ ^[yY]$ ]]; then
  253. sudo mkdir -p "$(dirname "$target_file")"
  254. sudo cp "$source_file" "$target_file"
  255. msg " -> СКОПИРОВАНО."
  256. fi
  257. continue
  258. fi
  259. if command -v diff &>/dev/null; then
  260. if ! diff -q "$target_file" "$source_file" &>/dev/null; then
  261. msg " Найдены различия:"
  262. diff -u "$target_file" "$source_file" | head -n 20
  263. warn " Заменить системный файл?"
  264. read -p " [y/N/b] (Да / Нет / Бэкап): " choice < /dev/tty
  265. case "$choice" in
  266. y|Y)
  267. sudo cp "$source_file" "$target_file"
  268. msg " -> ЗАМЕНЕНО."
  269. ;;
  270. b|B)
  271. sudo mv "$target_file" "$target_file.bak"
  272. sudo cp "$source_file" "$target_file"
  273. msg " -> БЭКАП И ЗАМЕНА."
  274. ;;
  275. esac
  276. else
  277. msg " -> Идентичны."
  278. fi
  279. else
  280. warn " diff не установлен, сравнение невозможно."
  281. fi
  282. done
  283. }
  284. # 8. Создание папок пользователя
  285. create_user_dirs() {
  286. msg "Проверка стандартных папок пользователя..."
  287. # Если xdg-user-dirs установлен, лучше использовать его
  288. if command -v xdg-user-dirs-update &>/dev/null; then
  289. xdg-user-dirs-update
  290. msg " -> Выполнен xdg-user-dirs-update"
  291. else
  292. mkdir -p "$HOME/Documents" "$HOME/Downloads" "$HOME/Pictures"
  293. msg " -> Папки созданы (fallback)."
  294. fi
  295. }
  296. # --- ГЛАВНЫЙ БЛОК ---
  297. show_help() {
  298. echo "Dotfiles Manager"
  299. echo "Команды:"
  300. echo " install - Установить пакеты, создать ссылки."
  301. echo " check - Проверка статуса."
  302. echo " update - git pull + install."
  303. echo " drivers - Рекомендации по драйверам."
  304. echo " system - Системные конфиги (/etc)."
  305. }
  306. if [ "$EUID" -eq 0 ]; then
  307. err "Запускайте от пользователя, не от root!"
  308. exit 1
  309. fi
  310. if [ $# -eq 0 ]; then show_help; exit 0; fi
  311. case "$1" in
  312. install)
  313. msg "--- УСТАНОВКА ---"
  314. install_packages
  315. link_dotfiles
  316. create_user_dirs
  317. msg "Готово."
  318. ;;
  319. check)
  320. check_config
  321. ;;
  322. update)
  323. msg "--- ОБНОВЛЕНИЕ ---"
  324. if git pull; then
  325. install_packages
  326. link_dotfiles
  327. create_user_dirs
  328. msg "Обновлено."
  329. else
  330. err "Ошибка git pull."
  331. fi
  332. ;;
  333. drivers)
  334. check_drivers
  335. ;;
  336. system)
  337. apply_system_configs
  338. ;;
  339. help|*)
  340. show_help
  341. ;;
  342. esac