3 """Amend systemd-repart definiton files.
5 In order to avoid Import-From-Derivation (IFD) when building images with
6 systemd-repart, the definition files created by Nix need to be amended with the
7 store paths from the closure.
9 This is achieved by adding CopyFiles= instructions to the definition files.
11 The arbitrary files configured via `contents` are also added to the definition
12 files using the same mechanism.
18 from pathlib
import Path
21 def add_contents_to_definition(
22 definition
: Path
, contents
: dict[str, dict[str, str]] |
None
24 """Add CopyFiles= instructions to a definition for all files in contents."""
28 copy_files_lines
: list[str] = []
29 for target
, options
in contents
.items():
30 source
= options
["source"]
32 copy_files_lines
.append(f
"CopyFiles={source}:{target}\n")
34 with
open(definition
, "a") as f
:
35 f
.writelines(copy_files_lines
)
38 def add_closure_to_definition(
39 definition
: Path
, closure
: Path |
None, strip_nix_store_prefix
: bool |
None
41 """Add CopyFiles= instructions to a definition for all paths in the closure.
43 If strip_nix_store_prefix is True, `/nix/store` is stripped from the target path.
48 copy_files_lines
: list[str] = []
49 with
open(closure
, "r") as f
:
51 if not isinstance(line
, str):
54 source
= Path(line
.strip())
55 target
= str(source
.relative_to("/nix/store/"))
56 target
= f
":/{target}" if strip_nix_store_prefix
else ""
58 copy_files_lines
.append(f
"CopyFiles={source}{target}\n")
60 with
open(definition
, "a") as f
:
61 f
.writelines(copy_files_lines
)
65 """Amend the provided repart definitions by adding CopyFiles= instructions.
67 For each file specified in the `contents` field of a partition in the
68 partiton config file, a `CopyFiles=` instruction is added to the
69 corresponding definition file.
71 The same is done for every store path of the `closure` field.
73 Print the path to a directory that contains the amended repart
74 definitions to stdout.
76 partition_config_file
= sys
.argv
[1]
77 if not partition_config_file
:
78 print("No partition config file was supplied.")
81 repart_definitions
= sys
.argv
[2]
82 if not repart_definitions
:
83 print("No repart definitions were supplied.")
86 with
open(partition_config_file
, "rb") as f
:
87 partition_config
= json
.load(f
)
89 if not partition_config
:
90 print("Partition config is empty.")
93 target_dir
= Path("amended-repart.d")
95 shutil
.copytree(repart_definitions
, target_dir
, dirs_exist_ok
=True)
97 for name
, config
in partition_config
.items():
98 definition
= target_dir
.joinpath(f
"{name}.conf")
99 definition
.chmod(0o644)
101 contents
= config
.get("contents")
102 add_contents_to_definition(definition
, contents
)
104 closure
= config
.get("closure")
105 strip_nix_store_prefix
= config
.get("stripNixStorePrefix")
106 add_closure_to_definition(definition
, closure
, strip_nix_store_prefix
)
108 print(target_dir
.absolute())
111 if __name__
== "__main__":