nixos-rebuild{-ng,}: Don't eval nixos closure before validating image variants. (#395148)
This commit is contained in:
commit
b569b62759
@ -396,7 +396,7 @@ def execute(argv: list[str]) -> None:
|
|||||||
raise NRError(
|
raise NRError(
|
||||||
"please specify one of the following "
|
"please specify one of the following "
|
||||||
+ "supported image variants via --image-variant:\n"
|
+ "supported image variants via --image-variant:\n"
|
||||||
+ "\n".join(f"- {v}" for v in variants.keys())
|
+ "\n".join(f"- {v}" for v in variants)
|
||||||
)
|
)
|
||||||
|
|
||||||
match action:
|
match action:
|
||||||
@ -518,7 +518,19 @@ def execute(argv: list[str]) -> None:
|
|||||||
"Done. The virtual machine can be started by running", vm_path
|
"Done. The virtual machine can be started by running", vm_path
|
||||||
)
|
)
|
||||||
case Action.BUILD_IMAGE:
|
case Action.BUILD_IMAGE:
|
||||||
disk_path = path_to_config / variants[args.image_variant]
|
if flake:
|
||||||
|
image_name = nix.get_build_image_name_flake(
|
||||||
|
flake,
|
||||||
|
args.image_variant,
|
||||||
|
eval_flags=flake_common_flags,
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
image_name = nix.get_build_image_name(
|
||||||
|
build_attr,
|
||||||
|
args.image_variant,
|
||||||
|
instantiate_flags=flake_common_flags,
|
||||||
|
)
|
||||||
|
disk_path = path_to_config / image_name
|
||||||
print_result("Done. The disk image can be found in", disk_path)
|
print_result("Done. The disk image can be found in", disk_path)
|
||||||
|
|
||||||
case Action.EDIT:
|
case Action.EDIT:
|
||||||
|
@ -8,7 +8,7 @@ from typing import Any, Callable, ClassVar, Self, TypedDict, override
|
|||||||
|
|
||||||
from .process import Remote, run_wrapper
|
from .process import Remote, run_wrapper
|
||||||
|
|
||||||
type ImageVariants = dict[str, str]
|
type ImageVariants = list[str]
|
||||||
|
|
||||||
|
|
||||||
class NRError(Exception):
|
class NRError(Exception):
|
||||||
|
@ -266,6 +266,59 @@ def find_file(file: str, nix_flags: Args | None = None) -> Path | None:
|
|||||||
return Path(r.stdout.strip())
|
return Path(r.stdout.strip())
|
||||||
|
|
||||||
|
|
||||||
|
def get_build_image_name(
|
||||||
|
build_attr: BuildAttr,
|
||||||
|
image_variant: str,
|
||||||
|
instantiate_flags: Args | None = None,
|
||||||
|
) -> str:
|
||||||
|
path = (
|
||||||
|
f'"{build_attr.path.resolve()}"'
|
||||||
|
if isinstance(build_attr.path, Path)
|
||||||
|
else build_attr.path
|
||||||
|
)
|
||||||
|
r = run_wrapper(
|
||||||
|
[
|
||||||
|
"nix-instantiate",
|
||||||
|
"--eval",
|
||||||
|
"--strict",
|
||||||
|
"--json",
|
||||||
|
"--expr",
|
||||||
|
textwrap.dedent(f"""
|
||||||
|
let
|
||||||
|
value = import {path};
|
||||||
|
set = if builtins.isFunction value then value {{}} else value;
|
||||||
|
in
|
||||||
|
set.{build_attr.to_attr("config.system.build.images", image_variant, "passthru", "filePath")}
|
||||||
|
"""),
|
||||||
|
*dict_to_flags(instantiate_flags),
|
||||||
|
],
|
||||||
|
stdout=PIPE,
|
||||||
|
)
|
||||||
|
j: str = json.loads(r.stdout.strip())
|
||||||
|
return j
|
||||||
|
|
||||||
|
|
||||||
|
def get_build_image_name_flake(
|
||||||
|
flake: Flake,
|
||||||
|
image_variant: str,
|
||||||
|
eval_flags: Args | None = None,
|
||||||
|
) -> str:
|
||||||
|
r = run_wrapper(
|
||||||
|
[
|
||||||
|
"nix",
|
||||||
|
"eval",
|
||||||
|
"--json",
|
||||||
|
flake.to_attr(
|
||||||
|
"config.system.build.images", image_variant, "passthru", "filePath"
|
||||||
|
),
|
||||||
|
*dict_to_flags(eval_flags),
|
||||||
|
],
|
||||||
|
stdout=PIPE,
|
||||||
|
)
|
||||||
|
j: str = json.loads(r.stdout.strip())
|
||||||
|
return j
|
||||||
|
|
||||||
|
|
||||||
def get_build_image_variants(
|
def get_build_image_variants(
|
||||||
build_attr: BuildAttr,
|
build_attr: BuildAttr,
|
||||||
instantiate_flags: Args | None = None,
|
instantiate_flags: Args | None = None,
|
||||||
@ -287,7 +340,7 @@ def get_build_image_variants(
|
|||||||
value = import {path};
|
value = import {path};
|
||||||
set = if builtins.isFunction value then value {{}} else value;
|
set = if builtins.isFunction value then value {{}} else value;
|
||||||
in
|
in
|
||||||
builtins.mapAttrs (n: v: v.passthru.filePath) set.{build_attr.to_attr("config.system.build.images")}
|
builtins.attrNames set.{build_attr.to_attr("config.system.build.images")}
|
||||||
"""),
|
"""),
|
||||||
*dict_to_flags(instantiate_flags),
|
*dict_to_flags(instantiate_flags),
|
||||||
],
|
],
|
||||||
@ -308,7 +361,7 @@ def get_build_image_variants_flake(
|
|||||||
"--json",
|
"--json",
|
||||||
flake.to_attr("config.system.build.images"),
|
flake.to_attr("config.system.build.images"),
|
||||||
"--apply",
|
"--apply",
|
||||||
"builtins.mapAttrs (n: v: v.passthru.filePath)",
|
"builtins.attrNames",
|
||||||
*dict_to_flags(eval_flags),
|
*dict_to_flags(eval_flags),
|
||||||
],
|
],
|
||||||
stdout=PIPE,
|
stdout=PIPE,
|
||||||
|
@ -347,12 +347,7 @@ def test_execute_nix_build_image_flake(mock_run: Mock, tmp_path: Path) -> None:
|
|||||||
return CompletedProcess(
|
return CompletedProcess(
|
||||||
[],
|
[],
|
||||||
0,
|
0,
|
||||||
"""
|
'"nixos-image-azure-25.05.20250102.6df2492-x86_64-linux.vhd"',
|
||||||
{
|
|
||||||
"azure": "nixos-image-azure-25.05.20250102.6df2492-x86_64-linux.vhd",
|
|
||||||
"vmware": "nixos-image-vmware-25.05.20250102.6df2492-x86_64-linux.vmdk"
|
|
||||||
}
|
|
||||||
""",
|
|
||||||
)
|
)
|
||||||
elif args[0] == "nix":
|
elif args[0] == "nix":
|
||||||
return CompletedProcess([], 0, str(config_path))
|
return CompletedProcess([], 0, str(config_path))
|
||||||
@ -372,7 +367,7 @@ def test_execute_nix_build_image_flake(mock_run: Mock, tmp_path: Path) -> None:
|
|||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
assert mock_run.call_count == 2
|
assert mock_run.call_count == 3
|
||||||
mock_run.assert_has_calls(
|
mock_run.assert_has_calls(
|
||||||
[
|
[
|
||||||
call(
|
call(
|
||||||
@ -382,7 +377,7 @@ def test_execute_nix_build_image_flake(mock_run: Mock, tmp_path: Path) -> None:
|
|||||||
"--json",
|
"--json",
|
||||||
"/path/to/config#nixosConfigurations.hostname.config.system.build.images",
|
"/path/to/config#nixosConfigurations.hostname.config.system.build.images",
|
||||||
"--apply",
|
"--apply",
|
||||||
"builtins.mapAttrs (n: v: v.passthru.filePath)",
|
"builtins.attrNames",
|
||||||
],
|
],
|
||||||
check=True,
|
check=True,
|
||||||
stdout=PIPE,
|
stdout=PIPE,
|
||||||
@ -401,6 +396,17 @@ def test_execute_nix_build_image_flake(mock_run: Mock, tmp_path: Path) -> None:
|
|||||||
stdout=PIPE,
|
stdout=PIPE,
|
||||||
**DEFAULT_RUN_KWARGS,
|
**DEFAULT_RUN_KWARGS,
|
||||||
),
|
),
|
||||||
|
call(
|
||||||
|
[
|
||||||
|
"nix",
|
||||||
|
"eval",
|
||||||
|
"--json",
|
||||||
|
"/path/to/config#nixosConfigurations.hostname.config.system.build.images.azure.passthru.filePath",
|
||||||
|
],
|
||||||
|
check=True,
|
||||||
|
stdout=PIPE,
|
||||||
|
**DEFAULT_RUN_KWARGS,
|
||||||
|
),
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -353,7 +353,7 @@ def test_get_build_image_variants(mock_run: Mock, tmp_path: Path) -> None:
|
|||||||
value = import <nixpkgs/nixos>;
|
value = import <nixpkgs/nixos>;
|
||||||
set = if builtins.isFunction value then value {} else value;
|
set = if builtins.isFunction value then value {} else value;
|
||||||
in
|
in
|
||||||
builtins.mapAttrs (n: v: v.passthru.filePath) set.config.system.build.images
|
builtins.attrNames set.config.system.build.images
|
||||||
"""),
|
"""),
|
||||||
],
|
],
|
||||||
stdout=PIPE,
|
stdout=PIPE,
|
||||||
@ -376,7 +376,7 @@ def test_get_build_image_variants(mock_run: Mock, tmp_path: Path) -> None:
|
|||||||
value = import "{tmp_path}";
|
value = import "{tmp_path}";
|
||||||
set = if builtins.isFunction value then value {{}} else value;
|
set = if builtins.isFunction value then value {{}} else value;
|
||||||
in
|
in
|
||||||
builtins.mapAttrs (n: v: v.passthru.filePath) set.preAttr.config.system.build.images
|
builtins.attrNames set.preAttr.config.system.build.images
|
||||||
"""),
|
"""),
|
||||||
"--inst-flag",
|
"--inst-flag",
|
||||||
],
|
],
|
||||||
@ -411,7 +411,7 @@ def test_get_build_image_variants_flake(mock_run: Mock) -> None:
|
|||||||
"--json",
|
"--json",
|
||||||
"flake.nix#myAttr.config.system.build.images",
|
"flake.nix#myAttr.config.system.build.images",
|
||||||
"--apply",
|
"--apply",
|
||||||
"builtins.mapAttrs (n: v: v.passthru.filePath)",
|
"builtins.attrNames",
|
||||||
"--eval-flag",
|
"--eval-flag",
|
||||||
],
|
],
|
||||||
stdout=PIPE,
|
stdout=PIPE,
|
||||||
|
@ -835,28 +835,50 @@ if [ -z "$rollback" ]; then
|
|||||||
"let
|
"let
|
||||||
value = import \"$(realpath $buildFile)\";
|
value = import \"$(realpath $buildFile)\";
|
||||||
set = if builtins.isFunction value then value {} else value;
|
set = if builtins.isFunction value then value {} else value;
|
||||||
in builtins.mapAttrs (n: v: v.passthru.filePath) set.${attr:+$attr.}config.system.build.images" \
|
in builtins.attrNames set.${attr:+$attr.}config.system.build.images" \
|
||||||
"${extraBuildFlags[@]}"
|
"${extraBuildFlags[@]}"
|
||||||
)"
|
)"
|
||||||
elif [[ -z $flake ]]; then
|
elif [[ -z $flake ]]; then
|
||||||
variants="$(
|
variants="$(
|
||||||
runCmd nix-instantiate --eval --strict --json --expr \
|
runCmd nix-instantiate --eval --strict --json --expr \
|
||||||
"with import <nixpkgs/nixos> {}; builtins.mapAttrs (n: v: v.passthru.filePath) config.system.build.images" \
|
"with import <nixpkgs/nixos> {}; builtins.attrNames config.system.build.images" \
|
||||||
"${extraBuildFlags[@]}"
|
"${extraBuildFlags[@]}"
|
||||||
)"
|
)"
|
||||||
else
|
else
|
||||||
variants="$(
|
variants="$(
|
||||||
runCmd nix "${flakeFlags[@]}" eval --json \
|
runCmd nix "${flakeFlags[@]}" eval --json \
|
||||||
"$flake#$flakeAttr.config.system.build.images" \
|
"$flake#$flakeAttr.config.system.build.images" \
|
||||||
--apply "builtins.mapAttrs (n: v: v.passthru.filePath)" "${evalArgs[@]}" "${extraBuildFlags[@]}"
|
--apply "builtins.attrNames" "${evalArgs[@]}" "${extraBuildFlags[@]}"
|
||||||
)"
|
)"
|
||||||
fi
|
fi
|
||||||
if ! echo "$variants" | jq -e --arg variant "$imageVariant" "keys | any(. == \$variant)" > /dev/null; then
|
if ! echo "$variants" | jq -e --arg variant "$imageVariant" "any(. == \$variant)" > /dev/null; then
|
||||||
echo -e "Please specify one of the following supported image variants via --image-variant:\n" >&2
|
echo -e "Please specify one of the following supported image variants via --image-variant:\n" >&2
|
||||||
echo "$variants" | jq -r '. | keys | join ("\n")'
|
echo "$variants" | jq -r 'join ("\n")'
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
imageName="$(echo "$variants" | jq -r --arg variant "$imageVariant" ".[\$variant]")"
|
|
||||||
|
if [[ -z $buildingAttribute ]]; then
|
||||||
|
imageName="$(
|
||||||
|
runCmd nix-instantiate --eval --strict --json --expr \
|
||||||
|
"let
|
||||||
|
value = import \"$(realpath $buildFile)\";
|
||||||
|
set = if builtins.isFunction value then value {} else value;
|
||||||
|
in set.${attr:+$attr.}config.system.build.images.$imageVariant.v.passthru.filePath" \
|
||||||
|
"${extraBuildFlags[@]}"
|
||||||
|
)"
|
||||||
|
elif [[ -z $flake ]]; then
|
||||||
|
imageName="$(
|
||||||
|
runCmd nix-instantiate --eval --strict --json --expr \
|
||||||
|
"with import <nixpkgs/nixos> {}; config.system.build.images.$imageVariant.passthru.filePath" \
|
||||||
|
"${extraBuildFlags[@]}"
|
||||||
|
)"
|
||||||
|
else
|
||||||
|
imageName="$(
|
||||||
|
runCmd nix "${flakeFlags[@]}" eval --json \
|
||||||
|
"$flake#$flakeAttr.config.system.build.images.$imageVariant.passthru.filePath" \
|
||||||
|
"${evalArgs[@]}" "${extraBuildFlags[@]}"
|
||||||
|
)"
|
||||||
|
fi
|
||||||
|
|
||||||
if [[ -z $buildingAttribute ]]; then
|
if [[ -z $buildingAttribute ]]; then
|
||||||
pathToConfig="$(nixBuild $buildFile -A "${attr:+$attr.}config.system.build.images.${imageVariant}" "${extraBuildFlags[@]}")"
|
pathToConfig="$(nixBuild $buildFile -A "${attr:+$attr.}config.system.build.images.${imageVariant}" "${extraBuildFlags[@]}")"
|
||||||
|
Loading…
Reference in New Issue
Block a user