Graficzny instalator Zenit Linux. Zbudowany w Nim, interfejs na Fidget (immediate-mode UI, renderowane wektorowo przez pixie/OpenGL -- bez zależności od GTK/Qt).
Funkcje: partycjonowanie automatyczne (wymaż dysk) i ręczne (przypisanie
istniejących partycji do ról, z walidacją unikalności i minimalnego
rozmiaru), swap (partycja albo plik wymiany, konfigurowalny rozmiar),
szyfrowanie LUKS (łącznie z szyfrowanym swapem losowym kluczem), GRUB w
trybie UEFI albo BIOS-legacy z autodetekcją firmware'u, subwoluminy btrfs
(@/@home/@snapshots), ochrona przed wybraniem nośnika live jako celu
instalacji, wykrywanie innych systemów (dual-boot) przez os-prober,
generowanie /etc/fstab//etc/crypttab, sprzątanie
(odmontowanie/swapoff/luksClose) po nieudanej instalacji, fstrim.timer
dla SSD, instalacja na wątku roboczym (GUI nie zamraża się na czas
instalacji), przełączalny motyw ciemny/jasny (czarno-złoty domyślnie),
pełny interfejs w pięciu językach (pl/en/de/fr/es, przełącza się razem z
językiem wybranym dla instalowanego systemu) oraz alternatywne tryby bez
GUI: tekstowy --server i w pełni bezobsługowy --autoinstall=<plik>
(patrz niżej).
zlb (patrz zlbpkg/iso.nim w repo zlb) generuje w GRUB-ie dwa
oddzielne wpisy menu na zbudowanym ISO, dokładnie tak jak najnowsze
Fedory:
- "Try/Live Zenit Linux" -- zwykła sesja live,
boot=zenitbez dodatkowego parametru. - "Install Zenit Linux" -- to samo środowisko live, ale z
installer=1na linii poleceń jądra.
installerpkg/liveenv.nim czyta /proc/cmdline i na tej podstawie
installer.nim decyduje, czy wystartować od razu pełnoekranowo
(blmInstallerAuto), czy zostać zwykłą aplikacją dostępną z pulpitu
live (blmLiveOnly), czy działać jako samodzielne narzędzie
reinstalacji/odzyskiwania uruchomione ręcznie z zainstalowanego systemu
(blmStandalone).
Binarka installer sama trafia do obrazu przez ekosystem own zpm
(custom/own-repository.json w repo zpm) i jest osadzana w rootfsie
przez zlbpkg/rootfs.nim::embedInstaller w repo zlb -- nigdy przez
curl.
Cała instalacja (system bazowy + opcjonalne pakiety wybrane w
kreatorze) przechodzi przez installerpkg/zpmclient.nim, które woła
wyłącznie zpm --root=<target> .... Zpm samo rozstrzyga, z którego
backendu skorzystać (apt/dnf/pacman/zypper/flatpak/snap/brew/cargo/pip/
npm/own) na podstawie distro.base / jawnej adnotacji pakiet -> backend.
Fidget renderuje przez OpenGL/GLFW i linkuje bezpośrednio z X11 --
zainstaluj nagłówki deweloperskie zanim uruchomisz nimble/janet.
Bez nich nimble build kompiluje sam kod Nim poprawnie, ale pada na
etapie kompilacji C-ka dołączonego przez staticglfw z błędem:
fatal error: X11/Xlib.h: No such file or directory
Naprawa (Debian/Ubuntu -- jako root pomiń sudo):
sudo apt update
sudo apt install -y libglfw3-dev libgl1-mesa-dev libglu1-mesa-dev \
xorg-dev libxi-dev libxcursor-dev libxinerama-dev libxrandr-devNa Fedorze/RHEL: sudo dnf install glfw-devel mesa-libGL-devel mesa-libGLU-devel libXi-devel libXcursor-devel libXinerama-devel libXrandr-devel.
Na Arch: sudo pacman -S glfw-x11 mesa glu libxi libxcursor libxinerama libxrandr.
janet build.janet deps # nimble install --depsOnly + naprawia paczkę opengl (patrz niżej)
janet build.janet assets # sprawdza, że font UI (data/fonts/) jest na miejscu -- nic już nie pobiera domyślnie
janet build.janet release # -> bin/installer + bin/data/ (woła deps + assets automatycznie)
janet build.janet debug # -> bin/installer-debug + bin/data/
janet build.janet check # tylko sprawdzenie typów
janet build.janet package v0.1Bez Janeta: nimble install -y --depsOnly && nimble buildRelease.
Jeśli nimble build/nimble buildRelease kończy się:
Warning: Declarative parser failed, the file had to be parsed with the VM parser.
...
--path:.../opengl-<hash>/src ...
fidget/opengl/base.nim(1, 57) Error: cannot open file: opengl
to nie jest błąd w tym repozytorium. Paczka nimble opengl
(nim-lang/opengl) trzyma pliki
*.nim w KORZENIU paczki, a nie w podkatalogu src/. Mimo to (efekt
tej samej niespójności opengl.nimble, która wywołuje warning o
przełączeniu na stary parser VM) nimble każe nimowi szukać ich pod
.../opengl-<hash>/src/opengl.nim -- ta ścieżka po prostu nie istnieje,
więc kompilacja pada. Pinowanie innej wersji (w tym #head) tego nie
naprawia -- sprawdzone, że wskazują na ten sam układ plików.
Naprawa działa na poziomie samego kompilatora nim, a nie nimble:
config.nims w korzeniu repo jest ładowany automatycznie przez
nim przy KAŻDEJ kompilacji tego projektu -- czy to przez
nimble build, nimble buildRelease, czy nawet gołe
nim c src/installer.nim. Skanuje ~/.nimble/pkgs2/opengl-*, znajduje
faktyczne miejsce, w którym leży opengl.nim (u nas: katalog główny
paczki, .../opengl-<hash>/opengl.nim, a NIE .../src/opengl.nim,
którego nimble błędnie się spodziewa), i dokłada poprawny --path dla
bieżącej kompilacji -- bez dotykania cache'u nimble. Sprawdzone
działa: nie wymaga żadnego ręcznego kroku, wystarczy zwykłe
nimble build.
Jeśli mimo wszystko zobaczysz ten błąd, uruchom ręcznie i wklej wynik:
find ~/.nimble/pkgs2/opengl-* -maxdepth 3Obie te awarie przy STARCIE binarki (nie przy kompilacji) mają tę samą
przyczynę: Fidget doklejają data/ do ścieżki fontu WZGLĘDEM BIEŻĄCEGO
KATALOGU ROBOCZEGO procesu, nie względem lokalizacji samego pliku
wykonywalnego. Jeśli uruchamiasz binarkę z innego katalogu niż korzeń
repozytorium (np. cd bin && ./installer zamiast ./bin/installer z
korzenia), data/fonts/UiFont-Regular.ttf nie zostanie znaleziony.
File data/fonts/UiFont-Regular.ttf does not exist-- uruchamiasz z niewłaściwego katalogu, albodata/w ogóle nie zostało skopiowane razem z resztą repozytorium. Uruchom binarkę z korzenia repo, albo skopiujdata/obok niej (janet build.janet release/packagerobi to automatycznie -- patrzbin/data/po zbudowaniu).key not found: head(albo podobny błąd parsera fontu) -- plik pod tą ścieżką ISTNIEJE, ale nie jest poprawnym TTF/OTF (uszkodzony download, strona błędu HTML zapisana pod tą nazwą itp.). Podmień go na poprawny plik -- domyślnie dołączonydata/fonts/UiFont-Regular.ttfjest sprawdzonym, poprawnym plikiem (patrzdata/fonts/README.md), więc jeśli widzisz ten błąd, prawdopodobnie ktoś go ręcznie nadpisał czymś zepsutym.
app.nim::checkFontAvailable wykrywa oba te przypadki PRZED wywołaniem
Fidget i wypisuje krótki, konkretny komunikat zamiast surowego wyjątku z
głębi biblioteki -- ale samą przyczynę (zły katalog roboczy / zły plik)
trzeba poprawić ręcznie tak czy inaczej.
Zaobserwowane na żywym zrzucie ekranu z działającej binarki (nie na etapie kompilacji): tło elementu (przycisk, kafelek wyboru, aktywny krok w pasku bocznym) renderuje się poprawnie, ale napis wewnątrz -- nie.
Przyczyna: pierwotna struktura tych widżetów miała osobny węzeł
rectangle (tło) i text (napis) jako DWOJE dzieci jednej group, oba
w pełni nachodzące na tę samą pozycję. Próba naprawy przez zagnieżdżenie
tej pary w dodatkowym frame NIE POMOGŁA (potwierdzone kolejnym
zrzutem ekranu) -- więc to nie jest kwestia typu kontenera (group vs
frame), tylko samej obecności osobnego węzła rectangle obok text.
Aktualna naprawa (widgets.nim) w ogóle nie używa osobnego rectangle
do teł -- zamiast tego fill/cornerRadius/stroke idą BEZPOŚREDNIO na
group, dokładnie tak jak w jedynym elemencie, który był potwierdzone
poprawny na wszystkich dotychczasowych zrzutach: group "sidebar" w
app.nim (własny fill, wiele dzieci typu tekst/zagnieżdżona grupa, i
wszystko widoczne jednocześnie). Pełne uzasadnienie i historia obu prób
są opisane w komentarzu na górze widgets.nim.
Nadal nie mam tu środowiska graficznego do przetestowania Fidget na
żywo -- to druga, mocniej uzasadniona próba, nie potwierdzona naprawa.
Jeśli po przebudowaniu problem nadal występuje, to prawdopodobnie sam
mechanizm ustawiania fill/cornerRadius (a nie obecność osobnego
rectangle) jest tu czynnikiem -- zgłoś to razem ze zrzutem ekranu.
Obok kreatora GUI instalator ma też tryb tekstowy, prowadzony liniowo przez terminal -- odpowiednik tego, co np. Ubuntu Server ma obok swojego graficznego instalatora, przydatny na maszynach bez środowiska graficznego (serwer, konsola tekstowa, sesja przez SSH):
installer --serverKreator zadaje te samo pytania co GUI (język, klawiatura, strefa czasowa,
dysk, partycjonowanie, LUKS, konto, pakiety) w formie numerowanych list i
pytań tak/nie, a na końcu woła ten sam executor.runInstall co GUI --
zobacz installerpkg/cliapp.nim. --fullscreen/--windowed nie mają w
tym trybie znaczenia.
UWAGA: to jest przełącznik czasu wykonania w JEDNEJ binarce (bin/installer)
-- wciąż linkuje się z Fidget/OpenGL/GLFW/X11 nawet w --server, bo
installer.nim domyślnie importuje app.nim. Jeśli potrzebujesz binarki,
która NIGDY nie dotyka Fidget/OpenGL/X11 (ani przy kompilacji, ani przy
linkowaniu) -- patrz "Build headless" niżej.
janet build.janet server # -> bin/installer-server
# albo bez Janeta:
nimble buildServer # to samo, przez nimbleW przeciwieństwie do runtime'owego --server opisanego wyżej, to jest
osobny TARGET KOMPILACJI (nim c -d:server ...). installer.nim importuje
app.nim warunkowo (when not defined(server)) -- przy -d:server
app.nim, a razem z nim cały Fidget/OpenGL/GLFW/X11, nigdy nie trafia do
kompilacji ani linkowania. Ta binarka umie tylko --server/--autoinstall
(uruchomiona bez żadnej z tych flag wypisze komunikat i zakończy się kodem
- -- za to da się ją zbudować i uruchomić na maszynie bez żadnych
bibliotek graficznych, i
janet build.janet servercelowo pomijatask-deps/task-assets(nie trzeba instalować Fidget/OpenGL ani pobierać fontu, żeby ją zbudować).
Dla masowych/automatycznych wdrożeń -- odpowiednik autoinstall/cloud-init
w Ubuntu. Zamiast pytać interaktywnie, instalator czyta gotowe odpowiedzi z
prostego pliku klucz=wartość i instaluje bez żadnego potwierdzenia:
installer --autoinstall=/sciezka/do/odpowiedzi.confPrzykładowa zawartość pliku:
# Komentarze zaczynają się od #, puste linie są ignorowane.
language=pl_PL.UTF-8
keyboard=pl
timezone=Europe/Warsaw
disk=/dev/sda
partition_mode=erase # erase | manual
bootloader=uefi # uefi | bios
filesystem=ext4 # ext4 | btrfs | xfs
swap_mode=partition # none | partition | file
swap_size_mib=2048
luks=false
luks_passphrase=
# Używane tylko gdy partition_mode=manual -- ścieżki istniejących partycji,
# WSZYSTKIE muszą leżeć na dysku wskazanym przez disk= (sprawdzane) i być
# parami różne (też sprawdzane):
manual_esp=
manual_biosgrub=
manual_root=
manual_home=
manual_swap=
manual_swapfile_mib=0
fullname=Jan Kowalski
username=jkowalski
hostname=zenit-serwer
password=zmien-to-haslo
root_password=
autologin=false
extra_packages=vscode -> own,firefox -> flatpakWymagane jest przynajmniej username= i password= -- reszta ma sensowne
wartości domyślne (patrz installerpkg/cliapp.nim::runInstallerAutoinstall).
disk= musi dokładnie odpowiadać ścieżce zwróconej przez lsblk (np.
/dev/sda, /dev/nvme0n1) -- instalator jej nie zgaduje ani nie
dopasowuje częściowo. Przed instalacją sprawdzane jest to samo, co w
trybach interaktywnych: minimalny rozmiar dysku/partycji roota
(MinInstallDiskSizeBytes/MinRootPartitionSizeBytes), że
manual_esp/manual_biosgrub/manual_root/manual_home/manual_swap
leżą na dysku z disk= (a nie np. przez literówkę na innym dysku w tej
samej maszynie), że żadne dwie z nich nie wskazują tej samej partycji,
minimalna długość hasła (MinPasswordLength, patrz niżej), oraz
poprawność username=/hostname= (installerpkg/validation.nim). Każde
niepowodzenie walidacji przerywa instalację PRZED dotknięciem dysku.
Bezpieczeństwo pliku odpowiedzi: password=/root_password=/
luks_passphrase= leżą w nim jawnym tekstem -- to nieodłączna właściwość
tego mechanizmu (to samo dotyczy autoinstall/cloud-init w Ubuntu).
Instalator sam sprawdza uprawnienia pliku i ostrzega (nie blokuje), jeśli
jest czytelny dla grupy/innych -- ale to Twoja odpowiedzialność, żeby plik
nie trafił tam, gdzie nie powinien (np. chmod 600 odpowiedzi.conf, nie
commitować go do repozytorium, usunąć po instalacji).
--autoinstall jest nadrzędne wobec --server -- jeśli oba zostaną
podane, wygrywa autoinstall.
src/installer.nim -- punkt wejścia, detekcja trybu startu, --server/--autoinstall,
`when not defined(server): import app` (patrz "Build headless")
src/installerpkg/
types.nim -- wspólne typy (WizardStep, InstallPlan, ...) + stałe polityk
(MinInstallDiskSizeBytes, MinPasswordLength, ...)
liveenv.nim -- odczyt /proc/cmdline (installer=1)
validation.nim -- walidacja username/hostname (bez std/re)
i18n.nim -- słownik tłumaczeń interfejsu (pełne pl/en, częściowe de/fr/es)
diskutil.nim -- wykrywanie dysków/partycji, firmware, os-prober, nośnik live
partitioner.nim -- partycjonowanie + LUKS + swap + btrfs + mkfs + sprzątanie po błędzie
fstab.nim -- generowanie /etc/fstab (UUID-y przez blkid)
netcheck.nim -- prosty test połączenia (ping)
zpmclient.nim -- JEDYNA droga instalacji pakietów (zpm --root)
useraccount.nim -- hostname/locale/konto przez chroot
bootloader.nim -- grub-install (UEFI/BIOS-legacy) + os-prober + LUKS
executor.nim -- orkiestracja InstallPlan, postęp, wątek instalacyjny
widgets.nim -- toolkit widżetów nad prymitywami Fidget (w tym
passwordField, sizeStepper)
app.nim -- kreator GUI (drawMain, wołane co klatkę)
cliapp.nim -- kreator tekstowy (--server) + --autoinstall, bez GUI
data/fonts/ -- font UI dołączony do repozytorium (patrz data/fonts/README.md
-- WAŻNE: musi leżeć obok katalogu roboczego, z którego
uruchamiasz binarkę, nie obok samego pliku wykonywalnego)
config.nims -- naprawa błędu paczki opengl (--path na poziomie kompilatora nim)
tests/ -- testy jednostkowe czystej logiki (bez dostępu do dysku),
`nimble test` albo `janet build.janet test`
- Nośnik live jako cel instalacji.
diskutil.detectLiveMediumDiskssprawdza/proc/mounts(root sesji plus kilka znanych konwencji montowania --/cdrom,/run/live/medium,/run/live/rootfs,/lib/live/mount/medium,/run/archiso/bootmnt,/run/casper,/media/root-ro,/run/rootfsbase,/isodevice-- w zależności od narzędzia, którym zbudowano live) i oznacza pasujące dyski jakoisLiveMedium. Taki dysk nadal da się wybrać (jedyny dysk w maszynie to prawidłowy przypadek), ale wymaga dodatkowego, osobnego potwierdzenia -- w obu trybach, GUI i--server. Lista konwencji jest z konieczności best-effort -- nietypowe/rzadkie narzędzie do budowania live może się wymknąć tej detekcji. - Zduplikowane role w partycjonowaniu ręcznym. Ta sama partycja nie
może być jednocześnie np. rootem i home -- sprawdzane przed
przejściem dalej, tą samą logiką co w
--autoinstall(app.nim::manualSelectionsUnique,cliapp.nim::hasDuplicatePartitions). - Za mały dysk/partycja.
MinInstallDiskSizeBytes/MinRootPartitionSizeByteswtypes.nim(domyślnie 8 GiB) blokują kontynuację, zanim cokolwiek zostanie zapisane na dysk -- we WSZYSTKICH trybach, łącznie z--autoinstall. - Za krótkie hasło.
MinPasswordLengthwtypes.nim(domyślnie 8 znaków) dotyczy jednakowo hasła użytkownika, hasła root i hasła szyfrowania LUKS, we wszystkich trybach. To prosta, jawna polityka długości -- nie próba oceny "siły" hasła (entropii, słownikowości itp.), co jest znacznie bardziej subiektywne i poza zakresem tego prototypu. - Sprzątanie po nieudanej instalacji. Błąd w dowolnym miejscu --
także w połowie samego partycjonowania -- odmontowuje to, co zdążyło
się zamontować, wyłącza swap i zamyka kontener LUKS
(
partitioner.nim::bestEffortUndo,executor.nim::runInstall). - Szyfrowany swap. Gdy LUKS jest włączony, swap (partycja) dostaje
losowy klucz z
/dev/urandomprzy każdym rozruchu (crypttab), zamiast zostać zapisany jawnym tekstem. Plik wymiany (swapfile) automatycznie dziedziczy szyfrowanie, bo leży wewnątrz już zaszyfrowanego roota. - Kasowanie dysku z wykrytym innym systemem. Gdy tryb "wymaż cały
dysk" dotyczy dysku, na którym os-prober wykrył inny system operacyjny,
pokazywane jest dodatkowe, jawne ostrzeżenie o tym KONKRETNYM systemie
tuż przy przycisku potwierdzenia (
diskutil.filterOsesOnDisk) -- osobno od ogólnej listy "wykryto inne systemy" pokazywanej przy wyborze dysku. - Uprawnienia pliku
--autoinstall. Patrz sekcja wyżej -- ostrzeżenie (nie blokada), jeśli plik z hasłami jest czytelny dla grupy/innych. - Sprzeczne/nieznane klucze w pliku
--autoinstall. Wykrywane i zgłaszane PRZED instalacją: nieznany klucz (literówka),manual_*ustawione razem zpartition_mode=erase(ignorowane),swap_mode/swap_size_mibrazem zpartition_mode=manual(ignorowane), jednoczesnemanual_swapimanual_swapfile_mib(pierwsze wygrywa),luks_passphraseprzyluks=false(ignorowane), brakującamanual_esp/manual_biosgrubdla wybranego trybu rozruchu w partycjonowaniu ręcznym (to jedyny z tych przypadków, który przerywa instalację, nie tylko ostrzega -- prowadziłby do niebootowalnego systemu). Patrzcliapp.nim::runInstallerAutoinstall.
- Prawdziwa klawiatura wirtualna / IME dla sesji GUI bez fizycznej
klawiatury (tablety w trybie live) -- tryb
--server/build headless obchodzi ten problem, ale nie zastępuje go dla desktopowego przypadku użycia. - Wsparcie dla limine jako alternatywy dla GRUB (obecnie: GRUB w trybie
UEFI albo BIOS-legacy, patrz
bootloader.nim). - Automatyczne dual-boot jest już wykrywane przez
os-prober(diskutil.detectOtherOperatingSystems) i włączane wgrub-mkconfig(GRUB_DISABLE_OS_PROBER=false), ale samo montowanie/łączenie z konkretnymi wpisami menu innych systemów wciąż zostaje w gestii GRUB-a/os-probera, nie tego instalatora. - Interfejs instalatora (
i18n.nim) ma teraz PEŁNE tłumaczenia dla wszystkich 158 kluczy w 5 językach (pl/en/de/fr/es) -- 0 kluczy spadających na fallback angielski. Inne języki (np. rosyjski, chiński) nadal dostają angielski interfejs instalatora niezależnie od tego, jaki język wybrano dla instalowanego systemu. - Testy (
tests/) pokrywają czystą, bezstanową logikę (partitionPath,humanSize,parentDiskOf, walidatory,t()/setUiLanguage) ORAZ izolowane operacje plikowe w katalogach tymczasowych (writeFstab,parseAnswerFile) -- ale kod wykonujący REALNE operacje na dysku/partycjach/chroot (mount, mkfs, cryptsetup, grub-install) nadal nie ma automatycznych testów (wymagałby kontenera/VM z uprawnieniami roota i prawdziwym blokiem urządzeń do sensownego mockowania). - Rozmiar swapu (partycji albo pliku) jest teraz konfigurowalny w GUI
(
widgets.sizeStepper, krok 256 MiB) i w--server(cliapp.askInt) -- ale nadal krokowo/z ograniczonym zakresem (256 MiB-64 GiB), nie dowolna precyzyjna wartość wpisywana z klawiatury (patrz uzasadnienie w komentarzuwidgets.sizeStepper). - Przełącznik motywu (
widgets.applyTheme, ciemny/jasny) jest dostępny tylko na ekranie powitalnym GUI -- nie ma go w trybie--server(terminal ma własny motyw użytkownika, więc to naturalne), i nie jest zapamiętywany między uruchomieniami (zawsze startuje w motywie ciemnym).