Unverified Commit 47f3deb4 authored by tomberek's avatar tomberek Committed by GitHub
Browse files

calamares-nixos-extensions: add filesystem type chooser with btrfs support (#475297)

parents 6f766f5c d73a36d3
Loading
Loading
Loading
Loading
+14 −2
Original line number Diff line number Diff line
@@ -20,8 +20,20 @@ extraMounts:
      mountPoint: /sys/firmware/efi/efivars
      efi: true

# Ensure the right fmask/dmask is set on the ESP, as it will be
# picked up by nixos-generate-config later
# Btrfs subvolume layout for NixOS
# Empty subvolume for / means no subvolume (top-level) for GRUB compatibility
btrfsSubvolumes:
    - mountPoint: /
      subvolume: ""
    - mountPoint: /home
      subvolume: /home
    - mountPoint: /nix
      subvolume: /nix

# Mount options by filesystem type
# nixos-generate-config picks these up for hardware-configuration.nix
mountOptions:
    - filesystem: efi
      options: [ fmask=0077, dmask=0077 ]
    - filesystem: btrfs
      options: [ compress=zstd, noatime ]
+19 −1
Original line number Diff line number Diff line
@@ -12,11 +12,29 @@ userSwapChoices:

luksGeneration: luks2

defaultFileSystemType: "ext4"

availableFileSystemTypes:
    - ext4
    - btrfs
    - xfs
    - f2fs

showNotEncryptedBootMessage: false

bios:
    mountPoint: "/boot"
    minimumSize: 512MiB
    recommendedSize: 1GiB
    label: "BOOT"

partitionLayout:
    - name: "root"
    - name: "boot"
      filesystem: "ext4"
      mountPoint: "/boot"
      size: 1GiB
    - name: "root"
      filesystem: "unknown"
      noEncrypt: false
      mountPoint: "/"
      size: 100%
+87 −5
Original line number Diff line number Diff line
@@ -45,6 +45,15 @@ cfgbootbios = """ # Bootloader.

"""

cfgbootbiosbtrfs = """  # Bootloader.
  boot.loader.grub.enable = true;
  boot.loader.grub.device = "@@bootdev@@";
  boot.loader.grub.useOSProber = true;
  # Use provided UUIDs instead of blkid probing (required for btrfs subvolumes)
  boot.loader.grub.fsIdentifier = "provided";

"""

cfgbootnone = """  # Disable bootloader.
  boot.loader.grub.enable = false;

@@ -360,6 +369,46 @@ def catenate(d, key, *values):
    d[key] = "".join(values)


def fix_btrfs_subvolumes(hardware_config, partitions):
    """
    Fix btrfs subvolume configuration in hardware-configuration.nix.

    nixos-generate-config generates incorrect subvol options for btrfs
    by setting them to mount points instead of actual subvolume names.
    This function corrects the subvol options to match what Calamares configured.
    """
    # Map of mount points to their correct btrfs subvolume names
    # These match what is configured in mount.conf btrfsSubvolumes
    # Root uses top-level (no subvolume) for GRUB compatibility
    subvol_map = {
        "/home": "home",
        "/nix": "nix",
    }

    # Check if root is actually btrfs
    root_is_btrfs = False
    for part in partitions:
        if part.get("mountPoint") == "/" and part.get("fs") == "btrfs":
            root_is_btrfs = True
            break

    if not root_is_btrfs:
        return hardware_config

    libcalamares.utils.debug("Fixing btrfs subvolume configuration")

    # Fix subvol options for each mount point
    # nixos-generate-config may generate "subvol=/" instead of "subvol=@"
    for mount_point, correct_subvol in subvol_map.items():
        # Match any "subvol=<something>" and replace with correct subvolume
        # This handles cases like "subvol=/" or "subvol=/home"
        pattern = r'(fileSystems\."{}"[^;]*"subvol=)[^"]*"'.format(re.escape(mount_point))
        replacement = r'\g<1>{}"'.format(correct_subvol)
        hardware_config = re.sub(pattern, replacement, hardware_config, flags=re.DOTALL)

    return hardware_config


def run():
    """NixOS Configuration."""

@@ -388,10 +437,21 @@ def run():

    # Pick config parts and prepare substitution

    # Check if root filesystem is btrfs
    root_is_btrfs = False
    for part in gs.value("partitions"):
        if part.get("mountPoint") == "/" and part.get("fs") == "btrfs":
            root_is_btrfs = True
            break

    # Check bootloader
    if fw_type == "efi":
        cfg += cfgbootefi
    elif bootdev != "nodev":
        # Use btrfs-specific config to avoid blkid issues with subvolumes
        if root_is_btrfs:
            cfg += cfgbootbiosbtrfs
        else:
            cfg += cfgbootbios
        catenate(variables, "bootdev", bootdev)
    else:
@@ -734,9 +794,20 @@ def run():
            libcalamares.utils.error(e.output.decode("utf8"))
        return (_("nixos-generate-config failed"), _(e.output.decode("utf8")))

    # Check for unfree stuff in hardware-configuration.nix
    # Read and fix hardware-configuration.nix
    hf = open(root_mount_point + "/etc/nixos/hardware-configuration.nix", "r")
    htxt = hf.read()
    hf.close()

    hardware_modified = False

    # Fix btrfs subvolume configuration if needed
    htxt_fixed = fix_btrfs_subvolumes(htxt, gs.value("partitions"))
    if htxt_fixed != htxt:
        htxt = htxt_fixed
        hardware_modified = True

    # Check for unfree stuff in hardware-configuration.nix
    search = re.search(r"boot\.extraModulePackages = \[ (.*) \];", htxt)

    # Check if any extraModulePackages are defined, and remove if only free packages are allowed
@@ -765,14 +836,17 @@ def run():
                    )
                )
                expkgs.remove(pkg)
        hardwareout = re.sub(
        htxt = re.sub(
            r"boot\.extraModulePackages = \[ (.*) \];",
            "boot.extraModulePackages = [ {}];".format(
                "".join(map(lambda x: x + " ", expkgs))
            ),
            htxt,
        )
        # Write the hardware-configuration.nix file
        hardware_modified = True

    # Write the hardware-configuration.nix file if modified
    if hardware_modified:
        libcalamares.utils.host_env_process_output(
            [
                "cp",
@@ -780,7 +854,7 @@ def run():
                root_mount_point + "/etc/nixos/hardware-configuration.nix",
            ],
            None,
            hardwareout,
            htxt,
        )

    # Write the configuration.nix file
@@ -789,6 +863,14 @@ def run():
    status = _("Installing NixOS")
    libcalamares.job.setprogress(0.3)

    try:
        subprocess.check_output(
            ["pkexec", "chmod", "755", root_mount_point],
            stderr=subprocess.STDOUT,
        )
    except subprocess.CalledProcessError as e:
        libcalamares.utils.warning("Failed to set permissions on {}: {}".format(root_mount_point, e.output))

    # build nixos-install command
    nixosInstallCmd = [ "pkexec" ]
    nixosInstallCmd.extend(generateProxyStrings())