configuration.nix/installer/mirea-install.sh

249 lines
11 KiB
Shell
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env bash
# MIREA NixOS Installer
# Устанавливает NixOS рядом с Windows или на чистый диск.
# NixOS root: 50 GiB, EFI (при чистой установке): 512 MiB.
set -euo pipefail
CONFIG_REPO_URL="@CONFIG_REPO_URL@"
NIXOS_SIZE_GIB=50
EFI_SIZE_MIB=512
MNT=/mnt
R='\033[0;31m' G='\033[0;32m' Y='\033[1;33m' B='\033[0;34m' N='\033[0m'
info() { echo -e "${G}[✓]${N} $*"; }
warn() { echo -e "${Y}[!]${N} $*"; }
error() { echo -e "${R}[✗]${N} $*" >&2; exit 1; }
step() { echo -e "\n${B}══${N} $* ${B}══${N}"; }
# ── Проверки ──────────────────────────────────────────────────────────────────
[[ $EUID -eq 0 ]] || error "Запустите от root"
command -v sgdisk &>/dev/null || error "sgdisk не найден (пакет gptfdisk)"
command -v parted &>/dev/null || error "parted не найден"
command -v mkfs.fat &>/dev/null || error "mkfs.fat не найден (пакет dosfstools)"
command -v mkfs.ext4 &>/dev/null || error "mkfs.ext4 не найден (пакет e2fsprogs)"
# ── Выбор диска ───────────────────────────────────────────────────────────────
step "Доступные диски"
lsblk -d -o NAME,SIZE,MODEL,TRAN | grep -v loop
echo
while true; do
read -rp "Имя диска для установки (например: sda, nvme0n1): " dname
DISK="/dev/$dname"
[[ -b "$DISK" ]] && break
warn "Блочное устройство $DISK не найдено, попробуйте ещё раз"
done
info "Выбран диск: $DISK"
# ── Определение наличия Windows ───────────────────────────────────────────────
step "Проверка наличия Windows"
HAS_WINDOWS=false
EFI_PART=""
pttype=$(lsblk -d -o PTTYPE "$DISK" 2>/dev/null | tail -1 | tr -d ' ')
if [[ "$pttype" == "gpt" ]]; then
while IFS= read -r pdev; do
tmpdir=$(mktemp -d)
if mount -t vfat "$pdev" "$tmpdir" 2>/dev/null; then
if [[ -d "$tmpdir/EFI/Microsoft" ]]; then
HAS_WINDOWS=true
EFI_PART="$pdev"
info "Windows обнаружена, EFI раздел: $EFI_PART"
fi
umount "$tmpdir"
fi
rmdir "$tmpdir"
done < <(lsblk -r -o NAME,PARTTYPE "$DISK" 2>/dev/null \
| awk '/c12a7328-f81f-11d2-ba4b-00a0c93ec93b/{print "/dev/"$1}')
fi
$HAS_WINDOWS || info "Windows не обнаружена"
# ── Разметка ──────────────────────────────────────────────────────────────────
NIXOS_PART=""
NEED_NEW_EFI=false
if $HAS_WINDOWS; then
step "Двойная загрузка: проверка EFI раздела"
efi_size_b=$(lsblk -b -d -o SIZE "$EFI_PART" 2>/dev/null | tail -1 | tr -d ' ')
efi_size_mib=$(( efi_size_b / 1024 / 1024 ))
info "Размер существующего EFI раздела ($EFI_PART): ${efi_size_mib} MiB"
if (( efi_size_mib < 256 )); then
warn "EFI раздел слишком мал — стандартные 100 MiB Windows EFI недостаточны даже для обновлений NixOS."
warn "Будет создан отдельный EFI раздел NixOS 500 MiB."
NEED_NEW_EFI=true
else
info "EFI раздел достаточного размера, будет использован совместно с Windows."
fi
step "Поиск свободного места"
# sgdisk -f = first usable sector in largest free space
# sgdisk -E = last usable sector in largest free space
sector_size=$(cat "/sys/block/$(basename "$DISK")/queue/logical_block_size")
free_first=$(sgdisk -f "$DISK" 2>/dev/null)
free_last=$(sgdisk -E "$DISK" 2>/dev/null)
free_bytes=$(( (free_last - free_first + 1) * sector_size ))
free_gib=$(( free_bytes / 1024 / 1024 / 1024 ))
if $NEED_NEW_EFI; then
required_bytes=$(( (500 * 1024 * 1024) + (NIXOS_SIZE_GIB * 1024 * 1024 * 1024) ))
required_label="${NIXOS_SIZE_GIB} GiB + 500 MiB EFI"
else
required_bytes=$(( NIXOS_SIZE_GIB * 1024 * 1024 * 1024 ))
required_label="${NIXOS_SIZE_GIB} GiB"
fi
if (( free_bytes < required_bytes )); then
error "Свободного места ${free_gib} GiB < ${required_label}. Освободите место в Windows и повторите."
fi
info "Свободного места: ${free_gib} GiB"
echo
if $NEED_NEW_EFI; then
warn "Будет создан новый EFI раздел NixOS 500 MiB + раздел NixOS ${NIXOS_SIZE_GIB} GiB."
warn "Старый EFI Windows ($EFI_PART, ${efi_size_mib} MiB) не затрагивается и не используется для NixOS."
else
warn "Будет создан раздел NixOS ${NIXOS_SIZE_GIB} GiB."
warn "EFI раздел Windows ($EFI_PART) будет использован совместно."
fi
warn "Данные Windows не затрагиваются."
echo
read -rp "Продолжить? (да/нет): " ans
[[ "$ans" == "да" ]] || error "Установка отменена"
if $NEED_NEW_EFI; then
sgdisk \
--new=0:"${free_first}s":"+500MiB" \
--typecode=0:ef00 \
--change-name=0:"NixOS-EFI" \
--new=0:0:"+${NIXOS_SIZE_GIB}GiB" \
--typecode=0:8304 \
--change-name=0:"NixOS" \
"$DISK"
partprobe "$DISK"; sleep 2
EFI_PART=$(lsblk -r -o NAME,PARTLABEL "$DISK" 2>/dev/null \
| awk '$2 == "NixOS-EFI" {print "/dev/"$1}' | tail -1)
NIXOS_PART=$(lsblk -r -o NAME,PARTLABEL "$DISK" 2>/dev/null \
| awk '$2 == "NixOS" {print "/dev/"$1}' | tail -1)
else
sgdisk \
--new=0:"${free_first}s":"+${NIXOS_SIZE_GIB}GiB" \
--typecode=0:8304 \
--change-name=0:"NixOS" \
"$DISK"
partprobe "$DISK"; sleep 2
NIXOS_PART=$(lsblk -r -o NAME,PARTLABEL "$DISK" 2>/dev/null \
| awk '$2 == "NixOS" {print "/dev/"$1}' | tail -1)
fi
else
step "Чистая установка"
disk_gib=$(( $(lsblk -d -b -o SIZE "$DISK" | tail -1 | tr -d ' ') / 1024 / 1024 / 1024 ))
(( disk_gib >= NIXOS_SIZE_GIB + 1 )) \
|| error "Диск слишком мал: ${disk_gib} GiB (нужно минимум $((NIXOS_SIZE_GIB + 1)) GiB)"
echo
warn "ВСЕ ДАННЫЕ НА ДИСКЕ $DISK (${disk_gib} GiB) БУДУТ УНИЧТОЖЕНЫ!"
echo
read -rp "Введите имя диска для подтверждения ($(basename "$DISK")): " ans
[[ "$ans" == "$(basename "$DISK")" ]] || error "Установка отменена"
sgdisk --zap-all "$DISK"
sgdisk \
--new=1:2048:"+${EFI_SIZE_MIB}MiB" \
--typecode=1:ef00 \
--change-name=1:"EFI" \
--new=2:0:"+${NIXOS_SIZE_GIB}GiB" \
--typecode=2:8304 \
--change-name=2:"NixOS" \
"$DISK"
partprobe "$DISK"; sleep 2
EFI_PART=$(lsblk -r -o NAME,PARTLABEL "$DISK" 2>/dev/null \
| awk '/^[^ ]+ EFI$/{print "/dev/"$1}')
NIXOS_PART=$(lsblk -r -o NAME,PARTLABEL "$DISK" 2>/dev/null \
| awk '/NixOS/{print "/dev/"$1}')
fi
[[ -b "$NIXOS_PART" ]] || error "Не удалось определить раздел NixOS после разметки"
[[ -b "$EFI_PART" ]] || error "Не удалось определить EFI раздел после разметки"
info "EFI раздел: $EFI_PART"
info "NixOS раздел: $NIXOS_PART"
# ── Форматирование ────────────────────────────────────────────────────────────
step "Форматирование"
if ! $HAS_WINDOWS || $NEED_NEW_EFI; then
mkfs.fat -F32 -n EFI "$EFI_PART"
info "EFI отформатирован (FAT32)"
else
info "EFI Windows используется как есть"
fi
mkfs.ext4 -L nixos -F "$NIXOS_PART"
info "NixOS раздел отформатирован (ext4)"
# ── Монтирование ──────────────────────────────────────────────────────────────
step "Монтирование"
mount "$NIXOS_PART" "$MNT"
mkdir -p "$MNT/boot"
mount "$EFI_PART" "$MNT/boot"
info "Смонтировано в $MNT"
# ── Конфигурация ──────────────────────────────────────────────────────────────
step "Генерация hardware-configuration.nix"
nixos-generate-config --root "$MNT"
# Добавляем noatime к ext4 — уменьшает запись на диск, важно на 50G машинах
awk '
/fsType = "ext4"/ {
print
print " options = [ \"noatime\" ];"
next
}
{ print }
' "$MNT/etc/nixos/hardware-configuration.nix" > /tmp/hw-patched.nix
mv /tmp/hw-patched.nix "$MNT/etc/nixos/hardware-configuration.nix"
info "ext4 разделы: опция noatime добавлена"
step "Загрузка конфигурации MIREA"
tmpconf=$(mktemp -d)
git clone --depth=1 "$CONFIG_REPO_URL" "$tmpconf/config" \
|| error "Не удалось клонировать $CONFIG_REPO_URL. Проверьте сетевое подключение."
cp "$tmpconf/config/flake.nix" "$MNT/etc/nixos/"
cp "$tmpconf/config/flake.lock" "$MNT/etc/nixos/"
cp "$tmpconf/config/configuration.nix" "$MNT/etc/nixos/"
# hardware-configuration.nix оставляем сгенерированный
rm -rf "$tmpconf"
info "Конфигурация MIREA установлена"
# ── Установка ─────────────────────────────────────────────────────────────────
step "Установка NixOS (это займёт время)"
nixos-install \
--root "$MNT" \
--flake "/mnt/etc/nixos#nixos" \
--no-root-passwd
# ── Завершение ────────────────────────────────────────────────────────────────
step "Готово"
umount -R "$MNT" || true
echo
info "NixOS установлена на $DISK"
info "Извлеките USB-носитель и перезагрузите систему"
echo
read -rp "Перезагрузить сейчас? (да/нет): " ans
[[ "$ans" == "да" ]] && reboot || true