Merge omacom/omarchy-iso#241: region from the timezone in one ISO

Drop our --region build, prepare-region.sh, region skel, the preselected
China timezone, the explicit region in the configurator's JSON, Rime
bundling and its pin.
This commit is contained in:
ZacharyZhang-NY committed 2026-10-09 00:03:17 -04:00
commit 75d00a2036
14 files changed
+409 -618

No files matched your search

@@ -12,6 +12,7 @@ from pathlib import Path
from typing import Any
from .keyboard import validate_input_selection
from .region import GLOBAL, resolve_region
@dataclass
@@ -29,6 +30,7 @@ class InstallContext:
arch_config_path: Path
omarchy_install: dict[str, Any]
defer_provisioning: bool = False
region: str = GLOBAL
target: Path = Path("/mnt")
omarchy_path: Path = Path("/usr/share/omarchy")
@@ -61,6 +63,11 @@ class InstallContext:
validate_input_selection(omarchy_install.get("input_method"), omarchy_install.get("input_xkb_layout", ""))
# Resolved before any disk is touched, so an autoinstall naming a
# region this ISO lacks fails without wiping anything.
region = resolve_region(omarchy_install, user_configuration.get("timezone"))
omarchy_install["region"] = region
# Deferred provisioning: the whole system installs but user creation is deferred to
# first boot. Selected by the configurator (omarchy_install.defer_provisioning) or by
# an `defer-provisioning` marker file on an autoinstall drive, which also replaces the
@@ -69,12 +76,6 @@ class InstallContext:
defer_provisioning = bool(omarchy_install.get("defer_provisioning")) or defer_provisioning_marker is not None
omarchy_install["defer_provisioning"] = defer_provisioning
# Autoinstall configs written before regions existed install Global.
region = omarchy_install.get("region", "global")
if region not in ("global", "cn"):
raise RuntimeError(f"omarchy_install.region must be global or cn, not {region!r}")
omarchy_install["region"] = region
if creds_path.exists():
user_credentials = json.loads(creds_path.read_text())
elif defer_provisioning:
@@ -131,6 +132,7 @@ class InstallContext:
arch_config_path=arch_config_path,
omarchy_install=omarchy_install,
defer_provisioning=defer_provisioning,
region=region,
state_dir=state_dir,
)
disk_config = user_configuration.get("disk_config", {})
@@ -36,35 +36,10 @@ from . import archinstall_adapter as arch
from .command import capture, capture_identifier, require_text
from .context import InstallContext
from .keyboard import configure_keyboard
from .region import GLOBAL, region_keyrings, region_packages
from .ui import error, info
ISO_REGION_PAYLOAD = Path("/usr/share/omarchy-iso/region")
def _region_packages(ctx: InstallContext) -> list[str]:
if ctx.omarchy_install["region"] != "cn":
return []
lines = (ISO_REGION_PAYLOAD / "packages").read_text().splitlines()
return [s for s in (raw.strip() for raw in lines) if s and not s.startswith("#")]
def _stage_region_defaults(ctx: InstallContext) -> None:
"""Seed the target before useradd, including deferred first-boot users.
Region is a bootstrap default, not a locale or a user-level policy.
Existing home directories are never rewritten by this step.
"""
region = ctx.omarchy_install["region"]
skel = ISO_REGION_PAYLOAD / "skel"
if region == "cn" and skel.is_dir():
shutil.copytree(skel, ctx.target / "etc/skel", dirs_exist_ok=True)
marker = ctx.target / "etc/omarchy/region"
marker.parent.mkdir(parents=True, exist_ok=True)
marker.write_text(region + "\n")
marker.chmod(0o644)
# Package targets are written by builder/build-iso.sh. Stable ISOs use the
# stable package names, while dev/local-source ISOs install the dev package
# names explicitly instead of relying on provides=omarchy resolution.
@@ -313,7 +288,6 @@ def arch_install_system(ctx: InstallContext) -> None:
_install_early_packages(installer)
_configure_limine_boot(ctx, installer, config)
_stage_region_defaults(ctx)
info("› creating user (with /etc/skel populated)")
if config.auth_config and config.auth_config.users:
installer.create_users(config.auth_config.users)
@@ -325,6 +299,11 @@ def arch_install_system(ctx: InstallContext) -> None:
info("› installing Omarchy runtime + omarchy-base.packages")
installer.add_additional_packages(_runtime_package_list(ctx))
if region_pkgs := region_packages(ctx.region):
info(f"› installing {ctx.region} region packages: {', '.join(region_pkgs)}")
installer.add_additional_packages(region_pkgs)
_write_region_marker(ctx)
# Tailscale is bundled in the offline mirror but only installed
# when an autoinstall drive staged an auth key; must happen here,
# while the mirror is still bind-mounted, not in the phase that
@@ -755,6 +734,17 @@ def _unmask_mkinitcpio_pacman_hooks(
info(f"warning: failed to restore pacman hook mask for {name}: {exc}")
def _write_region_marker(ctx: InstallContext) -> None:
"""Tell the runtime's pacman finalizer which profile to apply. Global
installs write nothing, so they stay identical to a region-less install."""
if ctx.region == GLOBAL:
return
marker = ctx.target / "etc/omarchy/region"
marker.parent.mkdir(parents=True, exist_ok=True)
marker.write_text(ctx.region + "\n")
marker.chmod(0o644)
def _runtime_package_list(ctx: InstallContext) -> list[str]:
"""Selected Omarchy runtime package + every package in the ISO-bundled
base package list that isn't already installed early."""
@@ -774,10 +764,6 @@ def _runtime_package_list(ctx: InstallContext) -> list[str]:
continue
if s not in already_installed and s not in pkgs:
pkgs.append(s)
pkgs += [p for p in _region_packages(ctx) if p not in pkgs]
# Local builds live only in this ISO's mirror; a later region switch could not fetch them.
if PINNED_PACKAGES.exists():
pkgs += [p for p in PINNED_PACKAGES.read_text().split() if p not in already_installed and p not in pkgs]
return pkgs
@@ -1129,7 +1115,6 @@ def _run_target_setup_command(ctx: InstallContext, cmd: list[str], *, user: str
f"OMARCHY_USER_NAME={ctx.full_name}",
f"OMARCHY_USER_EMAIL={ctx.email}",
f"OMARCHY_MIRROR={mirror_channel}",
f"OMARCHY_REGION={ctx.omarchy_install['region']}",
f"OMARCHY_ISO_REF={_iso_ref()}",
f"OMARCHY_RUNTIME_PACKAGE={_omarchy_runtime_package()}",
f"OMARCHY_SETTINGS_PACKAGE={_omarchy_settings_package()}",
@@ -1167,12 +1152,13 @@ def _run_target_setup_command(ctx: InstallContext, cmd: list[str], *, user: str
def run_system_finalizer(ctx: InstallContext) -> None:
# The runtime package transaction has installed the regional keyring from
# the ISO. Initialize the target's trust database before enabling the online
# community repository; the build container's GPG state is not inherited.
if ctx.omarchy_install["region"] == "cn":
# The region's keyring packages are installed by now, but the build
# container's GPG state is not inherited. Initialize the target's trust
# database with only this region's keys before the finalizer enables its
# online repositories; global installs never trust them.
if keyrings := region_keyrings(ctx.region):
_run_target_setup_command(ctx, ["pacman-key", "--init"])
_run_target_setup_command(ctx, ["pacman-key", "--populate", "archlinux", "archlinuxcn"])
_run_target_setup_command(ctx, ["pacman-key", "--populate", "archlinux", *keyrings])
if ctx.defer_provisioning:
cmd = ["/usr/bin/omarchy-apply-system", "--defer-provisioning", "--first-install"]
@@ -1414,7 +1400,6 @@ def run_chroot_finalizer(ctx: InstallContext) -> None:
)
PINNED_PACKAGES = Path("/usr/share/omarchy-iso/pinned-packages")
PIN_HOOK_SCRIPT = """#!/bin/bash
@@ -0,0 +1,68 @@
"""Region selection: which of the runtime's region profiles a target gets.
The builder copies every profile from the bundled runtime's default/regions/
into REGIONS_DIR, and their packages into the offline mirror. Nobody picks a
region by hand: the timezone the user already chose selects it, and an
autoinstall config may name one explicitly in omarchy_install.region. Run as
`python -m orchestrator.region <timezone>` to print the region the installer
would use, which is how the configurator fills its summary.
"""
from __future__ import annotations
import re
import sys
from pathlib import Path
REGIONS_DIR = Path("/usr/share/omarchy-iso/regions")
GLOBAL = "global"
def _entries(path: Path) -> list[str]:
if not path.is_file():
return []
lines = (line.strip() for line in path.read_text().splitlines())
return [line for line in lines if line and not line.startswith("#")]
def region_for_timezone(timezone: str | None, regions_dir: Path | None = None) -> str:
regions_dir = regions_dir or REGIONS_DIR
if timezone and regions_dir.is_dir():
for profile in sorted(regions_dir.iterdir()):
if timezone in _entries(profile / "timezones"):
return profile.name
return GLOBAL
def resolve_region(omarchy_install: dict, timezone: str | None, regions_dir: Path | None = None) -> str:
regions_dir = regions_dir or REGIONS_DIR
region = omarchy_install.get("region")
if region is None or region == "":
return region_for_timezone(timezone, regions_dir)
# Profiles are named by ISO 3166-1 alpha-2 code; checking the shape first
# keeps a path like ".." from passing the directory test.
if not isinstance(region, str) or (
region != GLOBAL and not (re.fullmatch(r"[a-z]{2}", region) and (regions_dir / region).is_dir())
):
raise RuntimeError(f"Unsupported region: {region!r}")
return region
def region_packages(region: str, regions_dir: Path | None = None) -> list[str]:
if region == GLOBAL:
return []
return _entries((regions_dir or REGIONS_DIR) / region / "packages")
def region_keyrings(region: str, regions_dir: Path | None = None) -> list[str]:
"""Pacman keyrings the profile ships, named the Arch way: <name>-keyring
installs /usr/share/pacman/keyrings/<name>.gpg."""
return [
package.removesuffix("-keyring")
for package in region_packages(region, regions_dir)
if package.endswith("-keyring")
]
if __name__ == "__main__":
print(region_for_timezone(sys.argv[1] if len(sys.argv) > 1 else None))