···4040}4141```42424343-## Nix Store Partition {#sec-image-repart-store-partition}4343+## Nix Store Paths {#sec-image-repart-store-paths}4444+4545+If you want to rewrite Nix store paths, e.g., to remove the `/nix/store` prefix4646+or to nest it below a parent path, you can do that through the4747+`nixStorePrefix` option.4848+4949+### Nix Store Partition {#sec-image-repart-store-partition}44504551You can define a partition that only contains the Nix store and then mount it4652under `/nix/store`. Because the `/nix/store` part of the paths is already4747-determined by the mount point, you have to set `stripNixStorePrefix = true;` so4848-that the prefix is stripped from the paths before copying them into the image.5353+determined by the mount point, you have to set `nixStorePrefix = "/"` so5454+that `/nix/store` is stripped from the paths before copying them into the image.49555056```nix5157{···6054 image.repart.partitions = {6155 "store" = {6256 storePaths = [ config.system.build.toplevel ];6363- stripNixStorePrefix = true;5757+ nixStorePrefix = "/";6458 repartConfig = {6559 Type = "linux-generic";6660 Label = "nix-store";6161+ # ...6262+ };6363+ };6464+ };6565+}6666+```6767+6868+### Nix Store Subvolume {#sec-image-repart-store-subvolume}6969+7070+Alternatively, you can create a Btrfs subvolume `/@nix-store` containing the7171+Nix store and mount it on `/nix/store`:7272+7373+```nix7474+{7575+ fileSystems."/" = {7676+ device = "/dev/disk/by-partlabel/root";7777+ fsType = "btrfs";7878+ options = [ "subvol=/@" ];7979+ };8080+8181+ fileSystems."/nix/store" = {8282+ device = "/dev/disk/by-partlabel/root";8383+ fsType = "btrfs";8484+ options = [ "subvol=/@nix-store" ];8585+ };8686+8787+ image.repart.partitions = {8888+ "root" = {8989+ storePaths = [ config.system.build.toplevel ];9090+ nixStorePrefix = "/@nix-store";9191+ repartConfig = {9292+ Type = "root";9393+ Label = "root";9494+ Format = "btrfs";9595+ Subvolumes = "/@ /@nix-store";9696+ MakeDirectories = "/@ /@nix-store";6797 # ...6898 };6999 };
···363637373838def add_closure_to_definition(3939- definition: Path, closure: Path | None, strip_nix_store_prefix: bool | None3939+ definition: Path, closure: Path | None, nix_store_prefix: str | None4040) -> None:4141 """Add CopyFiles= instructions to a definition for all paths in the closure.42424343- If strip_nix_store_prefix is True, `/nix/store` is stripped from the target path.4343+ Replace `/nix/store` with the value of nix_store_prefix.4444 """4545 if not closure:4646 return···5252 continue53535454 source = Path(line.strip())5555- target = str(source.relative_to("/nix/store/"))5656- target = f":/{target}" if strip_nix_store_prefix else ""5555+ option = f"CopyFiles={source}"5656+ if nix_store_prefix:5757+ target = nix_store_prefix / source.relative_to("/nix/store/")5858+ option = f"{option}:{target}"57595858- copy_files_lines.append(f"CopyFiles={source}{target}\n")6060+ copy_files_lines.append(f"{option}\n")59616062 with open(definition, "a") as f:6163 f.writelines(copy_files_lines)···104102 add_contents_to_definition(definition, contents)105103106104 closure = config.get("closure")107107- strip_nix_store_prefix = config.get("stripNixStorePrefix")108108- add_closure_to_definition(definition, closure, strip_nix_store_prefix)105105+ nix_store_prefix = config.get("nixStorePrefix")106106+ add_closure_to_definition(definition, closure, nix_store_prefix)109107110108 print(target_dir.absolute())111109
+91-74
nixos/modules/image/repart.nix
···15151616 inherit (utils.systemdUtils.lib) GPTMaxLabelLength;17171818- partitionOptions = {1919- options = {2020- storePaths = lib.mkOption {2121- type = with lib.types; listOf path;2222- default = [ ];2323- description = "The store paths to include in the partition.";2424- };2525-2626- stripNixStorePrefix = lib.mkOption {2727- type = lib.types.bool;2828- default = false;2929- description = ''3030- Whether to strip `/nix/store/` from the store paths. This is useful3131- when you want to build a partition that only contains store paths and3232- is mounted under `/nix/store`.3333- '';3434- };3535-3636- contents = lib.mkOption {3737- type =3838- with lib.types;3939- attrsOf (submodule {4040- options = {4141- source = lib.mkOption {4242- type = types.path;4343- description = "Path of the source file.";4444- };4545- };4646- });4747- default = { };4848- example = lib.literalExpression ''4949- {5050- "/EFI/BOOT/BOOTX64.EFI".source =5151- "''${pkgs.systemd}/lib/systemd/boot/efi/systemd-bootx64.efi";5252-5353- "/loader/entries/nixos.conf".source = systemdBootEntry;5454- }5555- '';5656- description = "The contents to end up in the filesystem image.";5757- };5858-5959- repartConfig = lib.mkOption {6060- type =6161- with lib.types;6262- attrsOf (oneOf [6363- str6464- int6565- bool6666- (listOf str)6767- ]);6868- example = {6969- Type = "home";7070- SizeMinBytes = "512M";7171- SizeMaxBytes = "2G";1818+ partitionOptions =1919+ { config, ... }:2020+ {2121+ options = {2222+ storePaths = lib.mkOption {2323+ type = with lib.types; listOf path;2424+ default = [ ];2525+ description = "The store paths to include in the partition.";7226 };7373- description = ''7474- Specify the repart options for a partiton as a structural setting.7575- See {manpage}`repart.d(5)`7676- for all available options.7777- '';2727+2828+ # Superseded by `nixStorePrefix`. Unfortunately, `mkChangedOptionModule`2929+ # does not support submodules.3030+ stripNixStorePrefix = lib.mkOption {3131+ default = "_mkMergedOptionModule";3232+ visible = false;3333+ };3434+3535+ nixStorePrefix = lib.mkOption {3636+ type = lib.types.path;3737+ default = "/nix/store";3838+ description = ''3939+ The prefix to use for store paths. Defaults to `/nix/store`. This is4040+ useful when you want to build a partition that only contains store4141+ paths and is mounted under `/nix/store` or if you want to create the4242+ store paths below a parent path (e.g., `/@nix/nix/store`).4343+ '';4444+ };4545+4646+ contents = lib.mkOption {4747+ type =4848+ with lib.types;4949+ attrsOf (submodule {5050+ options = {5151+ source = lib.mkOption {5252+ type = types.path;5353+ description = "Path of the source file.";5454+ };5555+ };5656+ });5757+ default = { };5858+ example = lib.literalExpression ''5959+ {6060+ "/EFI/BOOT/BOOTX64.EFI".source =6161+ "''${pkgs.systemd}/lib/systemd/boot/efi/systemd-bootx64.efi";6262+6363+ "/loader/entries/nixos.conf".source = systemdBootEntry;6464+ }6565+ '';6666+ description = "The contents to end up in the filesystem image.";6767+ };6868+6969+ repartConfig = lib.mkOption {7070+ type =7171+ with lib.types;7272+ attrsOf (oneOf [7373+ str7474+ int7575+ bool7676+ (listOf str)7777+ ]);7878+ example = {7979+ Type = "home";8080+ SizeMinBytes = "512M";8181+ SizeMaxBytes = "2G";8282+ };8383+ description = ''8484+ Specify the repart options for a partiton as a structural setting.8585+ See {manpage}`repart.d(5)`8686+ for all available options.8787+ '';8888+ };8989+ };9090+9191+ config = lib.mkIf (config.stripNixStorePrefix == true) {9292+ nixStorePrefix = "/";7893 };7994 };8080- };81958296 mkfsOptionsToEnv =8397 opts:···364350 }365351 ) cfg.partitions;366352367367- warnings = lib.filter (v: v != null) (353353+ warnings = lib.flatten (368354 lib.mapAttrsToList (369355 fileName: partitionConfig:370356 let···372358 suggestedMaxLabelLength = GPTMaxLabelLength - 2;373359 labelLength = builtins.stringLength repartConfig.Label;374360 in375375- if (repartConfig ? Label && labelLength >= suggestedMaxLabelLength) then376376- ''377377- The partition label '${repartConfig.Label}'378378- defined for '${fileName}' is ${toString labelLength} characters long.379379- The suggested maximum label length is ${toString suggestedMaxLabelLength}.361361+ lib.optional (repartConfig ? Label && labelLength >= suggestedMaxLabelLength) ''362362+ The partition label '${repartConfig.Label}'363363+ defined for '${fileName}' is ${toString labelLength} characters long.364364+ The suggested maximum label length is ${toString suggestedMaxLabelLength}.380365381381- If you use sytemd-sysupdate style A/B updates, this might382382- not leave enough space to increment the version number included in383383- the label in a future release. For example, if your label is384384- ${toString GPTMaxLabelLength} characters long (the maximum enforced by UEFI) and385385- you're at version 9, you cannot increment this to 10.386386- ''387387- else388388- null366366+ If you use sytemd-sysupdate style A/B updates, this might367367+ not leave enough space to increment the version number included in368368+ the label in a future release. For example, if your label is369369+ ${toString GPTMaxLabelLength} characters long (the maximum enforced by UEFI) and370370+ you're at version 9, you cannot increment this to 10.371371+ ''372372+ ++ lib.optional (partitionConfig.stripNixStorePrefix != "_mkMergedOptionModule") ''373373+ The option definition `image.repart.paritions.${fileName}.stripNixStorePrefix`374374+ has changed to `image.repart.paritions.${fileName}.nixStorePrefix` and now375375+ accepts the path to use as prefix directly. Use `nixStorePrefix = "/"` to376376+ achieve the same effect as setting `stripNixStorePrefix = true`.377377+ ''389378 ) cfg.partitions390379 );391380 };