Skip to content

Commit

Permalink
Merge pull request #323421 from Mic92/systemd-boot-builder
Browse files Browse the repository at this point in the history
  • Loading branch information
JulienMalka authored Jul 7, 2024
2 parents c7411f7 + ebfee30 commit 6701c2c
Showing 1 changed file with 56 additions and 33 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
import sys
import warnings
import json
from typing import NamedTuple, Dict, List
from typing import NamedTuple, Any
from dataclasses import dataclass

# These values will be replaced with actual values during the package build
Expand All @@ -21,7 +21,7 @@
LOADER_CONF = f"{EFI_SYS_MOUNT_POINT}/loader/loader.conf" # Always stored on the ESP
NIXOS_DIR = "@nixosDir@"
TIMEOUT = "@timeout@"
EDITOR = "@editor@" == "1"
EDITOR = "@editor@" == "1" # noqa: PLR0133
CONSOLE_MODE = "@consoleMode@"
BOOTSPEC_TOOLS = "@bootspecTools@"
DISTRO_NAME = "@distroName@"
Expand All @@ -38,17 +38,22 @@ class BootSpec:
init: str
initrd: str
kernel: str
kernelParams: List[str]
kernelParams: list[str] # noqa: N815
label: str
system: str
toplevel: str
specialisations: Dict[str, "BootSpec"]
sortKey: str
initrdSecrets: str | None = None
specialisations: dict[str, "BootSpec"]
sortKey: str # noqa: N815
initrdSecrets: str | None = None # noqa: N815


libc = ctypes.CDLL("libc.so.6")

FILE = None | int

def run(cmd: list[str], stdout: FILE = None) -> subprocess.CompletedProcess[str]:
return subprocess.run(cmd, check=True, text=True, stdout=stdout)

class SystemIdentifier(NamedTuple):
profile: str | None
generation: int
Expand Down Expand Up @@ -112,17 +117,20 @@ def get_bootspec(profile: str | None, generation: int) -> BootSpec:
boot_json_f = open(boot_json_path, 'r')
bootspec_json = json.load(boot_json_f)
else:
boot_json_str = subprocess.check_output([
f"{BOOTSPEC_TOOLS}/bin/synthesize",
"--version",
"1",
system_directory,
"/dev/stdout"],
universal_newlines=True)
boot_json_str = run(
[
f"{BOOTSPEC_TOOLS}/bin/synthesize",
"--version",
"1",
system_directory,
"/dev/stdout",
],
stdout=subprocess.PIPE,
).stdout
bootspec_json = json.loads(boot_json_str)
return bootspec_from_json(bootspec_json)

