Compare commits

..
4 Commits
Author SHA1 Message Date
dasandClaude Opus 5.5 f3793d468c Incremental package builds and releases on v* tags (0.8.0)
build / build (push) Successful in 30m42s
- build-packages.sh rebuilds a package only when its srcpkgs/ directory
  changed, its binary package is missing, or a dry-run install finds a
  shared library Void no longer provides; DASOS_REBUILD=1 rebuilds all.
  An unchanged `make packages` takes 20 s instead of 17 min on the CI host
- ci/release.sh publishes both ISOs and SHA256SUMS as a Gitea release
  when the workflow runs for a v* tag matching VERSION
- README and TODO updated

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 14:55:45 +03:00
dasandClaude Opus 5.5 dbfb104d89 TODO: stage 9 verified in Gitea and across a reboot
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 13:15:25 +03:00
dasandClaude Opus 5.5 125f9027c4 Stage 9: CI build on a self-hosted Gitea runner (0.7.0)
build / build (push) Successful in 45m41s
- .gitea/workflows/build.yml builds the packages and both ISOs with
  `make iso iso-server` on pushes to main and dev, v* tags and on demand
- ci/runner: setup of the CI host (WSL2 Ubuntu 24.04 with Docker Engine
  and gitea-runner as a systemd service, autostart task for Windows)
- scripts/builder.sh: DASOS_OUT keeps out/ outside the checkout, so CI
  reuses void-packages, the masterdir and the download cache
- README and TODO updated

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 12:27:00 +03:00
dasandClaude Opus 5.5 fe043711a0 Stage 8: developer profile with dprofile (0.6.0)
dprofile (das-helpers 0.2.0) installs profiles listed in
/usr/share/das/profiles: packages from the Void repository between a
snapper pre/post pair, their services and groups, subordinate IDs and a
shared root mount for rootless Podman, and optional IDEs from Flathub.
The installed system can't see the Das OS repository yet, so a das-dev
metapackage could not be installed there; Void packages always can.

The dev profile: Go, Python, Node.js, Git, Docker, Podman and command-line
tools everywhere, VS Code (code-oss), Meld and Flatpak on a desktop, with
Android Studio and JetBrains IDEs on demand. Questions come before sudo.

