Конфігурація як дані
Коли оновлення Arch у вівторок уранці потребує нового обхідного рішення для певного iGPU від Intel, — що робить традиційний інсталятор? Нічого, доки хтось не внесе латку в сценарій bash, який ним керує, не випустить новий ISO-образ (1—3 ГБ) і не дочекається, поки користувачі його завантажать. У кращому разі на це йдуть дні, частіше — тижні.
Ditana використовує принципово інший підхід: конфігурація як дані.
Три окремі частини
Розділ «Три окремі частини»Архітектуру Ditana розділено на три сховища:
-
Рушій (
ditana-installer) — невелика універсальна програма, яка знає, як малювати діалогові вікна, розбивати диски на розділи, виявляти обладнання й запускатиpacstrap. -
База знань (
ditana-config) — структурована база даних, написана мовою KDL v2. Вона оголошує кожне налаштування, кожну особливість обладнання, кожну залежність пакунків, кожен сценарій життєвого циклу та логічні зв’язки між ними. -
Конвеєр пакунків (
ditana-build) — те, що збирає пакунки, названі в базі знань. Сховище Ditana спирається на сховище Arch, а рецепти в ньому цей конвеєр перезбирає з вихідного коду, перевіряє й підписує, а не бере такими, як вони є.
Коли ви завантажуєтеся з ISO-образу Ditana, рушій підключається до GitHub і отримує найновіший випуск бази знань (а якщо підключення до інтернету немає, як резервний варіант використовує офлайн-знімок, вбудований в ISO-образ).
Варто знати й те, чого не охоплює отримання під час роботи. Сам рушій і конвертер, яким він читає KDL, містяться на носії й змінюються лише з новим носієм. А цей канал так само легко доставляє помилку, як і виправлення: конфігурація, у якій названо пакунок, якого не може надати сховище старішого носія, унеможливлює встановлення з цього носія, — саме це й сталося, коли у вересні 2026 року Arch вилучив bubblewrap-suid.
Чому це важливо
Розділ «Чому це важливо»Три переваги, упорядковані за безпосередністю впливу:
- Оновлення без перевипуску ISO-образу. Якщо користувач повідомляє, що недавнє оновлення Arch потребує нового обхідного рішення, виправлення потрапляє в
ditana-configяк невелика правка KDL. Уже наступна людина, яка завантажиться з ISO-образу Ditana, автоматично отримає оновлену логіку. Виправлення одразу доходить до користувачів, і нікому не потрібно завантажувати новий ISO-образ. - Прозоре обґрунтування. Оскільки налаштування оголошено як структуровані дані з явними умовами, правила можна перевірити від початку до кінця. Будь-хто може прочитати файли KDL і точно побачити, чому встановлюється пакунок, яка комбінація налаштувань спричиняє розгортання файлу конфігурації або яка властивість обладнання визначає доступність параметра. Жодної детективної роботи в bash.
- Внески через відгалуження. Додавання обхідного рішення для обладнання, нового підлаштування стільничного середовища чи нового рішення щодо пакунків зазвичай зводиться до зміни одного файлу KDL. Жодних змін у рушії інсталятора — а поза детекторами обладнання, які є однорядковими виразами Raku, узагалі жодного Raku. README сховища
ditana-configдокладно знайомить учасників зі схемою; більшість запитів на внесення змін (pull request) стосується одного файлу.
Чому KDL, а не JSON чи YAML
Розділ «Чому KDL, а не JSON чи YAML»База знань могла мати будь-який структурований формат. KDL вибрано тому, що він має властивості, яких справді потребує конфігурація Ditana:
- Вбудовані коментарі. І YAML, і JSON тут мають труднощі — YAML підтримує коментарі, але їх підтримка в інструментах нерівномірна; у JSON коментарів немає взагалі. Налаштування Ditana містять розлогі коментарі з обґрунтуванням, які пояснюють, чому типове значення саме таке. Саме в цих коментарях і суть.
- Необроблені рядки. Вбудовані фрагменти коду оболонки, вирази sed і шаблони регулярних виразів — повноцінні елементи. Жодного подвійного екранування
"і\заради синтаксичного аналізатора. - Ієрархічність без церемоній. Дочірні вузли, властивості й аргументи без проблем співіснують. Той самий вузол може описувати налаштування та містити вкладені вузли для його пакунків, сценаріїв і файлів.
- Зручний для порівняння змін. Порядок вставлення зберігається. Під час перевірки коду додавання одного рядка дає diff в один рядок, а не структуру зі зміненим порядком.
Формат розбирає невеликий конвертер на Rust (json-kdl-converter, версії якого теж ведуться разом зі схемою), перш ніж інсталятор на Raku отримає його у вигляді JSON. У наступному розділі пояснено, як дані перевіряються від початку до кінця ще до всього цього.
Як це виглядає на практиці
Розділ «Як це виглядає на практиці»Повне робоче налаштування в ditana-config виглядає так:
// XFCE fallback for Wayland-only primary terminals (foot, cosmic-term).// Fires when the user picks a Wayland-native terminal AND also installs// XFCE. Writes to xfce-xdg-terminals.list only; xdg-terminals.list still// points at the primary terminal for Wayland sessions.- name="fallback-kitty-for-xfce" \ default-value="`(install-foot OR install-cosmic-term) AND install-xfce`" { arch-packages "kitty" \ "imagemagick" \ "python-pygments" \ "libcanberra" \ "xdg-terminal-exec-git" files "/etc/xdg/kitty/kitty.conf" \ "/usr/share/pixmaps/ditana-logo-tiny.png" chroot-script "mkdir -p /etc/xdg" \ "echo kitty.desktop >/etc/xdg/xfce-xdg-terminals.list"}Цей вузол оголошує похідне налаштування без власного діалогового вікна, логічний вираз над трьома іншими налаштуваннями, пакунки, які слід встановити, коли вираз істинний, і файл, завдяки якому XFCE їх використовує. Обґрунтування стоїть поруч із правилом, де людина, яка його перевіряє, може побачити, чому воно таке. Повна документація схеми — у README сховища ditana-config.
Така сама форма описує й речі, які зовсім не є пакунками. Програма, якій для пісочниці потрібен непривілейований простір назв користувача (user namespace), зазначає це поруч із собою:
- name="flatpak" default-value=#true { arch-packages "flatpak" // Every Flatpak, not only the browsers, runs bwrap to build its outer // sandbox, and bwrap needs a user namespace. This is the declaration // that buys it one. userns-allow "/usr/bin/bwrap" }Ditana не надає непривілейовані простори назв користувача кожній програмі. Мінімальна програма BPF, ditana-userns-guard, під’єднується до власного хука ядра userns_create і відмовляє в просторі назв будь-якому виконуваному файлу, для якого його не запитало жодне налаштування. Хук такого типу може лише відмовити й ніколи не може надати дозвіл, тому заборону просторів назв через sysctl знімають лише після того, як програму завантажено, — комп’ютер, який не може її завантажити, залишає їх повністю вимкненими. Це типовий стан одного з параметрів розділу System Hardening; вимкніть його — і простори назв стануть відкритими для всього, як у більшості дистрибутивів.
Ditana відмовляє в просторах назв користувача всьому, що їх не запитувало. Працездатним це робить те, що запит локальний: його записано там, де вибирається пакунок, тож ніщо не мусить вести синхронізований центральний список, а з вимкненням налаштування зникає і дозвіл. Інсталятор збирає оголошення тих налаштувань, що зрештою залишаються ввімкненими, і генерує з них список дозволених виконуваних файлів.
Перевірка: виявлення помилок до публікації
Розділ «Перевірка: виявлення помилок до публікації»Така велика база знань потребує запобіжників. Для кожного коміту — і локально через хуки pre-commit, і віддалено в GitHub Actions — запускається багаторівневий конвеєр перевірок, який виявляє помилки, що їх може пропустити людина під час перевірки:
- Синтаксис KDL (
kdlfmt) — файл узагалі вдається розібрати. - Перевірка за схемою (
ditana-schema.json) — кожне поле має правильний тип, немає невідомих властивостей і не бракує обов’язкових полів. Виявляє друкарські помилки в назвах полів, як-отarc-packagesзамістьarch-packages. - Цілісність посилань на файли — кожен файл, на який посилається налаштування, справді існує в
folders/; і навпаки, на кожен файл уfolders/посилається щонайменше одне налаштування. Покинуті файли позначаються. Посилання на каталоги (які мовчки нічого б не робили, бо інсталятор використовуєcpбез-R) відхиляються. - Коректність життєвого циклу — рядки
chroot-script, що звертаються до/etc/skel/, відхиляються, бо користувача створюють після виконанняchroot-script, — правильним полем єearly-chroot-script. Це тонка помилка, яка інакше дала б систему, де в домашньому каталозі нового користувача немає очікуваних файлів. - Коректність сценаріїв оболонки — кожен фрагмент коду оболонки в будь-якому з полів зі списками сценаріїв перевіряється за допомогою
bash -nна синтаксис іshellcheckна якість. Пропущена лапка чи помилка на кшталт[ "$x" = $y ]виявляється під час коміту, а не під час першого встановлення. - Оголошені дозволи й параметри ядра — запис
userns-allowмає бути абсолютним шляхом, а записsysctlмає називати справжній ключ sysctl і надавати йому значення, яке ядро прийме. Обидва поля додано в 0.9.4, і їх оголошено вditana-schema.json. - Суперечливі параметри ядра — два налаштування, що записують той самий ключ sysctl з різними значеннями, зупиняють встановлення, і в повідомленні названо обидва. Коли все збиралося як текст оболонки, як це було до 0.9.4, просто перемагав останній записаний рядок, і ніхто про це не дізнавався.
- Цілісність логічних виразів — зворотні апострофи мають бути парними; кожна назва налаштування, на яку посилається вираз
default-valueчиavailable, має справді існувати десь у базі знань. Друкарська помилка на кшталтinstall-cosmikзамістьinstall-cosmicвиявляється під час коміту, а не спричиняє непомітний збій під час роботи.
Повна перевірка локально за допомогою pre-commit run --all-files триває лічені секунди й повторюється під час кожного надсилання змін на GitHub. Якщо локально все зелене, то й у CI все зелене; зламані коміти ніколи не потрапляють у випуск.
Що далі
Розділ «Що далі»- Прочитайте, як налаштування залежать одне від одного, — саме в
availableіdefault-valueзосереджена логіка бази знань. - Перегляньте сховище
ditana-config, щоб побачити, як правила впорядковано за діалоговими вікнами й темами. - Прочитайте README сховища
ditana-config, щоб ознайомитися з моделлю даних: як пов’язані між собою налаштування, сценарії, діалогові вікна й файли. - Перегляньте вихідний код
ditana-installer, якщо хочете побачити рушій, який читає конфігурацію й діє відповідно до неї.
Це машинний переклад. Читачі вдосконалюють його на Weblate.