def bootspec_from_json(bootspec_json: Dict) -> BootSpec:
def bootspec_from_json(bootspec_json: dict[str, Any]) -> BootSpec:
specialisations = bootspec_json['org.nixos.specialisation.v1']
specialisations = {k: bootspec_from_json(v) for k, v in specialisations.items()}
systemdBootExtension = bootspec_json.get('org.nixos.systemd-boot', {})
Expand Down Expand Up @@ -157,7 +165,7 @@ def write_entry(profile: str | None, generation: int, specialisation: str | None

try:
if bootspec.initrdSecrets is not None:
subprocess.check_call([bootspec.initrdSecrets, f"{BOOT_MOUNT_POINT}%s" % (initrd)])
run([bootspec.initrdSecrets, f"{BOOT_MOUNT_POINT}%s" % (initrd)])
except subprocess.CalledProcessError:
if current:
print("failed to create initrd secrets!", file=sys.stderr)
Expand Down Expand Up @@ -192,13 +200,17 @@ def write_entry(profile: str | None, generation: int, specialisation: str | None


def get_generations(profile: str | None = None) -> list[SystemIdentifier]:
gen_list = subprocess.check_output([
f"{NIX}/bin/nix-env",
"--list-generations",
"-p",
"/nix/var/nix/profiles/%s" % ("system-profiles/" + profile if profile else "system")],
universal_newlines=True)
gen_lines = gen_list.split('\n')
gen_list = run(
[
f"{NIX}/bin/nix-env",
"--list-generations",
"-p",
"/nix/var/nix/profiles/%s"
% ("system-profiles/" + profile if profile else "system"),
],
stdout=subprocess.PIPE,
).stdout
gen_lines = gen_list.split("\n")
gen_lines.pop()

configurationLimit = CONFIGURATION_LIMIT
Expand Down Expand Up @@ -230,10 +242,10 @@ def remove_old_entries(gens: list[SystemIdentifier]) -> None:
gen_number = int(rex_generation.sub(r"\1", path))
except ValueError:
continue
if not (prof, gen_number, None) in gens:
if (prof, gen_number, None) not in gens:
os.unlink(path)
for path in glob.iglob(f"{BOOT_MOUNT_POINT}/{NIXOS_DIR}/*"):
if not path in known_paths and not os.path.isdir(path):
if path not in known_paths and not os.path.isdir(path):
os.unlink(path)


Expand Down Expand Up @@ -263,9 +275,7 @@ def install_bootloader(args: argparse.Namespace) -> None:
# be there on newly installed systems, so let's generate one so that
# bootctl can find it and we can also pass it to write_entry() later.
cmd = [f"{SYSTEMD}/bin/systemd-machine-id-setup", "--print"]
machine_id = subprocess.run(
cmd, text=True, check=True, stdout=subprocess.PIPE
).stdout.rstrip()
machine_id = run(cmd, stdout=subprocess.PIPE).stdout.rstrip()

if os.getenv("NIXOS_INSTALL_GRUB") == "1":
warnings.warn("NIXOS_INSTALL_GRUB env var deprecated, use NIXOS_INSTALL_BOOTLOADER", DeprecationWarning)
Expand All @@ -288,11 +298,20 @@ def install_bootloader(args: argparse.Namespace) -> None:
if os.path.exists(LOADER_CONF):
os.unlink(LOADER_CONF)

subprocess.check_call([f"{SYSTEMD}/bin/bootctl", f"--esp-path={EFI_SYS_MOUNT_POINT}"] + bootctl_flags + ["install"])
run(
[f"{SYSTEMD}/bin/bootctl", f"--esp-path={EFI_SYS_MOUNT_POINT}"]
+ bootctl_flags
+ ["install"]
)
else:
# Update bootloader to latest if needed
available_out = subprocess.check_output([f"{SYSTEMD}/bin/bootctl", "--version"], universal_newlines=True).split()[2]
installed_out = subprocess.check_output([f"{SYSTEMD}/bin/bootctl", f"--esp-path={EFI_SYS_MOUNT_POINT}", "status"], universal_newlines=True)
available_out = run(
[f"{SYSTEMD}/bin/bootctl", "--version"], stdout=subprocess.PIPE
).stdout.split()[2]
installed_out = run(
[f"{SYSTEMD}/bin/bootctl", f"--esp-path={EFI_SYS_MOUNT_POINT}", "status"],
stdout=subprocess.PIPE,
).stdout

# See status_binaries() in systemd bootctl.c for code which generates this
installed_match = re.search(r"^\W+File:.*/EFI/(?:BOOT|systemd)/.*\.efi \(systemd-boot ([\d.]+[^)]*)\)$",
Expand All @@ -311,7 +330,11 @@ def install_bootloader(args: argparse.Namespace) -> None:

if installed_version < available_version:
print("updating systemd-boot from %s to %s" % (installed_version, available_version))
subprocess.check_call([f"{SYSTEMD}/bin/bootctl", f"--esp-path={EFI_SYS_MOUNT_POINT}"] + bootctl_flags + ["update"])
run(
[f"{SYSTEMD}/bin/bootctl", f"--esp-path={EFI_SYS_MOUNT_POINT}"]
+ bootctl_flags
+ ["update"]
)

os.makedirs(f"{BOOT_MOUNT_POINT}/{NIXOS_DIR}", exist_ok=True)
os.makedirs(f"{BOOT_MOUNT_POINT}/loader/entries", exist_ok=True)
Expand Down Expand Up @@ -362,15 +385,15 @@ def install_bootloader(args: argparse.Namespace) -> None:

os.makedirs(f"{BOOT_MOUNT_POINT}/{NIXOS_DIR}/.extra-files", exist_ok=True)

subprocess.check_call(COPY_EXTRA_FILES)
run([COPY_EXTRA_FILES])


def main() -> None:
parser = argparse.ArgumentParser(description=f"Update {DISTRO_NAME}-related systemd-boot files")
parser.add_argument('default_config', metavar='DEFAULT-CONFIG', help=f"The default {DISTRO_NAME} config to boot")
args = parser.parse_args()

subprocess.check_call(CHECK_MOUNTPOINTS)
run([CHECK_MOUNTPOINTS])

try:
install_bootloader(args)
Expand Down

0 comments on commit 6701c2c

Please sign in to comment.