das-welcome (das-tools 0.4.0) gets a developer profile row that runs
dprofile in a terminal; das-server-install mentions it at the end.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 08:49:53 +03:00
22 changed files with 829 additions and 29 deletions
+39
View File
@@ -0,0 +1,39 @@
# Builds the Das OS packages and both ISO images on the CI host (see ci/runner).
# Build output stays on the host in DASOS_OUT, set in the runner's config.
# A v* tag also publishes the images as a release (ci/release.sh).
name: build
on:
push:
branches: [main, dev]
tags: ["v*"]
workflow_dispatch:
concurrency:
group: build-${{ gitea.ref }}
cancel-in-progress: true
jobs:
build:
runs-on: dasci
permissions:
contents: write # ci/release.sh creates releases
steps:
- uses: builtin:checkout
# One make run builds the packages once for both images.
# Go tests run inside the das-tools and das-theme package builds.
- name: Packages and ISO images
run: make iso iso-server
- name: Result
run: ls -lh "$DASOS_OUT/iso/"*-"$(cat VERSION)"-x86_64.iso
# A v* tag publishes both images and their checksums as a release
- name: Release
if: startsWith(gitea.ref, 'refs/tags/v')
env:
GITEA_TOKEN: ${{ gitea.token }}
GITEA_SERVER_URL: ${{ gitea.server_url }}
GITEA_REPOSITORY: ${{ gitea.repository }}
run: ci/release.sh "${{ gitea.ref_name }}" "$DASOS_OUT/iso"
+1 -1
View File
@@ -40,5 +40,5 @@ test:
# Build output may be owned by root when a build was interrupted, so remove it from the container
clean:
scripts/builder.sh rm -rf /work/out/hostdir/binpkgs /work/out/iso
scripts/builder.sh rm -rf /work/out/hostdir/binpkgs /work/out/hostdir/stamps /work/out/iso
rm -rf out/qemu
+25 -4
View File
@@ -1,7 +1,7 @@
## Das OS
### _A light, friendly Void Linux–based desktop with Xfce and a Ukrainian touch, plus a console server edition_
[![Void Linux](https://img.shields.io/badge/Void_Linux-x86__64_glibc-green)](https://voidlinux.org) [![Xfce](https://img.shields.io/badge/Xfce-4.20-orange)](https://xfce.org) [![runit](https://img.shields.io/badge/init-runit-blue)](https://docs.voidlinux.org/config/services/) [![Go](https://img.shields.io/badge/Go-1.24+-blue)](https://go.dev) [![Docker](https://img.shields.io/badge/Docker-29-blue)](https://www.docker.com) [![Version](https://img.shields.io/badge/version-0.5.0-lightgrey)](#)
[![Void Linux](https://img.shields.io/badge/Void_Linux-x86__64_glibc-green)](https://voidlinux.org) [![Xfce](https://img.shields.io/badge/Xfce-4.20-orange)](https://xfce.org) [![runit](https://img.shields.io/badge/init-runit-blue)](https://docs.voidlinux.org/config/services/) [![Go](https://img.shields.io/badge/Go-1.24+-blue)](https://go.dev) [![Docker](https://img.shields.io/badge/Docker-29-blue)](https://www.docker.com) [![Version](https://img.shields.io/badge/version-0.8.0-lightgrey)](#)
🇺🇦 [Українська версія](README_ua.md)
@@ -13,13 +13,15 @@ Void Linux is fast, simple and independent: runit instead of systemd, and its ow
- [Graphical installer](#Installer) (Calamares) set up for Void and runit
- [Snapshots and rollback](#Snapshots): hourly Btrfs snapshots, bootable from the GRUB menu
- [System update](#Update) with a snapshot taken before it: a window, a tray icon and a terminal mode
- [Welcome window](#Welcome) at the first login: language, home folders, updates and help
- [Welcome window](#Welcome) at the first login: language, home folders, updates, the developer profile and help
- [Server image](#Server): a console live ISO with a text installer, SSH, firewall, fail2ban and Docker
- [Command-line helpers](#Helpers) for everyday admin tasks: services (`dsv`), users (`duser`), firewall (`dfw`) and system settings (`dsys`)
- [Developer profile](#DevProfile) in one command: Go, Python, Node.js, Docker, rootless Podman, VS Code and IDEs from Flathub
- [Das OS look](#Look): light and dark themes, generated window frames, wallpapers and logo
- [Desktop defaults](#Defaults) for Xfce that don't overwrite stock files
- [Own package repository](#Repository) built by xbps-src from in-tree templates
- [Containerised build](#Build) that runs on any Linux host with Docker, and QEMU scripts for testing
- [CI build](#CI) of the packages and both ISOs on every push, on a self-hosted Gitea Actions runner
### ⭐ Advantages
- **Void underneath** – a fast runit boot, the xbps package manager and fresh software, with none of the manual setup.
@@ -119,6 +121,7 @@ Void Linux is fast, simple and independent: runit instead of systemd, and its ow
- In the live session it offers to install Das OS.
- The interface language can be chosen when the system has more than one locale built. It is stored in AccountsService and `~/.dmrc` and takes effect at the next login.
- If the home folders still have English names (`Documents`, `Downloads`…), it offers to rename them to the system language, together with `user-dirs.dirs` and the file manager bookmarks. Folders the user moved, and those whose new name is already taken, are left alone.
- It installs the [developer profile](#DevProfile) in a terminal window, where the IDEs and the password are asked for, and once the profile is installed, adds IDEs from Flathub.
- It links to the system update, Xfce settings and help.
- It opens by itself only once. The *Show at login* check box keeps it opening at every login.
@@ -143,6 +146,15 @@ Void Linux is fast, simple and independent: runit instead of systemd, and its ow
- `dsys` replaces hostnamectl, timedatectl and localectl: `info` (time sync, language, console, addresses), `hostname`, `timezone` (part of the name will do: `dsys timezone Kyiv`), `locale` (builds the glibc locale if needed) and `keymap` (with a Cyrillic console font for Cyrillic layouts).
- They come in the `das-helpers` package and are on the desktop too. Both images also include `xtools-minimal` from Void for package work: `xi` installs, `xrs` searches, `xq` shows package details and `xcheckrestart` finds programs to restart after an update.
#### Developer profile<a id='DevProfile' />
**_`dprofile install dev` turns a desktop or a server into a development machine, with a snapshot taken before it._**
- Packages from the Void repository: `base-devel`, gdb, strace, Git with LFS, GitHub CLI, lazygit, Go with gopls, delve and golangci-lint, Python with pip, virtualenv and uv, Node.js, Docker with Compose and Buildx, lazydocker, Podman with podman-compose, jq, ripgrep, fd, fzf, direnv, shellcheck and SQLite.
- On a desktop also VS Code (Void's open-source build `code-oss`, extensions come from Open VSX), Meld, Flatpak with the Flathub remote and the desktop portals.
- It enables Docker and adds the user who runs it to the `docker` group, gives them subordinate IDs for rootless Podman and makes `/` a shared mount at every boot (`/etc/runit/core-services/60-das-shared-root.sh`), which rootless containers need.
- Before installing, it asks which IDEs to add from Flathub: Android Studio, IntelliJ IDEA Open and Ultimate, PyCharm, GoLand, WebStorm or Microsoft's Visual Studio Code. Later they are added with `dprofile app add GoLand` and removed with `dprofile app rm`, which also removes the Flatpak runtimes nothing else uses.
- The packages are installed between a snapper pre/post snapshot pair, like with `das-update`, and the command prints how to roll back. `dprofile list` and `dprofile show dev` show what is installed already; `--yes` and `--apps ID,...|all|none` make it work without questions.
- The profile is a plain list in `/usr/share/das/profiles/dev.conf`. The desktop installer doesn't offer it because the installation copies the live image without a network, and the profile downloads about 550 MB of packages (an IDE from Flathub takes 1–4 GB more with its runtimes).
#### Das OS look<a id='Look' />
**_A modern minimal style with a blue and yellow eight-petal star from Ukrainian embroidery._**
- The GTK themes `DasOS` and `DasOS-Dark` build on adw-gtk3 and add the Das OS accent colours. They also style the Xfce panel, which adw-gtk3 leaves black.
@@ -165,9 +177,10 @@ Void Linux is fast, simple and independent: runit instead of systemd, and its ow
- `srcpkgs/das-tools` contains `das-welcome` and the update window and tray icon (Go, GTK 3 through gotk3) with their menu and autostart entries. Its subpackage `das-update` is the update command and polkit action, without GTK.
- `srcpkgs/das-snapshots` contains the snapper configuration, `das-snapper-setup` and the dracut module for booting snapshots.
- `srcpkgs/das-installer` contains the Calamares settings and branding, `srcpkgs/das-server-installer` the console installer. The steps both share (`mount-source`, `postinstall`) are in `srcpkgs/das-install-common`. They exist only on the live ISOs.
- `srcpkgs/das-server` is the server metapackage with the nftables, fail2ban, sshd and Docker defaults. `srcpkgs/das-helpers` contains `dsv`, `duser`, `dfw` and `dsys`.
- `srcpkgs/das-server` is the server metapackage with the nftables, fail2ban, sshd and Docker defaults. `srcpkgs/das-helpers` contains `dsv`, `duser`, `dfw`, `dsys`, `dprofile` and the profiles.
- `srcpkgs/calamares`, `srcpkgs/adw-gtk3` and `srcpkgs/font-jetbrains-mono` package upstream releases that Void does not have.
- `make packages` lays the templates over a shallow clone of void-packages and builds them with `xbps-src` into `out/hostdir/binpkgs`. The ISO build installs them from there.
- A package is rebuilt only when its directory in `srcpkgs/` changed, its binary package is missing, or Void no longer provides a shared library it links to (checked with a dry-run install). `DASOS_REBUILD=1 make packages` rebuilds everything.
#### Containerised build<a id='Build' />
**_The whole build runs in a Docker container, so only Docker and QEMU are needed on the host._**
@@ -175,6 +188,14 @@ Void Linux is fast, simple and independent: runit instead of systemd, and its ow
2. `make iso` builds the packages and then the ISO with `void-mklive`, using the profile in `live/` (package list, services, root file system overlay). `make iso-server` does the same for the server profile in `server/`.
3. `make qemu` boots the newest ISO with UEFI. `make qemu-bios` uses legacy BIOS, and `make qemu-disk` also attaches a 20 GB virtual disk to install on. `make qemu-server` boots the server ISO with the disk on a serial console in the terminal (Ctrl-A X quits).
#### CI build<a id='CI' />
**_Every push to `main` or `dev` and every `v*` tag builds the packages and both ISOs on git.das.org.ua._**
- The workflow `.gitea/workflows/build.yml` runs `make iso iso-server` on a self-hosted runner with the `dasci` label.
- The runner is a WSL2 distro on a Windows machine: Ubuntu 24.04 with Docker Engine and `gitea-runner` as a systemd service. A scheduled task starts it when Windows boots, no login needed.
- `ci/runner/setup.sh` installs Docker, the runner and its `config.yaml`; `setup.sh register <token>` registers it, `autostart.ps1` creates the scheduled task.
- `DASOS_OUT` moves `out/` out of the checkout, so void-packages, the bootstrapped masterdir and the download cache survive between builds.
- A `v*` tag that matches `VERSION` also publishes both ISOs and `SHA256SUMS` as a release (`ci/release.sh`, with the job's own token): `git tag v0.8.0 && git push origin v0.8.0`. Other builds keep the ISOs on the CI host in `/var/lib/dasos-ci/out/iso`.
### 🚀 Building the application
Requirements: Linux with Docker (the user must be in the `docker` group), QEMU and OVMF for testing, and Go 1.24+ with the GTK 3 development files for `make test`. About 10 GB of free disk space.
```shell
@@ -187,6 +208,6 @@ make clean # remove build output, keep the download cache
```
The ISOs appear in `out/iso/dasos-<version>-x86_64.iso` and `out/iso/dasos-server-<version>-x86_64.iso`. Write them to a USB stick with `dd` or Ventoy.
**Note:** Das OS is an early version (0.5.0). The developer profile and signed repository hosting are planned for upcoming stages. Until the repository is hosted, an installed system gets updates from Void only. Das OS is based on Void Linux but is not affiliated with it.
**Note:** Das OS is an early version (0.8.0). Packages and ISOs are built in CI; signed repository hosting is planned for an upcoming stage. Until the repository is hosted, an installed system gets updates from Void only. Das OS is based on Void Linux but is not affiliated with it.
###### _Made by -=:dAs:=-_
+25 -4
View File
@@ -1,7 +1,7 @@
## Das OS
### _Легкий і дружній десктоп на базі Void Linux з Xfce та українським колоритом, а також консольна серверна версія_
[![Void Linux](https://img.shields.io/badge/Void_Linux-x86__64_glibc-green)](https://voidlinux.org) [![Xfce](https://img.shields.io/badge/Xfce-4.20-orange)](https://xfce.org) [![runit](https://img.shields.io/badge/init-runit-blue)](https://docs.voidlinux.org/config/services/) [![Go](https://img.shields.io/badge/Go-1.24+-blue)](https://go.dev) [![Docker](https://img.shields.io/badge/Docker-29-blue)](https://www.docker.com) [![Version](https://img.shields.io/badge/version-0.5.0-lightgrey)](#)
[![Void Linux](https://img.shields.io/badge/Void_Linux-x86__64_glibc-green)](https://voidlinux.org) [![Xfce](https://img.shields.io/badge/Xfce-4.20-orange)](https://xfce.org) [![runit](https://img.shields.io/badge/init-runit-blue)](https://docs.voidlinux.org/config/services/) [![Go](https://img.shields.io/badge/Go-1.24+-blue)](https://go.dev) [![Docker](https://img.shields.io/badge/Docker-29-blue)](https://www.docker.com) [![Version](https://img.shields.io/badge/version-0.8.0-lightgrey)](#)
🇬🇧 [English version](README.md)
@@ -13,13 +13,15 @@ Void Linux швидкий, простий і незалежний: runit зам
- [Графічний інсталятор](#Installer) Calamares, налаштований під Void і runit
- [Знімки й відкат](#Snapshots): щогодинні знімки Btrfs, які можна завантажити з меню GRUB
- [Оновлення системи](#Update) зі знімком перед ним: вікно, значок у треї та консольний режим
- [Вікно привітання](#Welcome) під час першого входу: мова, теки, оновлення та довідка
- [Вікно привітання](#Welcome) під час першого входу: мова, теки, оновлення, профіль розробника та довідка
- [Серверний образ](#Server): консольний live ISO з текстовим інсталятором, SSH, файрволом, fail2ban і Docker
- [Консольні помічники](#Helpers) для щоденного адміністрування: служби (`dsv`), користувачі (`duser`), брандмауер (`dfw`) і системні налаштування (`dsys`)
- [Профіль розробника](#DevProfile) однією командою: Go, Python, Node.js, Docker, rootless Podman, VS Code і середовища з Flathub
- [Оформлення Das OS](#Look): світла й темна теми, згенеровані рамки вікон, шпалери та логотип
- [Налаштування за замовчуванням](#Defaults) для Xfce, які не перезаписують стандартні файли
- [Власний репозиторій пакетів](#Repository), який xbps-src збирає з шаблонів у дереві проєкту
- [Збирання в контейнері](#Build), яке працює на будь-якому Linux із Docker, і скрипти QEMU для тестування
- [Збирання в CI](#CI) пакетів і обох ISO після кожного push на власному runner Gitea Actions
### ⭐ Переваги
- **Void усередині** – швидке завантаження з runit, менеджер пакетів xbps і свіжі програми без ручного налаштування.
@@ -119,6 +121,7 @@ Void Linux швидкий, простий і незалежний: runit зам
- У live-сесії пропонує встановити Das OS.
- Мову інтерфейсу можна вибрати, якщо в системі зібрано більше однієї локалі. Вона зберігається в AccountsService і `~/.dmrc` і діє з наступного входу.
- Якщо теки домашнього каталогу лишилися з англійськими назвами (`Documents`, `Downloads`…), пропонує перейменувати їх мовою системи разом із `user-dirs.dirs` і закладками файлового менеджера. Теки, які користувач переніс, і ті, чия нова назва вже зайнята, не чіпає.
- Встановлює [профіль розробника](#DevProfile) у вікні термінала, де питає про середовища й пароль, а коли профіль встановлено, додає середовища з Flathub.
- Містить посилання на оновлення системи, налаштування Xfce і довідку.
- Сам відкривається лише один раз. Прапорець *Показувати під час входу* залишає його на кожен вхід.
@@ -143,6 +146,15 @@ Void Linux швидкий, простий і незалежний: runit зам
- `dsys` замінює hostnamectl, timedatectl і localectl: `info` (синхронізація часу, мова, консоль, адреси), `hostname`, `timezone` (досить частини назви: `dsys timezone Kyiv`), `locale` (збирає локаль glibc, якщо треба) і `keymap` (з кириличним шрифтом консолі для кириличних розкладок).
- Вони входять у пакет `das-helpers` і є й на десктопі. Обидва образи також містять `xtools-minimal` з Void для роботи з пакетами: `xi` встановлює, `xrs` шукає, `xq` показує відомості про пакет, а `xcheckrestart` знаходить програми, які треба перезапустити після оновлення.
#### Профіль розробника<a id='DevProfile' />
**_`dprofile install dev` перетворює десктоп чи сервер на машину для розробки, перед цим створивши знімок системи._**
- Пакети з репозиторію Void: `base-devel`, gdb, strace, Git з LFS, GitHub CLI, lazygit, Go з gopls, delve і golangci-lint, Python з pip, virtualenv і uv, Node.js, Docker з Compose і Buildx, lazydocker, Podman з podman-compose, jq, ripgrep, fd, fzf, direnv, shellcheck і SQLite.
- На десктопі ще VS Code (відкрита збірка Void `code-oss`, розширення з Open VSX), Meld, Flatpak з репозиторієм Flathub і порталами робочого столу.
- Вмикає Docker і додає користувача, який його запустив, до групи `docker`, дає йому підлеглі ідентифікатори для rootless Podman і під час кожного завантаження робить `/` спільним монтуванням (`/etc/runit/core-services/60-das-shared-root.sh`), без чого rootless-контейнери працюють з попередженнями.
- Перед встановленням питає, які середовища додати з Flathub: Android Studio, IntelliJ IDEA Open та Ultimate, PyCharm, GoLand, WebStorm чи Visual Studio Code від Microsoft. Пізніше їх додає `dprofile app add GoLand`, а видаляє `dprofile app rm`, разом із рантаймами Flatpak, які більше нічому не потрібні.
- Пакети встановлюються між парою знімків snapper pre/post, як і в `das-update`, а наприкінці команда підказує, як відкотитися. `dprofile list` і `dprofile show dev` показують, що вже встановлено; з `--yes` і `--apps ID,...|all|none` команда працює без запитань.
- Профіль — звичайний список у `/usr/share/das/profiles/dev.conf`. Десктопний інсталятор його не пропонує: встановлення копіює live-образ без мережі, а профіль завантажує близько 550 МБ пакетів (середовище з Flathub разом із рантаймами — ще 1–4 ГБ).
#### Оформлення Das OS<a id='Look' />
**_Сучасний мінімалізм із синьо-жовтою восьмипелюстковою зіркою з української вишивки._**
- GTK-теми `DasOS` і `DasOS-Dark` побудовані на adw-gtk3 і додають акцентні кольори Das OS. Вони також оформлюють панель Xfce, яку adw-gtk3 лишає чорною.
@@ -165,9 +177,10 @@ Void Linux швидкий, простий і незалежний: runit зам
- `srcpkgs/das-tools` містить `das-welcome`, вікно оновлення і значок у треї (Go, GTK 3 через gotk3) з пунктами меню й автозапуском. Його підпакет `das-update` — сама команда оновлення й дія polkit, без GTK.
- `srcpkgs/das-snapshots` містить конфігурацію snapper, `das-snapper-setup` і dracut-модуль для завантаження знімків.
- `srcpkgs/das-installer` містить налаштування й брендинг Calamares, `srcpkgs/das-server-installer` — консольний інсталятор. Спільні для обох кроки (`mount-source`, `postinstall`) лежать у `srcpkgs/das-install-common`. Вони є лише на live-ISO.
- `srcpkgs/das-server` — серверний метапакет із налаштуваннями nftables, fail2ban, sshd і Docker. `srcpkgs/das-helpers` містить `dsv`, `duser`, `dfw` і `dsys`.
- `srcpkgs/das-server` — серверний метапакет із налаштуваннями nftables, fail2ban, sshd і Docker. `srcpkgs/das-helpers` містить `dsv`, `duser`, `dfw`, `dsys`, `dprofile` і профілі.
- `srcpkgs/calamares`, `srcpkgs/adw-gtk3` і `srcpkgs/font-jetbrains-mono` пакують релізи, яких немає у Void.
- `make packages` накладає шаблони на неглибокий клон void-packages і збирає їх через `xbps-src` в `out/hostdir/binpkgs`. Збирання ISO встановлює їх звідти.
- Пакет перезбирається, лише коли змінився його каталог у `srcpkgs/`, зник бінарний пакет або Void більше не надає бібліотеку, з якою він зібраний (перевіряється пробним встановленням). `DASOS_REBUILD=1 make packages` перезбирає все.
#### Збирання в контейнері<a id='Build' />
**_Усе збирання відбувається в Docker-контейнері, тож на хості потрібні лише Docker і QEMU._**
@@ -175,6 +188,14 @@ Void Linux швидкий, простий і незалежний: runit зам
2. `make iso` збирає пакети, а потім ISO через `void-mklive` за профілем у `live/` (список пакетів, сервіси, оверлей кореневої файлової системи). `make iso-server` робить те саме для серверного профілю в `server/`.
3. `make qemu` завантажує найновіший ISO з UEFI. `make qemu-bios` використовує старий BIOS, а `make qemu-disk` ще й підключає віртуальний диск на 20 ГБ для встановлення. `make qemu-server` завантажує серверний ISO з диском на послідовній консолі прямо в терміналі (вихід — Ctrl-A X).
#### Збирання в CI<a id='CI' />
**_Кожен push у `main` чи `dev` і кожен тег `v*` збирає пакети й обидва ISO на git.das.org.ua._**
- Workflow `.gitea/workflows/build.yml` запускає `make iso iso-server` на власному runner з міткою `dasci`.
- Runner — дистрибутив WSL2 на Windows-машині: Ubuntu 24.04 з Docker Engine і `gitea-runner` як службою systemd. Завдання планувальника запускає його під час завантаження Windows, вхід у систему не потрібен.
- `ci/runner/setup.sh` встановлює Docker, runner і його `config.yaml`; `setup.sh register <токен>` реєструє його, `autostart.ps1` створює завдання планувальника.
- `DASOS_OUT` виносить `out/` за межі робочої копії, тож void-packages, підготовлений masterdir і кеш завантажень зберігаються між збираннями.
- Тег `v*`, що збігається з `VERSION`, ще й публікує обидва ISO та `SHA256SUMS` як реліз (`ci/release.sh`, з власним токеном завдання): `git tag v0.8.0 && git push origin v0.8.0`. Інші збирання залишають ISO на CI-хості в `/var/lib/dasos-ci/out/iso`.
### 🚀 Збирання застосунку
Вимоги: Linux із Docker (користувач має бути в групі `docker`), QEMU та OVMF для тестування, Go 1.24+ і файли розробки GTK 3 для `make test`. Приблизно 10 ГБ вільного місця.
```shell
@@ -187,6 +208,6 @@ make clean # видалити результати збиранн
```
ISO з'являються в `out/iso/dasos-<версія>-x86_64.iso` і `out/iso/dasos-server-<версія>-x86_64.iso`. Записати їх на флешку можна через `dd` або Ventoy.
**Примітка:** Das OS — рання версія (0.5.0). Профіль розробника та підписаний репозиторій на хостингу заплановані на наступні етапи. Поки репозиторій не розміщено на хостингу, встановлена система отримує оновлення лише з Void. Das OS базується на Void Linux, але не пов'язана з ним офіційно.
**Примітка:** Das OS — рання версія (0.8.0). Пакети й ISO збираються в CI; підписаний репозиторій на хостингу заплановано на наступний етап. Поки репозиторій не розміщено на хостингу, встановлена система отримує оновлення лише з Void. Das OS базується на Void Linux, але не пов'язана з ним офіційно.
###### _Made by -=:dAs:=-_
+21 -9
View File
@@ -1,6 +1,6 @@
# Das OS — що зробити далі
Стан на 2026-10-20: версія 0.5.0, етапи 1–7 готові (live ISO, власний репозиторій, оформлення, інсталятор Calamares зі знімками Btrfs, Go-утиліти `das-update` і `das-welcome`, серверний образ з консольним інсталятором, менші ISO, консольні помічники). Далі: профіль розробника (етап 8).
Стан на 2026-10-20: версія 0.8.0, етапи 1–8 готові (live ISO, власний репозиторій, оформлення, інсталятор Calamares зі знімками Btrfs, Go-утиліти `das-update` і `das-welcome`, серверний образ з консольним інсталятором, менші ISO, консольні помічники, профіль розробника), CI (етап 9: пакети й обидва ISO збираються на власному runner, ~45 хв).
## Етап 5. Go-утиліти (готово, лишилися перевірки)
- [x] `das-update`: вікно, значок у треї (лише коли є оновлення), консольний режим `--cli`, знімок snapper pre/post, встановлення через pkexec, підказка про відкат.
@@ -12,7 +12,7 @@
- [x] Live ISO 0.4.0: екран не блокується під час встановлення.
- [ ] Вікно автентифікації polkit (`xfce-polkit`) англійською: перекласти або замінити агент.
- [ ] Повідомити авторів xdg-user-dirs про помилку з `XDG_DATA_DIRS`.
- [ ] Пункт «Профіль розробника» в `das-welcome` (разом з етапом 8).
- [x] Пункт «Профіль розробника» в `das-welcome` (етап 8).
## Етап 6. Серверний образ (готово)
Live ISO без графіки з консольним інсталятором: `dasos-server-<версія>-x86_64.iso`.
@@ -49,13 +49,25 @@ Live ISO без графіки з консольним інсталятором:
- [x] Перевірено на встановленому сервері: `dsv new` з Python-сервером на 8080, доступ з хоста після `dfw allow` і закриття після `dfw deny`; `duser add` з ключем, вхід, `lock` блокує й вхід за ключем; `dsys` (часовий пояс, ім'я, мова, розкладка); `dfw reload` поруч із контейнером nginx.
- [x] Повідомлення наприкінці `das-server-install` згадує `dsv`, `duser`, `dfw`, `dsys`.
## Етап 8. Профіль розробника
- [ ] Метапакет `das-dev`: go, git, docker, podman, vscode.
- [ ] Android Studio та JetBrains на вимогу через Flatpak.
- [ ] Вибір профілю в інсталяторі (модуль packagechooser) або в `das-welcome`.
## Етап 8. Профіль розробника (готово)
Не метапакет, а `dprofile` у `das-helpers` зі списком пакетів Void у `/usr/share/das/profiles/dev.conf`: встановлена система поки не бачить репозиторію Das OS, тож метапакет `das-dev` звідти не встановився б, а пакети Void доступні завжди.
- [x] `dprofile install dev`: base-devel, gdb, strace, git, git-lfs, github-cli, lazygit, go, gopls, delve, golangci-lint, python3-pip, virtualenv, uv, nodejs, docker, docker-compose, docker-buildx, lazydocker, podman, podman-compose, jq, ripgrep, fd, fzf, direnv, shellcheck, sqlite; на десктопі ще vscode (`code-oss`), meld, flatpak і портали. Пара знімків snapper pre/post, підказка про відкат; спершу оновлює xbps, якщо треба.
- [x] Налаштування: служба docker, група `docker` для того, хто запустив, `/etc/subuid`/`subgid` для rootless Podman, `/` як спільне монтування (`/etc/runit/core-services/60-das-shared-root.sh`; runit лишає його приватним, і Podman попереджає).
- [x] Flathub на вимогу (лише десктоп): Android Studio, IntelliJ IDEA Open/Ultimate, PyCharm, GoLand, WebStorm, VS Code від Microsoft; вибір номерами перед встановленням, `dprofile app add|rm` (з `--unused`, бо рантайми займають 1–4 ГБ). PyCharm Community на Flathub застарів (2024.3), тому `PyCharm-Professional` (безкоштовний режим).
- [x] Запитання й план — до `sudo`, пароль питається після них; `--yes`, `--apps ID,...|all|none` для скриптів.
- [x] `das-welcome`: рядок «Профіль розробника» відкриває `xfce4-terminal` з `dprofile install dev`; після встановлення — «Додати середовища».
- [x] Calamares packagechooser не додаємо: інсталятор копіює live-образ без мережі, а профіль завантажує ≈ 550 МБ.
- [x] Перевірено: сервер (QEMU) — `go run`, Node.js, uv, `docker run`, rootless `podman run` без попередження після перезавантаження; десктоп — встановлення з `das-welcome`, Code - OSS і VS Code з Flathub у меню після входу, `dprofile app rm` звільняє рантайми.
- [x] Повідомлення наприкінці `das-server-install` згадує `dprofile install dev`.
## Етап 9. CI
- [ ] Збирання пакетів і обох ISO (десктоп і сервер) в контейнері Void (Gitea Actions на git.das.org.ua або GitHub Actions).
## Етап 9. CI (готово)
- [x] Workflow `.gitea/workflows/build.yml`: `make iso iso-server` на власному runner `dasci:host` (push у `main`/`dev`, теги `v*`, ручний запуск).
- [x] CI-хост: Windows-машина (192.168.88.193), WSL2 Ubuntu 24.04 `dasci` у `D:\DasOS\wsl`, Docker Engine, `gitea-runner` 5.1.1 як служба systemd, автозапуск завданням планувальника (`ci/runner`).
- [x] `DASOS_OUT` у `scripts/builder.sh`: кеш `out/` на CI-хості в `/var/lib/dasos-ci/out`.
- [x] Runner зареєстровано, перший запуск у Gitea (run 1) успішний за 46 хв.
- [x] Після перезавантаження Windows runner піднімається сам, без входу в систему (завдання S4U).
- [x] Тег `v*` публікує обидва ISO і `SHA256SUMS` як реліз Gitea (`ci/release.sh`). Ліміт вкладення релізу — 2 ГБ на файл (`[repository.release] FILE_MAX_SIZE`).
- [ ] Перевірити першу публікацію на справжньому тегу.
## Репозиторій пакетів
- [ ] Підпис через `xbps-rindex --sign`, ключ поза репозиторієм.
@@ -78,7 +90,7 @@ Live ISO без графіки з консольним інсталятором:
- [ ] Прибрати значки томів live-носія («Том 6,6 ГБ») з робочого столу live-сесії.
- [ ] Тема GRUB у встановленій системі (зараз стандартний чорний екран).
- [ ] Перевірити меню Whisker вручну.
- [ ] Прискорити `make packages`: не перезбирати Calamares, якщо його версія не змінилася.
- [x] Прискорити `make packages`: пакет перезбирається лише після змін у `srcpkgs/<назва>`, без бінарного пакета або коли у Void зникла потрібна йому бібліотека (`xbps-install -n`). `DASOS_REBUILD=1` перезбирає все.
## Відкладено
- [ ] ARM-образ для Raspberry Pi.
+1 -1
View File
@@ -1 +1 @@
0.5.0
0.8.0
Executable
+41
View File
@@ -0,0 +1,41 @@
#!/bin/sh
# Publishes the ISO images of the current version as a Gitea release:
# release.sh <tag> <iso dir>
# Needs GITEA_TOKEN, GITEA_SERVER_URL and GITEA_REPOSITORY (owner/name); in CI
# the job provides them. Running it again for the same tag replaces the files.
set -eu
tag=$1
dir=$2
version=$(cat VERSION)
[ "$tag" = "v$version" ] || { echo "release: tag $tag does not match VERSION $version" >&2; exit 1; }
api=$GITEA_SERVER_URL/api/v1/repos/$GITEA_REPOSITORY
auth="Authorization: token $GITEA_TOKEN"
json() { python3 -c "import json,sys; d=json.load(sys.stdin); $1"; }
isos="dasos-$version-x86_64.iso dasos-server-$version-x86_64.iso"
cd "$dir"
sha256sum $isos >SHA256SUMS
if ! id=$(curl -fsS -H "$auth" "$api/releases/tags/$tag" 2>/dev/null | json 'print(d["id"])' 2>/dev/null); then
id=$(curl -fsS -H "$auth" -H 'Content-Type: application/json' \
-d "{\"tag_name\":\"$tag\",\"name\":\"Das OS $version\",\"body\":\"Desktop and server live ISO images. Check them with sha256sum -c SHA256SUMS.\"}" \
"$api/releases" | json 'print(d["id"])')
echo "release: created $tag (id $id)"
fi
# Files left from an earlier run for this tag are replaced
curl -fsS -H "$auth" "$api/releases/$id/assets" |
json '[print(a["id"], a["name"]) for a in d]' |
while read -r asset name; do
case " $isos SHA256SUMS " in
*" $name "*) curl -fsS -X DELETE -H "$auth" "$api/releases/$id/assets/$asset" ;;
esac
done
for f in $isos SHA256SUMS; do
echo "release: uploading $f"
curl -fsS -o /dev/null -H "$auth" -F "attachment=@$f" "$api/releases/$id/assets?name=$f"
done
echo "release: $GITEA_SERVER_URL/$GITEA_REPOSITORY/releases/tag/$tag"
+12
View File
@@ -0,0 +1,12 @@
# Starts the dasci WSL distro (Docker and gitea-runner inside) when Windows
# boots, without anyone logging in. Run once in an elevated PowerShell.
# The task keeps a process attached so WSL never stops the distro as idle.
$wsl = 'C:\Program Files\WSL\wsl.exe'
$action = New-ScheduledTaskAction -Execute $wsl -Argument '-d dasci --exec /bin/sleep infinity'
$trigger = New-ScheduledTaskTrigger -AtStartup
$principal = New-ScheduledTaskPrincipal -UserId $env:USERNAME -LogonType S4U -RunLevel Highest
$settings = New-ScheduledTaskSettingsSet -ExecutionTimeLimit 0 -AllowStartIfOnBatteries `
-DontStopIfGoingOnBatteries -RestartCount 999 -RestartInterval (New-TimeSpan -Minutes 1)
Register-ScheduledTask -TaskName 'DasOS CI (WSL dasci)' -Action $action -Trigger $trigger `
-Principal $principal -Settings $settings -Force | Out-Null
Get-ScheduledTask -TaskName 'DasOS CI (WSL dasci)' | Select-Object TaskName, State
+23
View File
@@ -0,0 +1,23 @@
# gitea-runner configuration for the Das OS CI host (WSL2 distro "dasci").
# Jobs run directly on the host: scripts/builder.sh needs the host's Docker
# and paths it can bind-mount into the privileged Void builder container.
log:
level: info
runner:
file: /var/lib/gitea-runner/.runner
# One build at a time: packages and ISOs share the cache in DASOS_OUT
capacity: 1
# Matches Gitea's default job timeout; the first build bootstraps void-packages
timeout: 3h
envs:
DASOS_OUT: /var/lib/dasos-ci/out
labels:
- "dasci:host"
cache:
# Build caches live in DASOS_OUT, the workflow does not use actions/cache
enabled: false
host:
workdir_parent: /var/lib/gitea-runner/work
+16
View File
@@ -0,0 +1,16 @@
[Unit]
Description=Gitea Actions runner for Das OS
After=docker.service network-online.target
Wants=network-online.target
Requires=docker.service
[Service]
User=runner
Group=runner
WorkingDirectory=/var/lib/gitea-runner
ExecStart=/usr/local/bin/gitea-runner -c /etc/gitea-runner/config.yaml daemon
Restart=always
RestartSec=10
[Install]
WantedBy=multi-user.target
+59
View File
@@ -0,0 +1,59 @@
#!/bin/sh
# Sets up the Das OS CI host: Docker Engine, the runner user and gitea-runner.
# Run as root inside a fresh Ubuntu 24.04 WSL2 distro with systemd enabled:
# sh setup.sh install everything
# sh setup.sh register <token> register the runner with git.das.org.ua
# Safe to run again.
set -eu
RUNNER_VERSION=5.1.1
INSTANCE=https://git.das.org.ua
here=$(cd "$(dirname "$0")" && pwd)
if [ "${1:-}" = register ]; then
[ -n "${2:-}" ] || { echo "usage: setup.sh register <token>" >&2; exit 1; }
sudo -u runner /usr/local/bin/gitea-runner -c /etc/gitea-runner/config.yaml \
register --no-interactive --instance "$INSTANCE" --token "$2" --name dasci
systemctl restart gitea-runner
exit 0
fi
export DEBIAN_FRONTEND=noninteractive
apt-get update -q
apt-get install -yq ca-certificates curl git make xz-utils
# Docker Engine from Docker's repository (Ubuntu's docker.io lags behind)
install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
. /etc/os-release
echo "deb [arch=amd64 signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu $VERSION_CODENAME stable" \
>/etc/apt/sources.list.d/docker.list
apt-get update -q
apt-get install -yq docker-ce docker-ce-cli containerd.io docker-buildx-plugin
systemctl enable --now docker
# Jobs run as an unprivileged user: build-packages.sh creates its xbps-src user
# with the caller's UID, which must not be root
id runner >/dev/null 2>&1 || useradd --create-home --shell /bin/bash --groups docker runner
install -d -o runner -g runner /var/lib/gitea-runner /var/lib/dasos-ci /var/lib/dasos-ci/out
url=https://gitea.com/gitea/runner/releases/download/v$RUNNER_VERSION/gitea-runner-$RUNNER_VERSION-linux-amd64.xz
tmp=$(mktemp -d)
curl -fsSL -o "$tmp/gitea-runner.xz" "$url"
curl -fsSL -o "$tmp/gitea-runner.xz.sha256" "$url.sha256"
(cd "$tmp" && echo "$(cut -d' ' -f1 gitea-runner.xz.sha256) gitea-runner.xz" | sha256sum -c --quiet)
xz -d "$tmp/gitea-runner.xz"
install -m 0755 "$tmp/gitea-runner" /usr/local/bin/gitea-runner
rm -rf "$tmp"
install -D -m 0644 "$here/config.yaml" /etc/gitea-runner/config.yaml
install -m 0644 "$here/gitea-runner.service" /etc/systemd/system/gitea-runner.service
systemctl daemon-reload
systemctl enable gitea-runner
# The runner starts once it is registered
if [ -f /var/lib/gitea-runner/.runner ]; then
systemctl restart gitea-runner
else
echo "Now register: sh setup.sh register <token>"
fi
gitea-runner --version
+6 -2
View File
@@ -1,18 +1,22 @@
#!/usr/bin/env bash
# Runs a command inside the Void Linux builder container.
# The project is mounted at /work; downloaded packages are cached in out/cache/xbps.
# DASOS_OUT puts out/ elsewhere (CI keeps it between checkouts).
set -euo pipefail
root=$(cd "$(dirname "$0")/.." && pwd)
out=${DASOS_OUT:-$root/out}
image=dasos-builder
docker build --quiet --tag "$image" "$root/docker/builder" >/dev/null
mkdir -p "$root/out/cache/xbps"
mkdir -p "$out/cache/xbps"
# --privileged: mklive mounts /proc, /sys, /dev and a loop device for the root image
exec docker run --rm --privileged \
--volume "$root:/work" \
--volume "$root/out/cache/xbps:/var/cache/xbps" \
${DASOS_OUT:+--volume "$out:/work/out"} \
--volume "$out/cache/xbps:/var/cache/xbps" \
--env HOST_UID="$(id -u)" \
--env HOST_GID="$(id -g)" \
--env DASOS_REBUILD \
"$image" "$@"
+31
View File
@@ -34,6 +34,30 @@ XBPS_CHROOT_CMD=uchroot
XBPS_MAKEJOBS=$(nproc)
CONF
# A package is rebuilt only when its directory in srcpkgs/ changed since the last
# build, its binary package is gone, or Void no longer provides a shared library
# it links to (a soname bump there needs a rebuild here). DASOS_REBUILD=1 rebuilds all.
stamps=$hostdir/stamps
mkdir -p "$stamps"
srchash() {
(cd "$vp/srcpkgs/$1" && find . -type f -print0 | sort -z | xargs -0 sha256sum) | sha256sum | cut -d' ' -f1
}
# An empty root to dry-run installs into: xbps refuses unresolved shared libraries
checkroot=$(mktemp -d)
mkdir -p "$checkroot/var/db/xbps/keys"
cp -a /var/db/xbps/keys/. "$checkroot/var/db/xbps/keys/"
voidrepo=$(sed -n 's/^repository=//p' /usr/share/xbps.d/*-repository-main.conf | head -1)
xbps-install -S -r "$checkroot" -R "$voidrepo" >/dev/null
up_to_date() {
local info version revision
[[ ${DASOS_REBUILD:-} != 1 && -f $stamps/$1 && $(< "$stamps/$1") == "$(srchash "$1")" ]] || return 1
info=$(as_builder ./xbps-src show "$1")
version=$(sed -n 's/^version:[[:space:]]*//p' <<<"$info")
revision=$(sed -n 's/^revision:[[:space:]]*//p' <<<"$info")
compgen -G "$hostdir/binpkgs/$1-${version}_$revision.*.xbps" >/dev/null || return 1
xbps-install -n -y -r "$checkroot" -R "$hostdir/binpkgs" -R "$voidrepo" "$1" >/dev/null 2>&1
}
names=()
for dir in /work/srcpkgs/*/; do
name=$(basename "$dir")
@@ -59,9 +83,16 @@ fi
# (also as a dependency of another one) would package the stale files
rm -rf masterdir-x86_64/destdir/*
for name in "${names[@]}"; do
if up_to_date "$name"; then
echo "==> $name is up to date"
continue
fi
echo "==> Building $name"
as_builder ./xbps-src -H "$hostdir" -f pkg "$name"
srchash "$name" >"$stamps/$name"
done
rm -rf "$checkroot"
chown -R "$HOST_UID:$HOST_GID" "$stamps"
echo "==> Repository: $hostdir/binpkgs"
ls -1 "$hostdir"/binpkgs/*.xbps
+416
View File
@@ -0,0 +1,416 @@
#!/bin/bash
# dprofile - install Das OS profiles: sets of packages from the Void
# repository with their services and groups, plus optional applications from
# Flathub. The profiles are in /usr/share/das/profiles/NAME.conf.
set -euo pipefail
# shellcheck source=helpers.sh
. "${DAS_HELPERS:-/usr/lib/das/helpers.sh}"
profiles_dir=${DAS_PROFILES:-/usr/share/das/profiles}
flathub=https://dl.flathub.org/repo/flathub.flatpakrepo
usage() {
if [[ -n $uk ]]; then
cat <<'EOF'
Використання: dprofile КОМАНДА [ПРОФІЛЬ] [...]
list профілі та їхній стан (типова команда)
show ПРОФІЛЬ пакети, служби й додаткові застосунки профілю
install ПРОФІЛЬ встановити профіль (зі знімком системи для відкату):
-y, --yes без запитань
--apps ID,...|all|none
які застосунки з Flathub додати (інакше запитає)
apps ПРОФІЛЬ додаткові застосунки профілю з Flathub
app add ID... встановити застосунки з Flathub (ID або його кінець:
AndroidStudio, GoLand)
app rm ID... видалити їх
Профіль dev: dprofile install dev
EOF
else
cat <<'EOF'
Usage: dprofile COMMAND [PROFILE] [...]
list profiles and their state (the default)
show PROFILE the profile's packages, services and optional apps
install PROFILE install a profile (with a system snapshot to roll back to):
-y, --yes ask nothing
--apps ID,...|all|none
which Flathub applications to add (asks otherwise)
apps PROFILE the profile's optional applications from Flathub
app add ID... install applications from Flathub (an ID or its end:
AndroidStudio, GoLand)
app rm ID... remove them
The dev profile: dprofile install dev
EOF
fi
}
desktop() {
command -v Xorg >/dev/null
}
live() {
grep -q 'root=live:' /proc/cmdline 2>/dev/null
}
profile_names() {
local f
for f in "$profiles_dir"/*.conf; do
[[ -e $f ]] || continue
f=${f##*/}
echo "${f%.conf}"
done
}
# load NAME: reads the profile into title, desc, packages, services, groups,
# subids, shared_root and apps (one "ID NAME" per line)
load() {
local f=$profiles_dir/$1.conf
[[ $1 =~ ^[a-z0-9-]+$ && -r $f ]] ||
die "немає профілю '$1' (dprofile list)" "no profile '$1' (dprofile list)"
title_uk="" title_en="" desc_uk="" desc_en="" server_desc_uk="" server_desc_en=""
packages="" desktop_packages="" services="" groups="" subids="" shared_root="" apps=""
# shellcheck source=profiles/dev.conf
. "$f"
title=$(say "$title_uk" "$title_en")
desc=$(say "$desc_uk" "$desc_en")
if desktop; then
packages+=" $desktop_packages"
else
apps=""
[[ -z $server_desc_en ]] || desc=$(say "$server_desc_uk" "$server_desc_en")
fi
# shellcheck disable=SC2086
packages=$(printf '%s\n' $packages)
apps=$(grep . <<<"$apps" || true)
}
installed() {
xbps-query "$1" >/dev/null 2>&1
}
# Packages of the loaded profile that are not installed yet
missing_packages() {
local p
while read -r p; do
installed "$p" || echo "$p"
done <<<"$packages"
}
app_installed() {
command -v flatpak >/dev/null && flatpak info --system "$1" >/dev/null 2>&1
}
cmd_list() {
local name total missing state
for name in $(profile_names); do
load "$name"
total=$(grep -c . <<<"$packages")
missing=$(missing_packages | grep -c . || true)
if ((missing == 0)); then
state=$(say "встановлено" "installed")
elif ((missing < total)); then
state=$(say "частково: бракує $missing з $total пакетів" "partly: $missing of $total packages missing")
else
state=$(say "не встановлено" "not installed")
fi
pad "$name" 8
echo "$title — $state"
echo " $desc"
done
}
cmd_show() {
local p id name
load "$1"
echo "$title: $desc"
say "Пакети (* — уже встановлені):" "Packages (* marks the installed ones):"
while read -r p; do
if installed "$p"; then echo " * $p"; else echo " $p"; fi
done <<<"$packages"
[[ -z $services ]] || say "Служби: $services" "Services: $services"
[[ -z $groups ]] || say "Групи користувача: $groups" "User groups: $groups"
if [[ -n $apps ]]; then
say "Додатково з Flathub (dprofile app add ID):" "Optional, from Flathub (dprofile app add ID):"
while read -r id name; do
if app_installed "$id"; then echo " * $(pad "$name" 30)$id"; else echo " $(pad "$name" 30)$id"; fi
done <<<"$apps"
fi
}
cmd_apps() {
local id name
load "$1"
[[ -n $apps ]] || {
say "У профілю $1 немає додаткових застосунків (або тут немає графічного сеансу)." \
"The $1 profile has no optional applications (or there is no graphical session here)."
return
}
while read -r id name; do
if app_installed "$id"; then echo "* $(pad "$name" 30)$id"; else echo " $(pad "$name" 30)$id"; fi
done <<<"$apps"
}
# resolve_app SPEC: the Flathub ID of SPEC, a full ID or its last part in any case
resolve_app() {
local spec=$1 name id found=""
if [[ $spec == *.*.* ]]; then
echo "$spec"
return
fi
shopt -s nocasematch
for name in $(profile_names); do
load "$name"
while read -r id _; do
[[ -n $id && ${id##*.} == "$spec" ]] && found=$id
done <<<"$apps"
done
shopt -u nocasematch
[[ -n $found ]] || die "невідомий застосунок '$spec': повний ID з Flathub або назва з dprofile apps" \
"unknown application '$spec': a full Flathub ID or a name from dprofile apps"
echo "$found"
}
setup_flathub() {
flatpak remote-add --system --if-not-exists flathub "$flathub"
}
# app_add ID...: installs Flathub applications system-wide
app_add() {
(($# > 0)) || return 0
command -v flatpak >/dev/null ||
die "немає flatpak: спершу dprofile install dev" "flatpak is missing: dprofile install dev first"
setup_flathub
say "Встановлюю з Flathub: $*" "Installing from Flathub: $*"
# The exports are in the users' XDG_DATA_DIRS (/etc/profile.d/flatpak.sh),
# not in root's: without them flatpak warns that the menu won't find the apps
XDG_DATA_DIRS=/var/lib/flatpak/exports/share:${XDG_DATA_DIRS:-/usr/local/share:/usr/share} \
flatpak install --system --noninteractive -y flathub "$@"
say "Застосунки з'являться в меню після наступного входу." "The applications appear in the menu after the next login."
}
cmd_app() {
local action=${1:-} ids=() spec
shift || true
desktop || die "застосунки з Flathub — лише для системи з графічним сеансом" \
"Flathub applications are only for a system with a graphical session"
(($# > 0)) || die "вкажіть застосунок: dprofile app $action GoLand" "give an application: dprofile app $action GoLand"
for spec in "$@"; do
ids+=("$(resolve_app "$spec")")
done
case $action in
add | install)
need_root app add "${ids[@]}"
app_add "${ids[@]}"
;;
rm | remove)
need_root app rm "${ids[@]}"
flatpak uninstall --system --noninteractive -y "${ids[@]}"
# The runtimes no other application uses take most of the space
flatpak uninstall --system --noninteractive -y --unused
;;
*) die "dprofile app add|rm ID..." "dprofile app add|rm ID..." ;;
esac
}
# choose_apps: asks which optional applications to install into "chosen"
choose_apps() {
local i=0 id name ids=() reply n ok
say "Додаткові середовища з Flathub (великі: 1–4 ГБ разом із рантаймами Flatpak):" \
"Optional IDEs from Flathub (large: 1-4 GB with the Flatpak runtimes):"
while read -r id name; do
ids+=("$id")
i=$((i + 1))
if app_installed "$id"; then
echo " $i) $(pad "$name" 30)$(say "уже встановлено" "already installed")"
else
echo " $i) $name"
fi
done <<<"$apps"
while true; do
chosen=()
ok=1
read -r -p "$(say "Номери через пробіл (Enter — жодного): " "Numbers separated by spaces (Enter for none): ")" reply || return 0
for n in ${reply//,/ }; do
if [[ $n =~ ^[0-9]+$ ]] && ((n >= 1 && n <= ${#ids[@]})); then
chosen+=("${ids[n - 1]}")
else
warn "'$n': номер від 1 до ${#ids[@]}" "'$n': a number from 1 to ${#ids[@]}"
ok=""
fi
done
[[ -z $ok ]] || return 0
done
}
# snapper pre/post pair around the installation, when snapshots are set up
snapshot_pre() {
[[ -e /etc/snapper/configs/root ]] || return 0
snapper -c root create --type pre --print-number --cleanup-algorithm number \
--description "dprofile install $1"
}
snapshot_post() {
[[ -n $1 ]] || return 0
snapper -c root create --type post --pre-number "$1" --cleanup-algorithm number \
--description "dprofile install $2" || true
}
# add_subids USER: subordinate IDs for rootless containers, after the
# highest range already given out
add_subids() {
local user=$1 file start
for file in /etc/subuid /etc/subgid; do
touch "$file"
grep -q "^$user:" "$file" && continue
start=$(awk -F: 'BEGIN { m = 100000 } { if ($2 + $3 > m) m = $2 + $3 } END { print m }' "$file")
if [[ $file == /etc/subuid ]]; then
usermod --add-subuids "$start-$((start + 65535))" "$user"
else
usermod --add-subgids "$start-$((start + 65535))" "$user"
fi
done
}
# Mount propagation for rootless containers, at every boot and right now
make_root_shared() {
local f=/etc/runit/core-services/60-das-shared-root.sh
[[ -e $f ]] && return
cat >"$f" <<'EOF'
# Created by dprofile: rootless Podman wants / to be a shared mount
mount --make-rshared /
EOF
mount --make-rshared /
}
cmd_install() {
local name="" yes="" asked="" app_spec="" user=${SUDO_USER:-} missing chosen=() id pre="" sv g joined=""
while (($# > 0)); do
case $1 in
-y | --yes) yes=1 ;;
--asked) asked=1 ;;
--apps) app_spec=${2:-}; shift ;;
--apps=*) app_spec=${1#--apps=} ;;
-*) die "невідомий параметр $1" "unknown option $1" ;;
*) name=$1 ;;
esac
shift
done
[[ -n $name ]] || die "вкажіть профіль: dprofile install dev" "give a profile: dprofile install dev"
load "$name"
live && die "це live-сесія: спершу встановіть Das OS на диск" "this is a live session: install Das OS to a disk first"
[[ $user == root ]] && user=""
missing=$(missing_packages | xargs)
# The questions come before sudo, so the password is asked for a known plan;
# --asked is the run through sudo after them
if [[ -z $asked ]]; then
echo "$title: $desc"
if [[ -n $missing ]]; then
say "Буде встановлено: $missing" "To be installed: $missing"
else
say "Усі пакети вже встановлено." "All packages are installed already."
fi
if [[ -n $apps && -z $app_spec && -z $yes ]] && interactive; then
choose_apps
app_spec=$(IFS=,; echo "${chosen[*]}")
app_spec=${app_spec:-none}
fi
if [[ -z $yes ]] && interactive; then
confirm "Продовжити?" "Continue?" || exit 1
fi
fi
need_root install "$name" --asked ${app_spec:+--apps "$app_spec"}
chosen=()
if [[ -n $apps ]]; then
case $app_spec in
"" | none) ;;
all) mapfile -t chosen < <(awk '{ print $1 }' <<<"$apps") ;;
*)
for id in ${app_spec//,/ }; do
chosen+=("$(resolve_app "$id")")
done
;;
esac
fi
if [[ -n $missing ]]; then
xbps-install -S
# xbps refuses to install anything while an update of itself is pending
if xbps-install -un 2>/dev/null | grep -q '^xbps-[0-9]'; then
xbps-install -uy xbps
fi
pre=$(snapshot_pre "$name") ||
die "не вдалося створити знімок системи, нічого не встановлено" "could not take a system snapshot, nothing was installed"
# shellcheck disable=SC2086
if ! xbps-install -y $missing; then
snapshot_post "$pre" "$name"
die "xbps-install не вдався" "xbps-install failed"
fi
snapshot_post "$pre" "$name"
fi
for sv in $services; do
if [[ -d /etc/sv/$sv && ! -e /etc/runit/runsvdir/default/$sv ]]; then
ln -s "/etc/sv/$sv" /etc/runit/runsvdir/default/
say "Служба $sv увімкнена" "Service $sv enabled"
fi
done
[[ -z $shared_root ]] || make_root_shared
if [[ -n $user ]]; then
for g in $groups; do
if getent group "$g" >/dev/null && ! id -nG "$user" | grep -qw "$g"; then
gpasswd -a "$user" "$g" >/dev/null
joined+=" $g"
fi
done
[[ -n $subids ]] && add_subids "$user"
[[ -z $joined ]] || say "$user тепер у групах:$joined (діє з наступного входу)" \
"$user is now in the groups:$joined (from the next login)"
elif [[ -n $groups ]]; then
say "Додайте користувачів до груп самі: duser groups КОРИСТУВАЧ +${groups// / +}" \
"Add users to the groups yourself: duser groups USER +${groups// / +}"
fi
if command -v flatpak >/dev/null && desktop; then
setup_flathub
app_add "${chosen[@]}"
fi
say "Профіль $name встановлено." "The $name profile is installed."
[[ -z $pre ]] || say "Відкат: у меню завантаження «Das OS snapshots» → знімок №$pre, потім sudo snapper-rollback $pre." \
"To roll back: \"Das OS snapshots\" → snapshot #$pre in the boot menu, then sudo snapper-rollback $pre."
}
cmd=${1:-list}
[[ $# -gt 0 ]] && shift
case $cmd in
list | ls) cmd_list ;;
show | info)
[[ $# -gt 0 ]] || die "вкажіть профіль: dprofile show dev" "give a profile: dprofile show dev"
cmd_show "$1"
;;
# Quiet, for das-welcome: success when every package is installed
check)
load "${1:-}"
[[ -z $(missing_packages) ]]
;;
install) cmd_install "$@" ;;
apps)
[[ $# -gt 0 ]] || die "вкажіть профіль: dprofile apps dev" "give a profile: dprofile apps dev"
cmd_apps "$1"
;;
app) cmd_app "$@" ;;
-h | --help | help) usage ;;
*)
usage >&2
exit 1
;;
esac
@@ -0,0 +1,32 @@
# bash completion for dprofile
# shellcheck shell=bash
_dprofile() {
local cur=${COMP_WORDS[COMP_CWORD]} cmd=${COMP_WORDS[1]:-} dir=/usr/share/das/profiles
local profiles
profiles=$(find "$dir" -maxdepth 1 -name '*.conf' -printf '%f\n' 2>/dev/null | sed 's/\.conf$//')
if ((COMP_CWORD == 1)); then
mapfile -t COMPREPLY < <(compgen -W "list show install apps app help" -- "$cur")
return
fi
case $cmd in
show | apps | check)
((COMP_CWORD == 2)) && mapfile -t COMPREPLY < <(compgen -W "$profiles" -- "$cur")
;;
install)
if [[ ${COMP_WORDS[COMP_CWORD - 1]} == --apps ]]; then
mapfile -t COMPREPLY < <(compgen -W "all none" -- "$cur")
else
mapfile -t COMPREPLY < <(compgen -W "$profiles --yes --apps" -- "$cur")
fi
;;
app)
if ((COMP_CWORD == 2)); then
mapfile -t COMPREPLY < <(compgen -W "add rm" -- "$cur")
else
# the last part of the IDs in the profiles: AndroidStudio, GoLand
mapfile -t COMPREPLY < <(compgen -W "$(sed -n 's/^[a-z]*\.[A-Za-z0-9.-]*\.\([A-Za-z0-9-]*\) .*/\1/p' "$dir"/*.conf 2>/dev/null)" -- "$cur")
fi
;;
esac
}
complete -F _dprofile dprofile
@@ -0,0 +1,47 @@
# Das OS developer profile, installed with "dprofile install dev".
# shellcheck shell=bash disable=SC2034
title_uk="Розробник"
title_en="Developer"
desc_uk="Go, Python, Node.js, Git, Docker і Podman, VS Code; середовища JetBrains і Android Studio з Flathub"
desc_en="Go, Python, Node.js, Git, Docker and Podman, VS Code; JetBrains IDEs and Android Studio from Flathub"
# Without a graphical session
server_desc_uk="Go, Python, Node.js, Git, Docker і Podman, консольні інструменти"
server_desc_en="Go, Python, Node.js, Git, Docker and Podman, command-line tools"
# Packages from the Void repository, on every system
packages="
base-devel gdb strace
git git-lfs github-cli lazygit
go gopls delve golangci-lint
python3-pip python3-virtualenv uv
nodejs
docker docker-compose docker-buildx lazydocker
podman podman-compose
jq ripgrep fd fzf direnv shellcheck sqlite"
# Only with a graphical session
desktop_packages="
vscode meld
flatpak xdg-desktop-portal xdg-desktop-portal-gtk"
# runit services to enable
services="docker"
# Groups the user who installs the profile joins (docker is root-equivalent)
groups="docker"
# Rootless Podman needs subordinate user and group IDs, and a shared root
# mount (runit leaves / private)
subids=yes
shared_root=yes
# Optional applications from Flathub (desktop only): ID and name
apps="
com.google.AndroidStudio Android Studio
com.jetbrains.IntelliJ-IDEA-Community IntelliJ IDEA Open
com.jetbrains.IntelliJ-IDEA-Ultimate IntelliJ IDEA Ultimate
com.jetbrains.PyCharm-Professional PyCharm
com.jetbrains.GoLand GoLand
com.jetbrains.WebStorm WebStorm
com.visualstudio.code Visual Studio Code (Microsoft)"
+4 -3
View File
@@ -1,9 +1,9 @@
# Template file for 'das-helpers'
pkgname=das-helpers
version=0.1.0
version=0.2.0
revision=1
depends="bash runit sudo shadow openssh nftables kbd"
short_desc="Das OS helpers: services (dsv), users (duser), firewall (dfw), system (dsys)"
short_desc="Das OS helpers: services, users, firewall, system settings, profiles"
maintainer="Das <anry.das@gmail.com>"
license="MIT"
homepage="https://git.das.org.ua/das/Das-OS"
@@ -13,7 +13,8 @@ provides="dsv-${version}_${revision}"
do_install() {
vinstall ${FILESDIR}/helpers.sh 644 usr/lib/das
for tool in dsv duser dfw dsys; do
vinstall ${FILESDIR}/profiles/dev.conf 644 usr/share/das/profiles
for tool in dsv duser dfw dsys dprofile; do
vbin ${FILESDIR}/${tool}
vcompletion ${FILESDIR}/${tool}.bash-completion bash ${tool}
done
@@ -66,7 +66,7 @@ t() {
s_config) echo "Налаштування системи..." ;;
s_post) echo "Локалі, знімки, initramfs (кілька хвилин)..." ;;
s_boot) echo "Встановлення завантажувача..." ;;
finished) echo "Das OS Server встановлено. Вийміть інсталяційний носій і перезавантажте сервер.\n\nВхід: %s, далі sudo. Служби: dsv. Користувачі: duser. Порти: dfw. Налаштування: dsys. Оновлення: das-update." ;;
finished) echo "Das OS Server встановлено. Вийміть інсталяційний носій і перезавантажте сервер.\n\nВхід: %s, далі sudo. Служби: dsv. Користувачі: duser. Порти: dfw. Налаштування: dsys. Оновлення: das-update. Профіль розробника: dprofile install dev." ;;
reboot) echo "Перезавантажити зараз?" ;;
failed) echo "Помилка встановлення. Журнал: %s" ;;
root) echo "Інсталятор треба запускати від root (sudo das-server-install)." ;;
@@ -105,7 +105,7 @@ t() {
s_config) echo "Configuring the system..." ;;
s_post) echo "Locales, snapshots, initramfs (a few minutes)..." ;;
s_boot) echo "Installing the boot loader..." ;;
finished) echo "Das OS Server is installed. Remove the installation medium and reboot.\n\nLog in as %s, then use sudo. Services: dsv. Users: duser. Ports: dfw. Settings: dsys. Updates: das-update." ;;
finished) echo "Das OS Server is installed. Remove the installation medium and reboot.\n\nLog in as %s, then use sudo. Services: dsv. Users: duser. Ports: dfw. Settings: dsys. Updates: das-update. Developer profile: dprofile install dev." ;;
reboot) echo "Reboot now?" ;;
failed) echo "Installation failed. Log: %s" ;;
root) echo "The installer must run as root (sudo das-server-install)." ;;
+1 -1
View File
@@ -1,6 +1,6 @@
# Template file for 'das-server-installer'
pkgname=das-server-installer
version=0.2.0
version=0.3.0
revision=1
depends="bash dialog das-install-common btrfs-progs dosfstools gptfdisk parted
rsync util-linux grub grub-x86_64-efi efibootmgr"
@@ -1,5 +1,5 @@
// Command das-welcome is the Das OS first-login window: interface language,
// home folder names, updates, settings and help.
// home folder names, updates, the developer profile, settings and help.
//
// das-welcome show the window
// das-welcome --autostart show it only if the user did not turn that off
@@ -207,6 +207,9 @@ func newWindow(app *gtk.Application) (*gtk.ApplicationWindow, error) {
row, _ := b.row("software-update-available", i18n.T("welcome.update"), i18n.T("welcome.update.desc"),
b.button(i18n.T("welcome.update.open"), func() { launch("das-update") }))
add(row)
if row := profileRow(b); row != nil {
add(row)
}
}
row, _ := b.row("preferences-desktop", i18n.T("welcome.settings"), i18n.T("welcome.settings.desc"),
b.button(i18n.T("welcome.open"), func() { launch("xfce4-settings-manager") }))
@@ -249,6 +252,23 @@ func launch(name string, args ...string) {
}
}
// profileRow installs the developer profile in a terminal, where dprofile
// asks for the password and which IDEs to add. It returns nil without dprofile.
func profileRow(b *builder) *gtk.Box {
if _, err := exec.LookPath("dprofile"); err != nil {
return nil
}
desc, label := i18n.T("welcome.dev.desc"), i18n.T("welcome.dev.install")
if exec.Command("dprofile", "check", "dev").Run() == nil {
desc, label = i18n.T("welcome.dev.installed"), i18n.T("welcome.dev.apps")
}
row, _ := b.row("applications-development", i18n.T("welcome.dev"), desc,
b.button(label, func() {
launch("xfce4-terminal", "--hold", "--title", i18n.T("welcome.dev"), "-x", "dprofile", "install", "dev")
}))
return row
}
// languageRow offers the UTF-8 locales the system has built. It returns nil
// when there is nothing to choose from.
func languageRow(b *builder) *gtk.Box {
@@ -111,6 +111,11 @@ var messages = map[string]message{
"welcome.update": {"Оновлення", "Updates"},
"welcome.update.desc": {"Перед кожним оновленням створюється знімок системи для відкату.", "A system snapshot is taken before every update so it can be rolled back."},
"welcome.update.open": {"Перевірити", "Check"},
"welcome.dev": {"Профіль розробника", "Developer profile"},
"welcome.dev.desc": {"Go, Python, Node.js, Git, Docker і Podman, VS Code; за бажанням JetBrains і Android Studio з Flathub.", "Go, Python, Node.js, Git, Docker and Podman, VS Code; JetBrains IDEs and Android Studio from Flathub if you like."},
"welcome.dev.installed": {"Встановлено. Середовища JetBrains і Android Studio можна додати з Flathub.", "Installed. JetBrains IDEs and Android Studio can be added from Flathub."},
"welcome.dev.install": {"Встановити", "Install"},
"welcome.dev.apps": {"Додати середовища", "Add IDEs"},
"welcome.settings": {"Налаштування", "Settings"},
"welcome.settings.desc": {"Тема, екран, клавіатура, принтери та інше.", "Theme, display, keyboard, printers and more."},
"welcome.open": {"Відкрити", "Open"},
+1 -1
View File
@@ -1,7 +1,7 @@
# Template file for 'das-tools'
# In-tree package: Go sources are in files/src (FILESDIR).
pkgname=das-tools
version=0.3.0
version=0.4.0
revision=1
create_wrksrc=yes
# Like build_style=go: the Go linker decides about PIE, xbps-src must not check it