-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathContainerfile
More file actions
402 lines (379 loc) · 19.1 KB
/
Copy pathContainerfile
File metadata and controls
402 lines (379 loc) · 19.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
# generated — edit Containerfile.d/*.containerfile instead
ARG BASE_IMAGE="ghcr.io/ublue-os/bluefin-dx"
ARG TAG="stable"
FROM ${BASE_IMAGE}:${TAG}
# ── Framework laptop & Intel-specific ────────────────────────────────────────
RUN rpm-ostree install \
thermald \
fprintd \
fprintd-pam \
powertop \
&& ostree container commit
# ── Developer tooling ────────────────────────────────────────────────────────
# rpm-ostree doesn't support @group syntax in container builds; use dnf5
RUN dnf5 group install -y development-tools && dnf5 clean all && \
ostree container commit
RUN rpm-ostree install \
emacs \
python3 \
neovim \
tmux \
pandoc \
plantuml \
aspell \
aspell-en \
texlive-latex \
texlive-latex-bin \
texlive-collection-latexrecommended \
fish \
alacritty \
firefox \
sqlite-devel \
stow \
gitleaks \
the_silver_searcher \
rlwrap \
xclip \
fd-find \
bat \
eza \
zoxide \
fzf \
jq \
yq \
httpie \
ripgrep \
btop \
tldr \
fossil \
ShellCheck \
&& ostree container commit
# GitHub CLI — official RPM repo; not in Fedora repos
RUN curl -fsSL https://cli.github.com/packages/rpm/gh-cli.repo \
-o /etc/yum.repos.d/gh-cli.repo && \
dnf5 install -y gh && \
dnf5 clean all && \
ostree container commit
# Set fish as the default shell for new users (read by Anaconda at install time)
RUN sed -i 's|^SHELL=.*|SHELL=/usr/bin/fish|' /etc/default/useradd && \
ostree container commit
# zellij: not in Fedora 44 repos, install musl binary from GitHub releases
RUN curl -fsSL \
"https://github.com/zellij-org/zellij/releases/latest/download/zellij-x86_64-unknown-linux-musl.tar.gz" \
| tar -xz -C /usr/bin zellij && \
ostree container commit
# lazygit: git TUI, not in Fedora repos
RUN LAZYGIT_VERSION=$(curl -sL "https://api.github.com/repos/jesseduffield/lazygit/releases/latest" | \
jq -r '.tag_name') && \
curl -fsSL "https://github.com/jesseduffield/lazygit/releases/download/${LAZYGIT_VERSION}/lazygit_${LAZYGIT_VERSION#v}_Linux_x86_64.tar.gz" \
| tar -xz -C /usr/bin lazygit && \
ostree container commit
# fastfetch: tarball is fastfetch-linux-amd64/{usr/bin,usr/share,...}; strip the top dir
RUN curl -fsSL \
"https://github.com/fastfetch-cli/fastfetch/releases/latest/download/fastfetch-linux-amd64.tar.gz" \
| tar -xz --strip-components=1 -C / && \
ostree container commit
# starship: not in Fedora repos; /usr/local/bin doesn't exist in ostree images
RUN curl -fsSL \
"https://github.com/starship/starship/releases/latest/download/starship-x86_64-unknown-linux-musl.tar.gz" \
| tar -xz -C /usr/bin starship && \
ostree container commit
# whis CLI (https://whis.ink/cli): voice-to-text, separate from the Flatpak
# desktop app; not in Fedora repos. Release asset name embeds the version, so
# the latest/download static-filename trick (used above) doesn't apply here —
# resolve the tag first, as with lazygit.
RUN WHIS_VERSION=$(curl -sL "https://api.github.com/repos/frankdierolf/whis/releases/latest" | \
jq -r '.tag_name') && \
curl -fsSL "https://github.com/frankdierolf/whis/releases/download/${WHIS_VERSION}/whis-${WHIS_VERSION}-x86_64-unknown-linux-gnu.tar.gz" \
| tar -xz -C /usr/bin whis && \
ostree container commit
# trufflehog: secret scanner for git repos, filesystems, and live sources
# (https://github.com/trufflesecurity/trufflehog); not in Fedora repos.
# Asset name embeds the version without the leading "v", as with lazygit.
RUN TRUFFLEHOG_VERSION=$(curl -sL "https://api.github.com/repos/trufflesecurity/trufflehog/releases/latest" | \
jq -r '.tag_name') && \
curl -fsSL "https://github.com/trufflesecurity/trufflehog/releases/download/${TRUFFLEHOG_VERSION}/trufflehog_${TRUFFLEHOG_VERSION#v}_linux_amd64.tar.gz" \
| tar -xz -C /usr/bin trufflehog && \
ostree container commit
# Nyxt browser — not in Fedora repos; ships as an AppImage inside a tarball
# /opt is a symlink in ostree images; use /usr/lib instead
RUN curl -fsSL \
"https://github.com/atlas-engineer/nyxt/releases/latest/download/Linux-Nyxt-x86_64.tar.gz" \
-o /tmp/nyxt.tar.gz && \
mkdir -p /usr/lib/nyxt && \
tar -xzf /tmp/nyxt.tar.gz -C /usr/lib/nyxt && \
chmod +x /usr/lib/nyxt/*.AppImage && \
ln -sf /usr/lib/nyxt/Nyxt-x86_64.AppImage /usr/bin/nyxt && \
rm /tmp/nyxt.tar.gz && \
ostree container commit
# Homebrew — cloned to /home/linuxbrew/.linuxbrew (/home → /var/home in ostree)
# The image's /var is used to initialize a fresh install, so brew is available on first boot.
# wheel group owns the prefix so the default admin user can run brew install without sudo.
RUN mkdir -p /var/home/linuxbrew && \
git clone --depth=1 https://github.com/Homebrew/brew /var/home/linuxbrew/.linuxbrew && \
chown -R root:wheel /var/home/linuxbrew/.linuxbrew && \
chmod -R g+rwX /var/home/linuxbrew/.linuxbrew && \
ostree container commit
# opencode — installed via Homebrew tap; must run after brew is cloned above.
# eval'ing shellenv gives brew its Cellar/Homebrew.rb dependencies on PATH for
# the duration of this RUN step (brew isn't on PATH in a build shell otherwise).
# /root -> /var/roothome (symlink); pre-create it so Homebrew's Ruby code can
# resolve $HOME (Dir.mkdir on a dangling symlink target raises EEXIST).
RUN mkdir -p /var/roothome && \
eval "$(/var/home/linuxbrew/.linuxbrew/bin/brew shellenv)" && \
brew install anomalyco/tap/opencode && \
ostree container commit
# SDKMAN! — installed to /var/sdkman (mutable, persists across bootc updates)
# wheel group owns the prefix so the default admin user can run sdk install without sudo.
# /root -> /var/roothome (symlink); pre-create .bashrc so the installer script can finish
# (it appends to .bashrc at the end — harmless, but errors if the file doesn't exist).
# sdkman-for-fish provides a native fish sdk function in /etc/fish/functions/sdk.fish.
RUN mkdir -p /var/roothome && \
touch /var/roothome/.bashrc /var/roothome/.bash_profile /var/roothome/.profile && \
curl -fsSL "https://get.sdkman.io" | SDKMAN_DIR=/var/sdkman SDKMAN_NONINTERACTIVE=true bash && \
chown -R root:wheel /var/sdkman && \
chmod -R g+rwX /var/sdkman && \
mkdir -p /etc/fish/functions /etc/fish/completions && \
curl -fsSL "https://raw.githubusercontent.com/reitzig/sdkman-for-fish/main/functions/sdk.fish" \
-o /etc/fish/functions/sdk.fish && \
curl -fsSL "https://raw.githubusercontent.com/reitzig/sdkman-for-fish/main/completions/sdk.fish" \
-o /etc/fish/completions/sdk.fish && \
ostree container commit
# Pi coding agent — use dnf5 (not rpm-ostree) so nodejs is immediately available
# for the subsequent npm call within the same RUN step
RUN dnf5 install -y nodejs pnpm && \
dnf5 clean all && \
npm install -g --prefix /usr --ignore-scripts @earendil-works/pi-coding-agent && \
ostree container commit
# TypeScript toolchain — compiler + LSP server for Emacs/Neovim editor integration
RUN npm install -g --prefix /usr --ignore-scripts \
typescript \
typescript-language-server && \
ostree container commit
# Claude Code CLI
RUN npm install -g --prefix /usr @anthropic-ai/claude-code && \
ostree container commit
# Rust — Fedora's packaged rustc/cargo, not rustup (upstream warns the two
# conflict on the same system). rust-src + rustfmt + clippy + rust-analyzer
# cover IDE code intelligence and linting; `cargo install` works out of the
# box for pure-Rust crates since development-tools (gcc, make) is already
# installed for crates that need to compile C dependencies.
# https://developer.fedoraproject.org/tech/languages/rust/rust-installation.html
RUN rpm-ostree install \
rust \
cargo \
clippy \
rust-src \
rustfmt \
rust-analyzer \
&& ostree container commit
# Clojure CLI — use dnf5 so java is immediately available when the installer
# runs; use --prefix /usr (ostree has no /usr/local/bin)
RUN dnf5 install -y java-25-openjdk && \
dnf5 clean all && \
curl -fsSL "https://github.com/clojure/brew-install/releases/latest/download/linux-install.sh" \
-o /tmp/clojure-install.sh && \
chmod +x /tmp/clojure-install.sh && \
/tmp/clojure-install.sh --prefix /usr && \
rm /tmp/clojure-install.sh && \
ostree container commit
# clj-new — registers seancorfield/clj-new as a `clojure -T clj-new` tool for
# scaffolding new projects/templates. The registration lives under $HOME
# (~/.clojure/tools/tools.edn), same as any `clojure -Ttools install`; unlike
# the system-wide installs below, it only takes effect for whichever user's
# $HOME it's run under.
RUN clojure -Ttools install-latest :lib com.github.seancorfield/clj-new :as clj-new && \
ostree container commit
# babashka: fast-starting Clojure scripting runtime; bbin (next step) needs
# `bb` on PATH to run its own scripts. Static-binary release, same
# latest-tag-via-API pattern used for whis/trufflehog in 030-cli-tools.
RUN BB_VERSION=$(curl -sL "https://api.github.com/repos/babashka/babashka/releases/latest" | \
jq -r '.tag_name') && \
curl -fsSL "https://github.com/babashka/babashka/releases/download/${BB_VERSION}/babashka-${BB_VERSION#v}-linux-amd64-static.tar.gz" \
| tar -xz -C /usr/bin bb && \
ostree container commit
# bbin — installs standalone Babashka scripts as commands (used below for
# clojure-mcp-light and clj-paren-repair). It's itself a `bb` script fetched
# straight from the repo; babashka/bbin has no GitHub Releases, so the tags
# API stands in for the "latest" lookup used elsewhere. BABASHKA_BBIN_BIN_DIR
# pins installed tools to /usr/bin instead of the default ~/.local/bin, so
# they land somewhere every user's PATH sees — same reasoning as the
# linuxbrew prefix in 050-package-managers.
RUN BBIN_VERSION=$(curl -sL "https://api.github.com/repos/babashka/bbin/tags" | \
jq -r '.[0].name') && \
curl -fsSL "https://raw.githubusercontent.com/babashka/bbin/${BBIN_VERSION}/bbin" \
-o /usr/bin/bbin && \
chmod +x /usr/bin/bbin && \
ostree container commit
# clojure-mcp-light + clj-paren-repair (bhauman/clojure-mcp-light) — MCP
# server and paren-balancing helper for agentic Clojure workflows.
# https://www.iwillig.me/agentic-engineering-with-clojure/agentic-toolchain.html
RUN BABASHKA_BBIN_BIN_DIR=/usr/bin bbin install \
https://github.com/bhauman/clojure-mcp-light.git \
--tag v0.2.1 && \
BABASHKA_BBIN_BIN_DIR=/usr/bin bbin install \
https://github.com/bhauman/clojure-mcp-light.git \
--tag v0.2.1 \
--as clj-paren-repair \
--main-opts '["-m" "clojure-mcp-light.paren-repair"]' && \
ostree container commit
# Handy — open-source push-to-talk speech-to-text; not in Fedora repos
# gtk-layer-shell is a runtime dependency missing from the handy RPM metadata
RUN dnf5 install -y gtk-layer-shell && \
HANDY_RPM_URL=$(curl -sL "https://api.github.com/repos/cjpais/Handy/releases/latest" | \
jq -r '.assets[] | select(.name | test("x86_64\\.rpm$")) | .browser_download_url') && \
curl -fsSL "$HANDY_RPM_URL" -o /tmp/handy.rpm && \
dnf5 install -y /tmp/handy.rpm && \
dnf5 clean all && \
rm /tmp/handy.rpm && \
ostree container commit
# Whis desktop — push-to-talk voice-to-text GUI companion to the whis CLI;
# not in Fedora repos. Installs /usr/bin/whis-desktop; sway binds
# ctrl+alt+w to `whis-desktop --toggle` per its own Wayland guidance.
RUN WHIS_RPM_URL=$(curl -sL "https://api.github.com/repos/frankdierolf/whis/releases/latest" | \
jq -r '.assets[] | select(.name | test("x86_64\\.rpm$")) | .browser_download_url') && \
curl -fsSL "$WHIS_RPM_URL" -o /tmp/whis.rpm && \
dnf5 install -y /tmp/whis.rpm && \
dnf5 clean all && \
rm /tmp/whis.rpm && \
ostree container commit
# ── Spatial / GIS tooling ─────────────────────────────────────────────────────
RUN rpm-ostree install \
gdal \
gdal-devel \
gdal-libs \
python3-gdal \
mapnik \
mapnik-devel \
python3-mapnik \
qgis \
grass \
grass-devel \
proj \
proj-devel \
geos \
geos-devel \
libspatialite \
libspatialite-devel \
spatialite-tools \
&& ostree container commit
# ── Wine ──────────────────────────────────────────────────────────────────────
RUN rpm-ostree install \
wine \
winetricks \
&& ostree container commit
# ── Fonts ─────────────────────────────────────────────────────────────────────
RUN rpm-ostree install \
jetbrains-mono-fonts \
cascadia-code-fonts \
google-noto-emoji-fonts \
&& ostree container commit
RUN mkdir -p /usr/share/fonts/inter && \
INTER_URL=$(curl -sL "https://api.github.com/repos/rsms/inter/releases/latest" | \
jq -r '.assets[] | select(.name | endswith(".zip")) | .browser_download_url') && \
curl -fsSL "$INTER_URL" -o /tmp/inter.zip && \
unzip -q /tmp/inter.zip -d /tmp/inter-extracted && \
find /tmp/inter-extracted -name "*.otf" -exec cp {} /usr/share/fonts/inter/ \; && \
rm -rf /tmp/inter.zip /tmp/inter-extracted && \
fc-cache -f && \
ostree container commit
# Download JetBrains Mono Nerd Font (patched version, not in Fedora repos)
RUN NERD_FONT_VERSION="v3.2.1" && \
mkdir -p /usr/share/fonts/nerd-fonts/JetBrainsMono && \
curl -fsSL "https://github.com/ryanoasis/nerd-fonts/releases/download/${NERD_FONT_VERSION}/JetBrainsMono.tar.xz" \
| tar -xJ -C /usr/share/fonts/nerd-fonts/JetBrainsMono && \
fc-cache -f && \
ostree container commit
# ── Better font rendering ─────────────────────────────────────────────────────
COPY config/files/ /
# Enable first-boot services
RUN systemctl enable install-1password.service && \
ostree container commit
# ── Sway — minimal Wayland tiling WM alongside GNOME ─────────────────────────
# All packages are in standard Fedora repos — no COPR needed.
# GDM auto-detects /usr/share/wayland-sessions/sway.desktop (installed by the
# sway package) and offers it as a login session choice — no display manager
# changes needed. All tools are session-scoped and do not conflict with GNOME.
#
# NOTE: Hyprland was evaluated but its solopasha COPR packages currently fail
# on bluefin-dx because they require libdisplay-info.so.2 while the base image
# ships libdisplay-info-0.3.0 (.so.3), which mutter also depends on. Revisit
# once the COPR rebuilds against .so.3.
#
# sway-config-fedora must be requested explicitly — plain `dnf install sway`
# defaults to sway-config-upstream, whose vanilla config wires up foot/wmenu
# and a built-in bar instead of the waybar/wofi/mako below.
# kanshi auto-switches output profiles on hotplug (e.g. disabling eDP-1 when the
# ViewSonic XG3220 external monitor is connected) — see /etc/kanshi/config.
# gnome-monitor-config is the equivalent manual CLI for the GNOME/mutter
# session, where kanshi's wlr-output-management protocol isn't available.
# blueman and network-manager-applet ship XDG autostart entries and launch
# automatically via sway-xdg-autostart.target (no exec needed in sway config).
# gammastep (GNOME Night Light equivalent) ships a systemd user service and is
# enabled globally here so it starts with the sway session.
RUN dnf5 install -y \
sway \
sway-config-fedora \
swaylock \
swaybg \
swayidle \
xdg-desktop-portal-wlr \
waybar \
wofi \
mako \
kanshi \
gnome-monitor-config \
blueman \
network-manager-applet \
gammastep \
&& dnf5 clean all \
&& systemctl --global enable kanshi.service \
&& systemctl --global enable gammastep.service \
&& ostree container commit
# ── elementary GTK theme ──────────────────────────────────────────────────────
# elementary-icon-theme is packaged natively in Fedora, but the GTK stylesheet
# itself isn't (only Arch/Ubuntu package it) — built from source per upstream's
# own instructions (meson + sassc). Upstream (8.2.2+) only ships accent-color
# variants now, no plain "io.elementary.stylesheet" theme; slate is the
# neutral/gray variant, closest to the classic elementary look.
RUN dnf5 install -y elementary-icon-theme meson ninja-build sassc \
&& dnf5 clean all \
&& ostree container commit
RUN STYLESHEET_VERSION="8.2.2" && \
curl -fsSL "https://github.com/elementary/stylesheet/archive/refs/tags/${STYLESHEET_VERSION}.tar.gz" \
| tar -xz && \
cd "stylesheet-${STYLESHEET_VERSION}" && \
meson setup build --prefix=/usr && \
ninja -C build install && \
cd .. && rm -rf "stylesheet-${STYLESHEET_VERSION}" && \
dnf5 remove -y meson ninja-build sassc \
&& dnf5 clean all \
&& ostree container commit
# ── llama.cpp — local LLM inference ──────────────────────────────────────────
# Uses official pre-built Linux x86_64 binaries (CPU backend).
# The tarball ships its own libggml*/libllama* .so files with RUNPATH=$ORIGIN,
# so binaries find their libs via /usr/lib/llama.cpp/ without needing ldconfig.
# Symlinks expose llama-cli, llama-server, and llama-bench on PATH.
#
# To switch to GPU acceleration, replace the asset selector with:
# ubuntu-vulkan-x64.tar.gz (Vulkan — Intel Iris Xe / Arc supported)
# ubuntu-sycl-fp16-x64 (SYCL — Intel GPU, requires oneAPI runtime)
#
# Pinned to a specific release rather than /releases/latest: the newest tag's
# binaries can lag behind its release-notes publish (assets still uploading,
# or the upload job failed), which leaves the API's assets[] empty and the
# release-notes body pointing at a URL that 404s. Bump LLAMA_CPP_TAG by hand
# to pick up new releases once their assets are confirmed present.
ARG LLAMA_CPP_TAG=b9870
RUN LLAMA_URL=$(curl -sL "https://api.github.com/repos/ggml-org/llama.cpp/releases/tags/${LLAMA_CPP_TAG}" | \
jq -r '.assets[] | select(.name | test("bin-ubuntu-x64\\.tar\\.gz$")) | .browser_download_url') && \
if [ -z "$LLAMA_URL" ]; then \
echo "ERROR: no ubuntu-x64 asset found for llama.cpp release ${LLAMA_CPP_TAG}" >&2; \
exit 1; \
fi && \
mkdir -p /usr/lib/llama.cpp && \
curl -fsSL "$LLAMA_URL" | tar -xz --strip-components=1 -C /usr/lib/llama.cpp && \
ln -sf /usr/lib/llama.cpp/llama-cli /usr/bin/llama-cli && \
ln -sf /usr/lib/llama.cpp/llama-server /usr/bin/llama-server && \
ln -sf /usr/lib/llama.cpp/llama-bench /usr/bin/llama-bench && \
ostree container commit