nixos/systemd-boot: add typechecking
This commit is contained in:
parent
2cfa110ae8
commit
ceda1a5eee
2 changed files with 44 additions and 18 deletions
|
@ -15,12 +15,15 @@ import re
|
||||||
import datetime
|
import datetime
|
||||||
import glob
|
import glob
|
||||||
import os.path
|
import os.path
|
||||||
|
from typing import Tuple, List, Optional
|
||||||
|
|
||||||
def copy_if_not_exists(source, dest):
|
|
||||||
|
def copy_if_not_exists(source: str, dest: str) -> None:
|
||||||
if not os.path.exists(dest):
|
if not os.path.exists(dest):
|
||||||
shutil.copyfile(source, dest)
|
shutil.copyfile(source, dest)
|
||||||
|
|
||||||
def system_dir(profile, generation):
|
|
||||||
|
def system_dir(profile: Optional[str], generation: int) -> str:
|
||||||
if profile:
|
if profile:
|
||||||
return "/nix/var/nix/profiles/system-profiles/%s-%d-link" % (profile, generation)
|
return "/nix/var/nix/profiles/system-profiles/%s-%d-link" % (profile, generation)
|
||||||
else:
|
else:
|
||||||
|
@ -42,7 +45,8 @@ MEMTEST_BOOT_ENTRY = """title MemTest86
|
||||||
efi /efi/memtest86/BOOTX64.efi
|
efi /efi/memtest86/BOOTX64.efi
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def write_loader_conf(profile, generation):
|
|
||||||
|
def write_loader_conf(profile: Optional[str], generation: int) -> None:
|
||||||
with open("@efiSysMountPoint@/loader/loader.conf.tmp", 'w') as f:
|
with open("@efiSysMountPoint@/loader/loader.conf.tmp", 'w') as f:
|
||||||
if "@timeout@" != "":
|
if "@timeout@" != "":
|
||||||
f.write("timeout @timeout@\n")
|
f.write("timeout @timeout@\n")
|
||||||
|
@ -55,10 +59,12 @@ def write_loader_conf(profile, generation):
|
||||||
f.write("console-mode @consoleMode@\n");
|
f.write("console-mode @consoleMode@\n");
|
||||||
os.rename("@efiSysMountPoint@/loader/loader.conf.tmp", "@efiSysMountPoint@/loader/loader.conf")
|
os.rename("@efiSysMountPoint@/loader/loader.conf.tmp", "@efiSysMountPoint@/loader/loader.conf")
|
||||||
|
|
||||||
def profile_path(profile, generation, name):
|
|
||||||
|
def profile_path(profile: Optional[str], generation: int, name: str) -> str:
|
||||||
return os.readlink("%s/%s" % (system_dir(profile, generation), name))
|
return os.readlink("%s/%s" % (system_dir(profile, generation), name))
|
||||||
|
|
||||||
def copy_from_profile(profile, generation, name, dry_run=False):
|
|
||||||
|
def copy_from_profile(profile: Optional[str], generation: int, name: str, dry_run: bool = False) -> str:
|
||||||
store_file_path = profile_path(profile, generation, name)
|
store_file_path = profile_path(profile, generation, name)
|
||||||
suffix = os.path.basename(store_file_path)
|
suffix = os.path.basename(store_file_path)
|
||||||
store_dir = os.path.basename(os.path.dirname(store_file_path))
|
store_dir = os.path.basename(os.path.dirname(store_file_path))
|
||||||
|
@ -67,7 +73,8 @@ def copy_from_profile(profile, generation, name, dry_run=False):
|
||||||
copy_if_not_exists(store_file_path, "@efiSysMountPoint@%s" % (efi_file_path))
|
copy_if_not_exists(store_file_path, "@efiSysMountPoint@%s" % (efi_file_path))
|
||||||
return efi_file_path
|
return efi_file_path
|
||||||
|
|
||||||
def describe_generation(generation_dir):
|
|
||||||
|
def describe_generation(generation_dir: str) -> str:
|
||||||
try:
|
try:
|
||||||
with open("%s/nixos-version" % generation_dir) as f:
|
with open("%s/nixos-version" % generation_dir) as f:
|
||||||
nixos_version = f.read()
|
nixos_version = f.read()
|
||||||
|
@ -87,7 +94,8 @@ def describe_generation(generation_dir):
|
||||||
|
|
||||||
return description
|
return description
|
||||||
|
|
||||||
def write_entry(profile, generation, machine_id):
|
|
||||||
|
def write_entry(profile: Optional[str], generation: int, machine_id: str) -> None:
|
||||||
kernel = copy_from_profile(profile, generation, "kernel")
|
kernel = copy_from_profile(profile, generation, "kernel")
|
||||||
initrd = copy_from_profile(profile, generation, "initrd")
|
initrd = copy_from_profile(profile, generation, "initrd")
|
||||||
try:
|
try:
|
||||||
|
@ -116,14 +124,16 @@ def write_entry(profile, generation, machine_id):
|
||||||
f.write("machine-id %s\n" % machine_id)
|
f.write("machine-id %s\n" % machine_id)
|
||||||
os.rename(tmp_path, entry_file)
|
os.rename(tmp_path, entry_file)
|
||||||
|
|
||||||
def mkdir_p(path):
|
|
||||||
|
def mkdir_p(path: str) -> None:
|
||||||
try:
|
try:
|
||||||
os.makedirs(path)
|
os.makedirs(path)
|
||||||
except OSError as e:
|
except OSError as e:
|
||||||
if e.errno != errno.EEXIST or not os.path.isdir(path):
|
if e.errno != errno.EEXIST or not os.path.isdir(path):
|
||||||
raise
|
raise
|
||||||
|
|
||||||
def get_generations(profile=None):
|
|
||||||
|
def get_generations(profile: Optional[str] = None) -> List[Tuple[Optional[str], int]]:
|
||||||
gen_list = subprocess.check_output([
|
gen_list = subprocess.check_output([
|
||||||
"@nix@/bin/nix-env",
|
"@nix@/bin/nix-env",
|
||||||
"--list-generations",
|
"--list-generations",
|
||||||
|
@ -137,7 +147,8 @@ def get_generations(profile=None):
|
||||||
configurationLimit = @configurationLimit@
|
configurationLimit = @configurationLimit@
|
||||||
return [ (profile, int(line.split()[0])) for line in gen_lines ][-configurationLimit:]
|
return [ (profile, int(line.split()[0])) for line in gen_lines ][-configurationLimit:]
|
||||||
|
|
||||||
def remove_old_entries(gens):
|
|
||||||
|
def remove_old_entries(gens: List[Tuple[Optional[str], int]]) -> None:
|
||||||
rex_profile = re.compile("^@efiSysMountPoint@/loader/entries/nixos-(.*)-generation-.*\.conf$")
|
rex_profile = re.compile("^@efiSysMountPoint@/loader/entries/nixos-(.*)-generation-.*\.conf$")
|
||||||
rex_generation = re.compile("^@efiSysMountPoint@/loader/entries/nixos.*-generation-(.*)\.conf$")
|
rex_generation = re.compile("^@efiSysMountPoint@/loader/entries/nixos.*-generation-(.*)\.conf$")
|
||||||
known_paths = []
|
known_paths = []
|
||||||
|
@ -150,8 +161,8 @@ def remove_old_entries(gens):
|
||||||
prof = rex_profile.sub(r"\1", path)
|
prof = rex_profile.sub(r"\1", path)
|
||||||
else:
|
else:
|
||||||
prof = "system"
|
prof = "system"
|
||||||
gen = int(rex_generation.sub(r"\1", path))
|
gen_number = int(rex_generation.sub(r"\1", path))
|
||||||
if not (prof, gen) in gens:
|
if not (prof, gen_number) in gens:
|
||||||
os.unlink(path)
|
os.unlink(path)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
pass
|
pass
|
||||||
|
@ -159,7 +170,8 @@ def remove_old_entries(gens):
|
||||||
if not path in known_paths and not os.path.isdir(path):
|
if not path in known_paths and not os.path.isdir(path):
|
||||||
os.unlink(path)
|
os.unlink(path)
|
||||||
|
|
||||||
def get_profiles():
|
|
||||||
|
def get_profiles() -> List[str]:
|
||||||
if os.path.isdir("/nix/var/nix/profiles/system-profiles/"):
|
if os.path.isdir("/nix/var/nix/profiles/system-profiles/"):
|
||||||
return [x
|
return [x
|
||||||
for x in os.listdir("/nix/var/nix/profiles/system-profiles/")
|
for x in os.listdir("/nix/var/nix/profiles/system-profiles/")
|
||||||
|
@ -167,7 +179,8 @@ def get_profiles():
|
||||||
else:
|
else:
|
||||||
return []
|
return []
|
||||||
|
|
||||||
def main():
|
|
||||||
|
def main() -> None:
|
||||||
parser = argparse.ArgumentParser(description='Update NixOS-related systemd-boot files')
|
parser = argparse.ArgumentParser(description='Update NixOS-related systemd-boot files')
|
||||||
parser.add_argument('default_config', metavar='DEFAULT-CONFIG', help='The default NixOS config to boot')
|
parser.add_argument('default_config', metavar='DEFAULT-CONFIG', help='The default NixOS config to boot')
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
@ -182,7 +195,9 @@ def main():
|
||||||
# be there on newly installed systems, so let's generate one so that
|
# 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.
|
# bootctl can find it and we can also pass it to write_entry() later.
|
||||||
cmd = ["@systemd@/bin/systemd-machine-id-setup", "--print"]
|
cmd = ["@systemd@/bin/systemd-machine-id-setup", "--print"]
|
||||||
machine_id = subprocess.check_output(cmd).rstrip()
|
machine_id = subprocess.run(
|
||||||
|
cmd, text=True, check=True, stdout=subprocess.PIPE
|
||||||
|
).stdout.rstrip()
|
||||||
|
|
||||||
if os.getenv("NIXOS_INSTALL_GRUB") == "1":
|
if os.getenv("NIXOS_INSTALL_GRUB") == "1":
|
||||||
warnings.warn("NIXOS_INSTALL_GRUB env var deprecated, use NIXOS_INSTALL_BOOTLOADER", DeprecationWarning)
|
warnings.warn("NIXOS_INSTALL_GRUB env var deprecated, use NIXOS_INSTALL_BOOTLOADER", DeprecationWarning)
|
||||||
|
@ -213,7 +228,6 @@ def main():
|
||||||
print("updating systemd-boot from %s to %s" % (sdboot_version, systemd_version))
|
print("updating systemd-boot from %s to %s" % (sdboot_version, systemd_version))
|
||||||
subprocess.check_call(["@systemd@/bin/bootctl", "--path=@efiSysMountPoint@", "update"])
|
subprocess.check_call(["@systemd@/bin/bootctl", "--path=@efiSysMountPoint@", "update"])
|
||||||
|
|
||||||
|
|
||||||
mkdir_p("@efiSysMountPoint@/efi/nixos")
|
mkdir_p("@efiSysMountPoint@/efi/nixos")
|
||||||
mkdir_p("@efiSysMountPoint@/loader/entries")
|
mkdir_p("@efiSysMountPoint@/loader/entries")
|
||||||
|
|
||||||
|
@ -252,5 +266,6 @@ def main():
|
||||||
if rc != 0:
|
if rc != 0:
|
||||||
print("could not sync @efiSysMountPoint@: {}".format(os.strerror(rc)), file=sys.stderr)
|
print("could not sync @efiSysMountPoint@: {}".format(os.strerror(rc)), file=sys.stderr)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
main()
|
main()
|
||||||
|
|
|
@ -7,7 +7,7 @@ let
|
||||||
|
|
||||||
efi = config.boot.loader.efi;
|
efi = config.boot.loader.efi;
|
||||||
|
|
||||||
gummibootBuilder = pkgs.substituteAll {
|
systemdBootBuilder = pkgs.substituteAll {
|
||||||
src = ./systemd-boot-builder.py;
|
src = ./systemd-boot-builder.py;
|
||||||
|
|
||||||
isExecutable = true;
|
isExecutable = true;
|
||||||
|
@ -30,6 +30,17 @@ let
|
||||||
|
|
||||||
memtest86 = if cfg.memtest86.enable then pkgs.memtest86-efi else "";
|
memtest86 = if cfg.memtest86.enable then pkgs.memtest86-efi else "";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
checkedSystemdBootBuilder = pkgs.runCommand "systemd-boot" {
|
||||||
|
nativeBuildInputs = [ pkgs.mypy ];
|
||||||
|
} ''
|
||||||
|
install -m755 ${systemdBootBuilder} $out
|
||||||
|
mypy \
|
||||||
|
--no-implicit-optional \
|
||||||
|
--disallow-untyped-calls \
|
||||||
|
--disallow-untyped-defs \
|
||||||
|
$out
|
||||||
|
'';
|
||||||
in {
|
in {
|
||||||
|
|
||||||
imports =
|
imports =
|
||||||
|
@ -131,7 +142,7 @@ in {
|
||||||
boot.loader.supportsInitrdSecrets = true;
|
boot.loader.supportsInitrdSecrets = true;
|
||||||
|
|
||||||
system = {
|
system = {
|
||||||
build.installBootLoader = gummibootBuilder;
|
build.installBootLoader = checkedSystemdBootBuilder;
|
||||||
|
|
||||||
boot.loader.id = "systemd-boot";
|
boot.loader.id = "systemd-boot";
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue