Skip to content

Commit

Permalink
Merge pull request #108952 from Mic92/systemd-builder
Browse files Browse the repository at this point in the history
nixos/systemd-boot: add typechecking
  • Loading branch information
Mic92 committed Mar 20, 2021
2 parents c612455 + ceda1a5 commit 1fc1440
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 18 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,15 @@
import datetime
import glob
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):
shutil.copyfile(source, dest)

def system_dir(profile, generation):

def system_dir(profile: Optional[str], generation: int) -> str:
if profile:
return "/nix/var/nix/profiles/system-profiles/%s-%d-link" % (profile, generation)
else:
Expand All @@ -42,7 +45,8 @@ def system_dir(profile, generation):
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:
if "@timeout@" != "":
f.write("timeout @timeout@\n")
Expand All @@ -55,10 +59,12 @@ def write_loader_conf(profile, generation):
f.write("console-mode @consoleMode@\n");
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))

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)
suffix = os.path.basename(store_file_path)
store_dir = os.path.basename(os.path.dirname(store_file_path))
Expand All @@ -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))
return efi_file_path

def describe_generation(generation_dir):

def describe_generation(generation_dir: str) -> str:
try:
with open("%s/nixos-version" % generation_dir) as f:
nixos_version = f.read()
Expand All @@ -87,7 +94,8 @@ def describe_generation(generation_dir):

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")
initrd = copy_from_profile(profile, generation, "initrd")
try:
Expand Down Expand Up @@ -116,14 +124,16 @@ def write_entry(profile, generation, machine_id):
f.write("machine-id %s\n" % machine_id)
os.rename(tmp_path, entry_file)

def mkdir_p(path):

def mkdir_p(path: str) -> None:
try:
os.makedirs(path)
except OSError as e:
if e.errno != errno.EEXIST or not os.path.isdir(path):
raise

def get_generations(profile=None):

def get_generations(profile: Optional[str] = None) -> List[Tuple[Optional[str], int]]:
gen_list = subprocess.check_output([
"@nix@/bin/nix-env",
"--list-generations",
Expand All @@ -137,7 +147,8 @@ def get_generations(profile=None):
configurationLimit = @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_generation = re.compile("^@efiSysMountPoint@/loader/entries/nixos.*-generation-(.*)\.conf$")
known_paths = []
Expand All @@ -150,24 +161,26 @@ def remove_old_entries(gens):
prof = rex_profile.sub(r"\1", path)
else:
prof = "system"
gen = int(rex_generation.sub(r"\1", path))
if not (prof, gen) in gens:
gen_number = int(rex_generation.sub(r"\1", path))
if not (prof, gen_number) in gens:
os.unlink(path)
except ValueError:
pass
for path in glob.iglob("@efiSysMountPoint@/efi/nixos/*"):
if not path in known_paths and not os.path.isdir(path):
os.unlink(path)

def get_profiles():

def get_profiles() -> List[str]:
if os.path.isdir("/nix/var/nix/profiles/system-profiles/"):
return [x
for x in os.listdir("/nix/var/nix/profiles/system-profiles/")
if not x.endswith("-link")]
else:
return []

def main():

def main() -> None:
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')
args = parser.parse_args()
Expand All @@ -182,7 +195,9 @@ def main():
# 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 = ["@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":
warnings.warn("NIXOS_INSTALL_GRUB env var deprecated, use NIXOS_INSTALL_BOOTLOADER", DeprecationWarning)
Expand Down Expand Up @@ -213,7 +228,6 @@ def main():
print("updating systemd-boot from %s to %s" % (sdboot_version, systemd_version))
subprocess.check_call(["@systemd@/bin/bootctl", "--path=@efiSysMountPoint@", "update"])


mkdir_p("@efiSysMountPoint@/efi/nixos")
mkdir_p("@efiSysMountPoint@/loader/entries")

Expand Down Expand Up @@ -252,5 +266,6 @@ def main():
if rc != 0:
print("could not sync @efiSysMountPoint@: {}".format(os.strerror(rc)), file=sys.stderr)


if __name__ == '__main__':
main()
15 changes: 13 additions & 2 deletions nixos/modules/system/boot/loader/systemd-boot/systemd-boot.nix
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ let

efi = config.boot.loader.efi;

gummibootBuilder = pkgs.substituteAll {
systemdBootBuilder = pkgs.substituteAll {
src = ./systemd-boot-builder.py;

isExecutable = true;
Expand All @@ -30,6 +30,17 @@ let

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 {

imports =
Expand Down Expand Up @@ -131,7 +142,7 @@ in {
boot.loader.supportsInitrdSecrets = true;

system = {
build.installBootLoader = gummibootBuilder;
build.installBootLoader = checkedSystemdBootBuilder;

boot.loader.id = "systemd-boot";

Expand Down

0 comments on commit 1fc1440

Please sign in to comment.