Skip to main content

max / alloy_tui

11.0 KB · 248 lines History Blame Raw
1 # Alloy — bootable container image
2 #
3 # Built with `podman build`. Published to quay.io/alloy/alloy.
4 # See docs/IMAGE.md for the composition strategy and rationale.
5 #
6 # Layer order optimizes rebuild speed: repos first (rarely change),
7 # then fonts (large downloads, pinned), then package installs (change
8 # with STACK.md), then config tree (changes most often, so lives at
9 # the tail).
10 #
11 # Single-stage. The image carries no cargo-built binaries: everything
12 # ships from a repo. Screen recording is the one gap (see the deferral
13 # note in docs/STACK.md#screen-recorder).
14
15 # =====================================================================
16 # Runtime image — the bootable container itself.
17 # =====================================================================
18 FROM quay.io/fedora/fedora-bootc:43
19
20 # =====================================================================
21 # Third-party repos
22 # =====================================================================
23 # Tailscale is not in Fedora main; drop their .repo file directly.
24 RUN curl -fsSL -o /etc/yum.repos.d/tailscale.repo \
25 https://pkgs.tailscale.com/stable/fedora/tailscale.repo
26
27 # Terra — Fedora repo for parts of the Wayland ecosystem (swww,
28 # starship, and some others). Does not carry Rust binaries like
29 # nushell or yazi; COPRs below handle those.
30 # https://terra.fyralabs.com/
31 RUN dnf install -y --nogpgcheck \
32 --repofrompath='terra,https://repos.fyralabs.com/terra$releasever' \
33 terra-release
34
35 # dnf5's copr plugin isn't in the base bootc image; pull it so we
36 # can `dnf copr enable` for the Rust-Wayland stragglers.
37 RUN dnf install -y 'dnf5-command(copr)'
38
39 # ublue-os/staging is the community-maintained COPR that packages
40 # much of the Wayland / Rust ecosystem for atomic Fedora derivatives.
41 # We're not using their base image, but their COPR is a legitimate
42 # adoption (same relationship the rest of Alloy has to Fedora repos).
43 #
44 # Verified 2026-07-19: it does NOT carry wl-screenrec, which is why
45 # that one needed a cargo stage and is now deferred. Check before
46 # assuming a Rust Wayland tool is here.
47 RUN dnf copr enable -y ublue-os/staging
48
49 # nushell binary (Terra has crates only)
50 RUN dnf copr enable -y atim/nushell
51
52 # yazi binary
53 RUN dnf copr enable -y varlad/yazi
54
55 # satty (screenshot annotator) is expected in ublue-os/staging;
56 # if it turns out to need its own COPR, add here.
57
58 # =====================================================================
59 # Fonts pulled from upstream releases (not cleanly packaged in Fedora):
60 # - IosevkaTerm Nerd Font (mono, TUI-safe: no ligatures, has NF glyphs)
61 # - Atkinson Hyperlegible (sans, high-legibility)
62 #
63 # These sit ahead of the package list on purpose. They are the largest
64 # downloads in the build, and the package list is the line that changes
65 # most often; behind it, every package edit re-fetched both archives.
66 # The unzip/fontconfig they need comes from its own small layer rather
67 # than from the main install, which is what lets the split work.
68 # =====================================================================
69 # Both sources are pinned. Unpinned (`releases/latest`, branch `main`)
70 # these layers change content without the Containerfile changing, so a
71 # cache hit stops meaning "same bytes" and two builds of the same commit
72 # can ship different fonts. Bump deliberately.
73 #
74 # Atkinson Hyperlegible publishes no tags, so it pins to a commit.
75 ARG NERD_FONTS_VERSION=v3.4.0
76 ARG ATKINSON_COMMIT=1cb311624b2ddf88e9e37873999d165a8cd28b46
77
78 RUN dnf install -y unzip fontconfig && dnf clean all
79 RUN mkdir -p /usr/share/fonts/iosevkaterm-nerd \
80 /usr/share/fonts/atkinson-hyperlegible && \
81 curl -fsSL -o /tmp/iosevkaterm-nf.zip \
82 "https://github.com/ryanoasis/nerd-fonts/releases/download/${NERD_FONTS_VERSION}/IosevkaTerm.zip" && \
83 unzip -o /tmp/iosevkaterm-nf.zip -d /usr/share/fonts/iosevkaterm-nerd && \
84 rm /tmp/iosevkaterm-nf.zip && \
85 curl -fsSL -o /tmp/atkinson-hyperlegible.tar.gz \
86 "https://github.com/googlefonts/atkinson-hyperlegible/archive/${ATKINSON_COMMIT}.tar.gz" && \
87 tar -xzf /tmp/atkinson-hyperlegible.tar.gz -C /tmp && \
88 find /tmp/atkinson-hyperlegible-* -name '*.ttf' -exec cp {} /usr/share/fonts/atkinson-hyperlegible/ \; && \
89 rm -rf /tmp/atkinson-hyperlegible.tar.gz /tmp/atkinson-hyperlegible-* && \
90 fc-cache -fv
91
92 # =====================================================================
93 # Package additions — full Alloy stack per docs/STACK.md
94 #
95 # Sources noted per group. Anything absent from both Fedora main and
96 # Terra is downloaded directly (Nerd Fonts, in the layer above). The
97 # `flatpak` client is installed so users can pull ungoogled-chromium and
98 # other on-demand apps from Flathub post-install; no Flatpaks are
99 # provisioned at build or first-boot time.
100 # =====================================================================
101 RUN dnf install -y \
102 # Compositor and Wayland session (Fedora main)
103 sway \
104 # Portals: -wlr is the wlroots backend sway needs for screencast.
105 # -gnome was the wrong backend here (it drives screencast through
106 # gnome-shell, which Alloy removes below). -gtk stays for the file
107 # chooser.
108 xdg-desktop-portal xdg-desktop-portal-gtk xdg-desktop-portal-wlr \
109 # Notifications, screenshot annotate, wallpaper (bar = sway's built-in swaybar)
110 mako \
111 satty \
112 swww \
113 # Terminal, multiplexer, editor, shell, prompt
114 rio \
115 zellij \
116 helix \
117 nushell \
118 starship \
119 zoxide \
120 direnv \
121 # File managers
122 yazi \
123 # Content viewers
124 mpv \
125 imv \
126 zathura zathura-pdf-mupdf \
127 # System introspection
128 bottom \
129 dua-cli \
130 # Wayland session glue
131 cliphist \
132 # Lock + idle. swaylock is the adopted lock surface per
133 # docs/STACK.md#lock. A session-lock surface is graphical and
134 # cannot be a TUI, so Alloy adopts rather than authors it. The
135 # themed config in etc/skel had no package behind it until now.
136 swaylock \
137 swayidle \
138 swayosd \
139 playerctl \
140 gammastep \
141 # Continuity
142 tailscale \
143 syncthing \
144 restic \
145 # Greeter
146 greetd \
147 tuigreet \
148 # First-boot account creation. The bootc Anaconda flow offers no
149 # user-creation spoke, so without this an install completes with
150 # root locked, greeter set to nologin, and no way to log in.
151 # Deliberately NOT initial-setup-gui: with no GUI binary present
152 # run-initial-setup takes the TUI branch, which is what Alloy
153 # wants regardless of default.target being graphical.target.
154 # Retired when the Alloy installer replaces Anaconda (GO task).
155 initial-setup \
156 # Cursor, GTK theme
157 bibata-cursor-theme \
158 adw-gtk3-theme \
159 # Screenshot capture + region-select (sway has no built-in grab)
160 grim slurp \
161 # Browser (Gecko default; ungoogled-chromium is opt-in Flatpak per docs/STACK.md)
162 firefox \
163 # Flatpak client (user-installed apps on demand; see docs/STACK.md)
164 flatpak \
165 && dnf clean all
166
167 # =====================================================================
168 # Package removals — stock desktop pieces Alloy replaces
169 # =====================================================================
170 # fedora-bootc:43 is minimal and probably ships none of these, but keep
171 # the remove line for safety in case the base grows. || true swallows
172 # the "package not installed" error path.
173 RUN dnf remove -y \
174 gdm \
175 gnome-shell \
176 gnome-session \
177 || true
178
179 # =====================================================================
180 # System user for greetd. greetd drops privileges to this account
181 # before spawning tuigreet; without it greetd exits with
182 # "configured default session user 'greeter' not found". Fedora
183 # bootc's minimal user database does not include it.
184 # =====================================================================
185 RUN useradd -M -r -s /sbin/nologin greeter
186
187 # =====================================================================
188 # Config tree — the etc/ and usr/ trees in the repo map 1:1 into
189 # the image. Per-user defaults live under etc/skel/.config/ and
190 # etc/skel/.mozilla/ (Firefox first-launch profile seed); system-
191 # wide config under etc/; Firefox autoconfig + mozilla.cfg under
192 # usr/lib64/firefox/. See docs/IMAGE.md for the layout.
193 # =====================================================================
194 COPY etc/ /etc/
195 COPY usr/ /usr/
196
197 # =====================================================================
198 # Systemd presets — shipped via etc/systemd/{system,user}-preset/
199 # in the config tree above. Split across system-preset (greetd,
200 # tailscaled) and user-preset (swayosd, syncthing, gammastep).
201 # See docs/CONTINUITY.md for rationale.
202 #
203 # The preset files declare the intended enable/disable state; they
204 # do not by themselves create the wants/ symlinks. `systemctl
205 # preset-all` reads every preset file and applies it — this must
206 # run after the config tree is in place, so it lives here.
207 # =====================================================================
208 RUN systemctl preset-all
209
210 # =====================================================================
211 # Branding
212 # =====================================================================
213 # os-release, plymouth splash, wallpapers ship via the config tree
214 # above. No additional layer needed here.
215
216 # =====================================================================
217 # Disable third-party repos post-install.
218 # =====================================================================
219 # terra, the Rust-Wayland COPRs, and Tailscale are needed only at
220 # build time to layer packages Fedora doesn't carry. Left enabled they
221 # earn nothing at runtime (a bootc image updates by whole-image pull,
222 # not per-package dnf) and actively break bootc-image-builder: its
223 # installer depsolve reads every enabled repo but runs in its own
224 # environment, where these repos' file:// GPG keys and metalinks can't
225 # be resolved. Disable them so only the Fedora repos remain live; the
226 # already-installed packages are unaffected.
227 RUN sed -i 's/^enabled=1/enabled=0/; s/^enabled_metadata=1/enabled_metadata=0/' \
228 /etc/yum.repos.d/terra.repo \
229 /etc/yum.repos.d/tailscale.repo \
230 /etc/yum.repos.d/_copr:*.repo
231
232 # =====================================================================
233 # Pin dnf's $releasever to the Fedora base version.
234 # =====================================================================
235 # Alloy's os-release carries its own VERSION_ID (0.0), so dnf/librepo
236 # would otherwise expand $releasever to "0.0" and request the
237 # nonexistent fedora-0.0 repo (404). Every consumer of the Fedora
238 # repos — rpm-ostree package layering on the installed system, and
239 # bootc-image-builder's installer depsolve — needs this pinned to the
240 # actual base version, independent of Alloy's product version.
241 RUN echo 43 > /etc/dnf/vars/releasever
242
243 # =====================================================================
244 # bootc validation — fails the build if the image isn't a valid
245 # bootable container.
246 # =====================================================================
247 RUN bootc container lint
248