nixos/image/repart: allow replacing /nix/store
This commit is contained in:
@@ -40,12 +40,18 @@ An example of how to build an image:
|
||||
}
|
||||
```
|
||||
|
||||
## Nix Store Partition {#sec-image-repart-store-partition}
|
||||
## Nix Store Paths {#sec-image-repart-store-paths}
|
||||
|
||||
If you want to rewrite Nix store paths, e.g., to remove the `/nix/store` prefix
|
||||
or to nest it below a parent path, you can do that through the
|
||||
`nixStorePrefix` option.
|
||||
|
||||
### Nix Store Partition {#sec-image-repart-store-partition}
|
||||
|
||||
You can define a partition that only contains the Nix store and then mount it
|
||||
under `/nix/store`. Because the `/nix/store` part of the paths is already
|
||||
determined by the mount point, you have to set `stripNixStorePrefix = true;` so
|
||||
that the prefix is stripped from the paths before copying them into the image.
|
||||
determined by the mount point, you have to set `nixStorePrefix = "/"` so
|
||||
that `/nix/store` is stripped from the paths before copying them into the image.
|
||||
|
||||
```nix
|
||||
{
|
||||
@@ -54,7 +60,7 @@ that the prefix is stripped from the paths before copying them into the image.
|
||||
image.repart.partitions = {
|
||||
"store" = {
|
||||
storePaths = [ config.system.build.toplevel ];
|
||||
stripNixStorePrefix = true;
|
||||
nixStorePrefix = "/";
|
||||
repartConfig = {
|
||||
Type = "linux-generic";
|
||||
Label = "nix-store";
|
||||
@@ -65,6 +71,42 @@ that the prefix is stripped from the paths before copying them into the image.
|
||||
}
|
||||
```
|
||||
|
||||
### Nix Store Subvolume {#sec-image-repart-store-subvolume}
|
||||
|
||||
Alternatively, you can create a Btrfs subvolume `/@nix-store` containing the
|
||||
Nix store and mount it on `/nix/store`:
|
||||
|
||||
```nix
|
||||
{
|
||||
fileSystems."/" = {
|
||||
device = "/dev/disk/by-partlabel/root";
|
||||
fsType = "btrfs";
|
||||
options = [ "subvol=/@" ];
|
||||
};
|
||||
|
||||
fileSystems."/nix/store" = {
|
||||
device = "/dev/disk/by-partlabel/root";
|
||||
fsType = "btrfs";
|
||||
options = [ "subvol=/@nix-store" ];
|
||||
};
|
||||
|
||||
image.repart.partitions = {
|
||||
"root" = {
|
||||
storePaths = [ config.system.build.toplevel ];
|
||||
nixStorePrefix = "/@nix-store";
|
||||
repartConfig = {
|
||||
Type = "root";
|
||||
Label = "root";
|
||||
Format = "btrfs";
|
||||
Subvolumes = "/@ /@nix-store";
|
||||
MakeDirectories = "/@ /@nix-store";
|
||||
# ...
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
## Appliance Image {#sec-image-repart-appliance}
|
||||
|
||||
The `image/repart.nix` module can also be used to build self-contained [software
|
||||
|
||||
@@ -287,9 +287,15 @@
|
||||
"sec-image-repart": [
|
||||
"index.html#sec-image-repart"
|
||||
],
|
||||
"sec-image-repart-store-paths": [
|
||||
"index.html#sec-image-repart-store-paths"
|
||||
],
|
||||
"sec-image-repart-store-partition": [
|
||||
"index.html#sec-image-repart-store-partition"
|
||||
],
|
||||
"sec-image-repart-store-subvolume": [
|
||||
"index.html#sec-image-repart-store-subvolume"
|
||||
],
|
||||
"sec-image-repart-appliance": [
|
||||
"index.html#sec-image-repart-appliance"
|
||||
],
|
||||
|
||||
@@ -36,11 +36,11 @@ def add_contents_to_definition(
|
||||
|
||||
|
||||
def add_closure_to_definition(
|
||||
definition: Path, closure: Path | None, strip_nix_store_prefix: bool | None
|
||||
definition: Path, closure: Path | None, nix_store_prefix: str | None
|
||||
) -> None:
|
||||
"""Add CopyFiles= instructions to a definition for all paths in the closure.
|
||||
|
||||
If strip_nix_store_prefix is True, `/nix/store` is stripped from the target path.
|
||||
Replace `/nix/store` with the value of nix_store_prefix.
|
||||
"""
|
||||
if not closure:
|
||||
return
|
||||
@@ -52,10 +52,12 @@ def add_closure_to_definition(
|
||||
continue
|
||||
|
||||
source = Path(line.strip())
|
||||
target = str(source.relative_to("/nix/store/"))
|
||||
target = f":/{target}" if strip_nix_store_prefix else ""
|
||||
option = f"CopyFiles={source}"
|
||||
if nix_store_prefix:
|
||||
target = nix_store_prefix / source.relative_to("/nix/store/")
|
||||
option = f"{option}:{target}"
|
||||
|
||||
copy_files_lines.append(f"CopyFiles={source}{target}\n")
|
||||
copy_files_lines.append(f"{option}\n")
|
||||
|
||||
with open(definition, "a") as f:
|
||||
f.writelines(copy_files_lines)
|
||||
@@ -102,8 +104,8 @@ def main() -> None:
|
||||
add_contents_to_definition(definition, contents)
|
||||
|
||||
closure = config.get("closure")
|
||||
strip_nix_store_prefix = config.get("stripNixStorePrefix")
|
||||
add_closure_to_definition(definition, closure, strip_nix_store_prefix)
|
||||
nix_store_prefix = config.get("nixStorePrefix")
|
||||
add_closure_to_definition(definition, closure, nix_store_prefix)
|
||||
|
||||
print(target_dir.absolute())
|
||||
|
||||
|
||||
@@ -15,7 +15,9 @@ let
|
||||
|
||||
inherit (utils.systemdUtils.lib) GPTMaxLabelLength;
|
||||
|
||||
partitionOptions = {
|
||||
partitionOptions =
|
||||
{ config, ... }:
|
||||
{
|
||||
options = {
|
||||
storePaths = lib.mkOption {
|
||||
type = with lib.types; listOf path;
|
||||
@@ -23,13 +25,21 @@ let
|
||||
description = "The store paths to include in the partition.";
|
||||
};
|
||||
|
||||
# Superseded by `nixStorePrefix`. Unfortunately, `mkChangedOptionModule`
|
||||
# does not support submodules.
|
||||
stripNixStorePrefix = lib.mkOption {
|
||||
type = lib.types.bool;
|
||||
default = false;
|
||||
default = "_mkMergedOptionModule";
|
||||
visible = false;
|
||||
};
|
||||
|
||||
nixStorePrefix = lib.mkOption {
|
||||
type = lib.types.path;
|
||||
default = "/nix/store";
|
||||
description = ''
|
||||
Whether to strip `/nix/store/` from the store paths. This is useful
|
||||
when you want to build a partition that only contains store paths and
|
||||
is mounted under `/nix/store`.
|
||||
The prefix to use for store paths. Defaults to `/nix/store`. This is
|
||||
useful when you want to build a partition that only contains store
|
||||
paths and is mounted under `/nix/store` or if you want to create the
|
||||
store paths below a parent path (e.g., `/@nix/nix/store`).
|
||||
'';
|
||||
};
|
||||
|
||||
@@ -77,6 +87,10 @@ let
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
config = lib.mkIf (config.stripNixStorePrefix == true) {
|
||||
nixStorePrefix = "/";
|
||||
};
|
||||
};
|
||||
|
||||
mkfsOptionsToEnv =
|
||||
@@ -350,7 +364,7 @@ in
|
||||
}
|
||||
) cfg.partitions;
|
||||
|
||||
warnings = lib.filter (v: v != null) (
|
||||
warnings = lib.flatten (
|
||||
lib.mapAttrsToList (
|
||||
fileName: partitionConfig:
|
||||
let
|
||||
@@ -358,8 +372,7 @@ in
|
||||
suggestedMaxLabelLength = GPTMaxLabelLength - 2;
|
||||
labelLength = builtins.stringLength repartConfig.Label;
|
||||
in
|
||||
if (repartConfig ? Label && labelLength >= suggestedMaxLabelLength) then
|
||||
''
|
||||
lib.optional (repartConfig ? Label && labelLength >= suggestedMaxLabelLength) ''
|
||||
The partition label '${repartConfig.Label}'
|
||||
defined for '${fileName}' is ${toString labelLength} characters long.
|
||||
The suggested maximum label length is ${toString suggestedMaxLabelLength}.
|
||||
@@ -370,8 +383,12 @@ in
|
||||
${toString GPTMaxLabelLength} characters long (the maximum enforced by UEFI) and
|
||||
you're at version 9, you cannot increment this to 10.
|
||||
''
|
||||
else
|
||||
null
|
||||
++ lib.optional (partitionConfig.stripNixStorePrefix != "_mkMergedOptionModule") ''
|
||||
The option definition `image.repart.paritions.${fileName}.stripNixStorePrefix`
|
||||
has changed to `image.repart.paritions.${fileName}.nixStorePrefix` and now
|
||||
accepts the path to use as prefix directly. Use `nixStorePrefix = "/"` to
|
||||
achieve the same effect as setting `stripNixStorePrefix = true`.
|
||||
''
|
||||
) cfg.partitions
|
||||
);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user