[INSTALL SPEED] Configure target keyboard without temporary boot (#93)

* Configure target keyboard without temporary boot

* Slim the offline keyboard configuration to what Omarchy consumes

Drop the Xorg 00-keyboard.conf writer: the installed system only reads
the XKB* settings in vconsole.conf (via detect-keyboard-layout.sh, which
copies XKBLAYOUT/XKBVARIANT into Hyprland's kb_layout), and nothing on
an Omarchy system reads xorg.conf.d. systemd-firstboot already writes
those vconsole settings.

Drop the set_keyboard_language monkey-patch: passing an empty kb_layout
to minimal_installation takes archinstall's documented skip path (no
nspawn boot), and the keymap is configured offline right after instead.

Append the preserved FONT= line instead of reproducing localectl's exact
file layout, and slim the tests to the behavior that matters: XKB
settings present, font preserved, every configurator keymap valid, and
archinstall-compatible invalid/empty handling.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: David Heinemeier Hansson <david@hey.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
authored and GitHub committed 2026-08-01 20:00:56 -05:00
1 parent 0b4d74f6af
commit 17532793fd
4 files changed
+146 -2

No files matched your search

@@ -0,0 +1,62 @@
"""Offline target keyboard configuration.
archinstall's set_keyboard_language boots the installed system in a
systemd-nspawn container just to run localectl. systemd-firstboot --root
produces the part of that output Omarchy actually consumes — KEYMAP for the
console plus the XKB* settings in vconsole.conf that omarchy's
detect-keyboard-layout.sh copies into Hyprland's kb_layout — without booting
anything. The Xorg 00-keyboard.conf that localectl also writes is not
generated: nothing on an Omarchy system reads it.
"""
from __future__ import annotations
import subprocess
from pathlib import Path
def configure_keyboard(target: Path, language: str) -> bool:
"""Write the console keymap into a mounted target without booting it.
Returns False for layouts localectl doesn't know (the configurator offers
two, ba and khmer), matching archinstall: warn and keep the default.
"""
if not language.strip():
return True
result = subprocess.run(
["localectl", "--no-pager", "list-keymaps"],
check=False,
text=True,
capture_output=True,
)
if result.returncode != 0:
detail = result.stderr.strip() or "localectl returned an error"
raise RuntimeError(f"Unable to list keyboard layouts: {detail}")
if language.lower() not in {layout.lower() for layout in result.stdout.splitlines()}:
return False
# systemd-firstboot --force rewrites vconsole.conf wholesale, dropping the
# FONT= line archinstall's set_vconsole wrote earlier.
vconsole_path = target / "etc" / "vconsole.conf"
font = None
if vconsole_path.exists():
font = next(
(line for line in vconsole_path.read_text().splitlines() if line.startswith("FONT=")),
None,
)
result = subprocess.run(
["systemd-firstboot", f"--root={target}", f"--keymap={language}", "--force"],
check=False,
text=True,
capture_output=True,
)
if result.returncode != 0:
detail = result.stderr.strip() or "systemd-firstboot returned an error"
raise RuntimeError(f"Unable to configure keyboard layout {language}: {detail}")
if font:
vconsole_path.write_text(vconsole_path.read_text() + font + "\n")
return True
@@ -27,11 +27,13 @@ import shutil
import subprocess
import textwrap
import time
from dataclasses import replace
from pathlib import Path
from . import archinstall_adapter as arch
from .context import InstallContext
from .ui import info
from .keyboard import configure_keyboard
from .ui import error, info
# Package targets are written by builder/build-iso.sh. Stable ISOs use the
@@ -246,6 +248,10 @@ def arch_install_system(ctx: InstallContext) -> None:
_mask_mkinitcpio_pacman_hooks(ctx)
try:
info("› installing base system (mkinitcpio deferred to final Limine UKI build)")
# An empty kb_layout makes archinstall's set_keyboard_language skip
# booting the target in a container just to run localectl; the
# keymap is configured offline right after instead.
kb_layout = config.locale_config.kb_layout if config.locale_config else ""
installer.minimal_installation(
optional_repositories=(
config.mirror_config.optional_repositories
@@ -253,10 +259,16 @@ def arch_install_system(ctx: InstallContext) -> None:
),
mkinitcpio=False,
hostname=config.hostname,
locale_config=config.locale_config,
locale_config=(
replace(config.locale_config, kb_layout="")
if config.locale_config else None
),
pacman_config=config.pacman_config,
)
if not configure_keyboard(installer.target, kb_layout):
error(f"Invalid keyboard language specified: {kb_layout}")
if config.mirror_config:
installer.set_mirrors(mirror_handler, config.mirror_config, on_target=True)
View File
Whitespace-only changes.
+70
View File
@@ -0,0 +1,70 @@
#!/usr/bin/python
import importlib.util
import re
import tempfile
import unittest
from pathlib import Path
ROOT = Path(__file__).resolve().parents[1]
MODULE_PATH = ROOT / "configs/airootfs/usr/share/omarchy-iso/orchestrator/keyboard.py"
SPEC = importlib.util.spec_from_file_location("installer_keyboard", MODULE_PATH)
KEYBOARD = importlib.util.module_from_spec(SPEC)
assert SPEC.loader
SPEC.loader.exec_module(KEYBOARD)
CONFIGURATOR = (ROOT / "configs/airootfs/root/configurator").read_text()
KEYBOARD_BLOCK = re.search(r"keyboards=\$'(.*?)'\n choice=", CONFIGURATOR, re.DOTALL)
assert KEYBOARD_BLOCK
SUPPORTED_KEYMAPS = [
line.split("|", 1)[1]
for line in KEYBOARD_BLOCK.group(1).splitlines()
]
UNSUPPORTED_KEYMAPS = {"ba", "khmer"}
class KeyboardConfigurationTest(unittest.TestCase):
def target(self, directory: str) -> Path:
target = Path(directory)
(target / "etc").mkdir()
(target / "etc/vconsole.conf").write_text(
"KEYMAP=us\nFONT=default8x16\n"
)
return target
def test_writes_keymap_and_xkb_settings_and_preserves_font(self):
# XKBLAYOUT is load-bearing: omarchy's detect-keyboard-layout.sh copies
# it into Hyprland's kb_layout on the installed system.
with tempfile.TemporaryDirectory() as directory:
target = self.target(directory)
self.assertTrue(KEYBOARD.configure_keyboard(target, "us"))
lines = (target / "etc/vconsole.conf").read_text().splitlines()
self.assertIn("KEYMAP=us", lines)
self.assertIn("XKBLAYOUT=us", lines)
self.assertEqual(lines.count("FONT=default8x16"), 1)
def test_all_configurator_keymaps_are_known_to_localectl(self):
for keymap in SUPPORTED_KEYMAPS:
with self.subTest(keymap=keymap), tempfile.TemporaryDirectory() as directory:
target = self.target(directory)
configured = KEYBOARD.configure_keyboard(target, keymap)
self.assertEqual(configured, keymap not in UNSUPPORTED_KEYMAPS)
if configured:
lines = (target / "etc/vconsole.conf").read_text().splitlines()
self.assertIn(f"KEYMAP={keymap}", lines)
self.assertEqual(lines.count("FONT=default8x16"), 1)
def test_unknown_and_empty_keymaps_match_archinstall_behavior(self):
for keymap, expected in (("definitely-not-a-keymap", False), ("", True)):
with self.subTest(keymap=keymap), tempfile.TemporaryDirectory() as directory:
target = self.target(directory)
self.assertEqual(KEYBOARD.configure_keyboard(target, keymap), expected)
self.assertEqual(
(target / "etc/vconsole.conf").read_text(),
"KEYMAP=us\nFONT=default8x16\n",
)
if __name__ == "__main__":
unittest.main()