diff --git a/pkgs/by-name/ni/nixos-rebuild-ng/src/nixos_rebuild/__init__.py b/pkgs/by-name/ni/nixos-rebuild-ng/src/nixos_rebuild/__init__.py index 0ee3c6db0fd7..ec10db85fcc5 100644 --- a/pkgs/by-name/ni/nixos-rebuild-ng/src/nixos_rebuild/__init__.py +++ b/pkgs/by-name/ni/nixos-rebuild-ng/src/nixos_rebuild/__init__.py @@ -194,13 +194,14 @@ def execute(argv: list[str]) -> None: match action: case Action.SWITCH | Action.BOOT: logger.info("building the system configuration...") + attr = "config.system.build.toplevel" if args.rollback: path_to_config = nix.rollback(profile, target_host, sudo=args.sudo) else: if flake: if build_host: - path_to_config = nix.nixos_remote_build_flake( - "toplevel", + path_to_config = nix.remote_build_flake( + attr, flake, build_host, flake_build_flags=flake_build_flags, @@ -208,16 +209,16 @@ def execute(argv: list[str]) -> None: build_flags=build_flags, ) else: - path_to_config = nix.nixos_build_flake( - "toplevel", + path_to_config = nix.build_flake( + attr, flake, no_link=True, **flake_build_flags, ) else: if build_host: - path_to_config = nix.nixos_remote_build( - "toplevel", + path_to_config = nix.remote_build( + attr, build_attr, build_host, instantiate_flags=common_flags, @@ -225,8 +226,8 @@ def execute(argv: list[str]) -> None: build_flags=build_flags, ) else: - path_to_config = nix.nixos_build( - "toplevel", + path_to_config = nix.build( + attr, build_attr, no_out_link=True, **build_flags, @@ -253,6 +254,7 @@ def execute(argv: list[str]) -> None: ) case Action.TEST | Action.BUILD | Action.DRY_BUILD | Action.DRY_ACTIVATE: logger.info("building the system configuration...") + attr = "config.system.build.toplevel" dry_run = action == Action.DRY_BUILD if args.rollback: if action not in (Action.TEST, Action.BUILD): @@ -267,15 +269,15 @@ def execute(argv: list[str]) -> None: else: raise NRError("could not find previous generation") elif flake: - path_to_config = nix.nixos_build_flake( - "toplevel", + path_to_config = nix.build_flake( + attr, flake, dry_run=dry_run, **flake_build_flags, ) else: - path_to_config = nix.nixos_build( - "toplevel", + path_to_config = nix.build( + attr, build_attr, dry_run=dry_run, **build_flags, @@ -292,14 +294,14 @@ def execute(argv: list[str]) -> None: logger.info("building the system configuration...") attr = "vm" if action == Action.BUILD_VM else "vmWithBootLoader" if flake: - path_to_config = nix.nixos_build_flake( - attr, + path_to_config = nix.build_flake( + f"config.system.build.{attr}", flake, **flake_build_flags, ) else: - path_to_config = nix.nixos_build( - attr, + path_to_config = nix.build( + f"config.system.build.{attr}", build_attr, **build_flags, ) diff --git a/pkgs/by-name/ni/nixos-rebuild-ng/src/nixos_rebuild/nix.py b/pkgs/by-name/ni/nixos-rebuild-ng/src/nixos_rebuild/nix.py index 7a42645d904b..ccf927a5e59f 100644 --- a/pkgs/by-name/ni/nixos-rebuild-ng/src/nixos_rebuild/nix.py +++ b/pkgs/by-name/ni/nixos-rebuild-ng/src/nixos_rebuild/nix.py @@ -25,6 +25,112 @@ FLAKE_REPL_TEMPLATE: Final = "repl.template.nix" logger = logging.getLogger(__name__) +def build( + attr: str, + build_attr: BuildAttr, + **build_flags: Args, +) -> Path: + """Build NixOS attribute using classic Nix. + + Returns the built attribute as path. + """ + run_args = [ + "nix-build", + build_attr.path, + "--attr", + build_attr.to_attr(attr), + *dict_to_flags(build_flags), + ] + r = run_wrapper(run_args, stdout=PIPE) + return Path(r.stdout.strip()) + + +def build_flake( + attr: str, + flake: Flake, + **flake_build_flags: Args, +) -> Path: + """Build NixOS attribute using Flakes. + + Returns the built attribute as path. + """ + run_args = [ + "nix", + *FLAKE_FLAGS, + "build", + "--print-out-paths", + flake.to_attr(attr), + *dict_to_flags(flake_build_flags), + ] + r = run_wrapper(run_args, stdout=PIPE) + return Path(r.stdout.strip()) + + +def remote_build( + attr: str, + build_attr: BuildAttr, + build_host: Remote | None, + build_flags: dict[str, Args] | None = None, + instantiate_flags: dict[str, Args] | None = None, + copy_flags: dict[str, Args] | None = None, +) -> Path: + r = run_wrapper( + [ + "nix-instantiate", + "--raw", + build_attr.path, + "--attr", + build_attr.to_attr(attr), + *dict_to_flags(instantiate_flags or {}), + ], + stdout=PIPE, + ) + drv = Path(r.stdout.strip()) + copy_closure(drv, to_host=build_host, from_host=None, **(copy_flags or {})) + r = run_wrapper( + ["nix-store", "--realise", drv, *dict_to_flags(build_flags or {})], + remote=build_host, + stdout=PIPE, + ) + return Path(r.stdout.strip()) + + +def remote_build_flake( + attr: str, + flake: Flake, + build_host: Remote, + flake_build_flags: dict[str, Args] | None = None, + copy_flags: dict[str, Args] | None = None, + build_flags: dict[str, Args] | None = None, +) -> Path: + r = run_wrapper( + [ + "nix", + *FLAKE_FLAGS, + "eval", + "--raw", + flake.to_attr(attr, "drvPath"), + *dict_to_flags(flake_build_flags or {}), + ], + stdout=PIPE, + ) + drv = Path(r.stdout.strip()) + copy_closure(drv, to_host=build_host, from_host=None, **(copy_flags or {})) + r = run_wrapper( + [ + "nix", + *FLAKE_FLAGS, + "build", + f"{drv}^*", + "--print-out-paths", + *dict_to_flags(build_flags or {}), + ], + remote=build_host, + stdout=PIPE, + ) + return Path(r.stdout.strip()) + + def copy_closure( closure: Path, to_host: Remote | None, @@ -248,112 +354,6 @@ def list_generations(profile: Profile) -> list[GenerationJson]: return result -def nixos_build( - attr: str, - build_attr: BuildAttr, - **build_flags: Args, -) -> Path: - """Build NixOS attribute using classic Nix. - - Returns the built attribute as path. - """ - run_args = [ - "nix-build", - build_attr.path, - "--attr", - build_attr.to_attr("config", "system", "build", attr), - *dict_to_flags(build_flags), - ] - r = run_wrapper(run_args, stdout=PIPE) - return Path(r.stdout.strip()) - - -def nixos_build_flake( - attr: str, - flake: Flake, - **flake_build_flags: Args, -) -> Path: - """Build NixOS attribute using Flakes. - - Returns the built attribute as path. - """ - run_args = [ - "nix", - *FLAKE_FLAGS, - "build", - "--print-out-paths", - flake.to_attr("config", "system", "build", attr), - *dict_to_flags(flake_build_flags), - ] - r = run_wrapper(run_args, stdout=PIPE) - return Path(r.stdout.strip()) - - -def nixos_remote_build( - attr: str, - build_attr: BuildAttr, - build_host: Remote | None, - build_flags: dict[str, Args] | None = None, - instantiate_flags: dict[str, Args] | None = None, - copy_flags: dict[str, Args] | None = None, -) -> Path: - r = run_wrapper( - [ - "nix-instantiate", - "--raw", - build_attr.path, - "--attr", - build_attr.to_attr("config", "system", "build", attr), - *dict_to_flags(instantiate_flags or {}), - ], - stdout=PIPE, - ) - drv = Path(r.stdout.strip()) - copy_closure(drv, to_host=build_host, from_host=None, **(copy_flags or {})) - r = run_wrapper( - ["nix-store", "--realise", drv, *dict_to_flags(build_flags or {})], - remote=build_host, - stdout=PIPE, - ) - return Path(r.stdout.strip()) - - -def nixos_remote_build_flake( - attr: str, - flake: Flake, - build_host: Remote, - flake_build_flags: dict[str, Args] | None = None, - copy_flags: dict[str, Args] | None = None, - build_flags: dict[str, Args] | None = None, -) -> Path: - r = run_wrapper( - [ - "nix", - *FLAKE_FLAGS, - "eval", - "--raw", - flake.to_attr("config", "system", "build", attr, "drvPath"), - *dict_to_flags(flake_build_flags or {}), - ], - stdout=PIPE, - ) - drv = Path(r.stdout.strip()) - copy_closure(drv, to_host=build_host, from_host=None, **(copy_flags or {})) - r = run_wrapper( - [ - "nix", - *FLAKE_FLAGS, - "build", - f"{drv}^*", - "--print-out-paths", - *dict_to_flags(build_flags or {}), - ], - remote=build_host, - stdout=PIPE, - ) - return Path(r.stdout.strip()) - - def repl(attr: str, build_attr: BuildAttr, **nix_flags: Args) -> None: run_args = ["nix", "repl", "--file", build_attr.path] if build_attr.attr: diff --git a/pkgs/by-name/ni/nixos-rebuild-ng/src/tests/test_nix.py b/pkgs/by-name/ni/nixos-rebuild-ng/src/tests/test_nix.py index dce98cf6b939..317821d5fea0 100644 --- a/pkgs/by-name/ni/nixos-rebuild-ng/src/tests/test_nix.py +++ b/pkgs/by-name/ni/nixos-rebuild-ng/src/tests/test_nix.py @@ -12,6 +12,173 @@ import nixos_rebuild.nix as n from .helpers import get_qualified_name +@patch( + get_qualified_name(n.run_wrapper, n), + autospec=True, + return_value=CompletedProcess([], 0, stdout=" \n/path/to/file\n "), +) +def test_build(mock_run: Any, monkeypatch: Any) -> None: + assert n.build( + "config.system.build.attr", m.BuildAttr("", None), nix_flag="foo" + ) == Path("/path/to/file") + mock_run.assert_called_with( + [ + "nix-build", + "", + "--attr", + "config.system.build.attr", + "--nix-flag", + "foo", + ], + stdout=PIPE, + ) + + assert n.build( + "config.system.build.attr", m.BuildAttr(Path("file"), "preAttr") + ) == Path("/path/to/file") + mock_run.assert_called_with( + ["nix-build", Path("file"), "--attr", "preAttr.config.system.build.attr"], + stdout=PIPE, + ) + + +@patch( + get_qualified_name(n.run_wrapper, n), + autospec=True, + return_value=CompletedProcess([], 0, stdout=" \n/path/to/file\n "), +) +def test_build_flake(mock_run: Any) -> None: + flake = m.Flake.parse(".#hostname") + + assert n.build_flake( + "config.system.build.toplevel", + flake, + no_link=True, + nix_flag="foo", + ) == Path("/path/to/file") + mock_run.assert_called_with( + [ + "nix", + "--extra-experimental-features", + "nix-command flakes", + "build", + "--print-out-paths", + ".#nixosConfigurations.hostname.config.system.build.toplevel", + "--no-link", + "--nix-flag", + "foo", + ], + stdout=PIPE, + ) + + +@patch( + get_qualified_name(n.run_wrapper, n), + autospec=True, + return_value=CompletedProcess([], 0, stdout=" \n/path/to/file\n "), +) +def test_remote_build(mock_run: Any, monkeypatch: Any) -> None: + build_host = m.Remote("user@host", ["--ssh", "opts"], None) + assert n.remote_build( + "config.system.build.toplevel", + m.BuildAttr("", "preAttr"), + build_host, + build_flags={"build": True}, + instantiate_flags={"inst": True}, + copy_flags={"copy": True}, + ) == Path("/path/to/file") + mock_run.assert_has_calls( + [ + call( + [ + "nix-instantiate", + "--raw", + "", + "--attr", + "preAttr.config.system.build.toplevel", + "--inst", + ], + stdout=PIPE, + ), + call( + [ + "nix-copy-closure", + "--copy", + "--to", + "user@host", + Path("/path/to/file"), + ], + extra_env={"NIX_SSHOPTS": "--ssh opts"}, + remote=None, + ), + call( + ["nix-store", "--realise", Path("/path/to/file"), "--build"], + remote=build_host, + stdout=PIPE, + ), + ] + ) + + +@patch( + get_qualified_name(n.run_wrapper, n), + autospec=True, + return_value=CompletedProcess([], 0, stdout=" \n/path/to/file\n "), +) +def test_remote_build_flake(mock_run: Any) -> None: + flake = m.Flake.parse(".#hostname") + build_host = m.Remote("user@host", ["--ssh", "opts"], None) + + assert n.remote_build_flake( + "config.system.build.toplevel", + flake, + build_host, + flake_build_flags={"flake": True}, + copy_flags={"copy": True}, + build_flags={"build": True}, + ) == Path("/path/to/file") + mock_run.assert_has_calls( + [ + call( + [ + "nix", + "--extra-experimental-features", + "nix-command flakes", + "eval", + "--raw", + ".#nixosConfigurations.hostname.config.system.build.toplevel.drvPath", + "--flake", + ], + stdout=PIPE, + ), + call( + [ + "nix-copy-closure", + "--copy", + "--to", + "user@host", + Path("/path/to/file"), + ], + extra_env={"NIX_SSHOPTS": "--ssh opts"}, + remote=None, + ), + call( + [ + "nix", + "--extra-experimental-features", + "nix-command flakes", + "build", + "/path/to/file^*", + "--print-out-paths", + "--build", + ], + remote=build_host, + stdout=PIPE, + ), + ] + ) + + @patch(get_qualified_name(n.run_wrapper, n), autospec=True) def test_copy_closure(mock_run: Any, monkeypatch: Any) -> None: closure = Path("/path/to/closure") @@ -211,173 +378,6 @@ def test_list_generations(mock_get_generations: Any, tmp_path: Path) -> None: ] -@patch( - get_qualified_name(n.run_wrapper, n), - autospec=True, - return_value=CompletedProcess([], 0, stdout=" \n/path/to/file\n "), -) -def test_nixos_build_flake(mock_run: Any) -> None: - flake = m.Flake.parse(".#hostname") - - assert n.nixos_build_flake( - "toplevel", - flake, - no_link=True, - nix_flag="foo", - ) == Path("/path/to/file") - mock_run.assert_called_with( - [ - "nix", - "--extra-experimental-features", - "nix-command flakes", - "build", - "--print-out-paths", - ".#nixosConfigurations.hostname.config.system.build.toplevel", - "--no-link", - "--nix-flag", - "foo", - ], - stdout=PIPE, - ) - - -@patch( - get_qualified_name(n.run_wrapper, n), - autospec=True, - return_value=CompletedProcess([], 0, stdout=" \n/path/to/file\n "), -) -def test_nixos_build(mock_run: Any, monkeypatch: Any) -> None: - assert n.nixos_build( - "attr", m.BuildAttr("", None), nix_flag="foo" - ) == Path("/path/to/file") - mock_run.assert_called_with( - [ - "nix-build", - "", - "--attr", - "config.system.build.attr", - "--nix-flag", - "foo", - ], - stdout=PIPE, - ) - - assert n.nixos_build("attr", m.BuildAttr(Path("file"), "preAttr")) == Path( - "/path/to/file" - ) - mock_run.assert_called_with( - ["nix-build", Path("file"), "--attr", "preAttr.config.system.build.attr"], - stdout=PIPE, - ) - - -@patch( - get_qualified_name(n.run_wrapper, n), - autospec=True, - return_value=CompletedProcess([], 0, stdout=" \n/path/to/file\n "), -) -def test_nixos_remote_build_flake(mock_run: Any) -> None: - flake = m.Flake.parse(".#hostname") - build_host = m.Remote("user@host", ["--ssh", "opts"], None) - - assert n.nixos_remote_build_flake( - "toplevel", - flake, - build_host, - flake_build_flags={"flake": True}, - copy_flags={"copy": True}, - build_flags={"build": True}, - ) == Path("/path/to/file") - mock_run.assert_has_calls( - [ - call( - [ - "nix", - "--extra-experimental-features", - "nix-command flakes", - "eval", - "--raw", - ".#nixosConfigurations.hostname.config.system.build.toplevel.drvPath", - "--flake", - ], - stdout=PIPE, - ), - call( - [ - "nix-copy-closure", - "--copy", - "--to", - "user@host", - Path("/path/to/file"), - ], - extra_env={"NIX_SSHOPTS": "--ssh opts"}, - remote=None, - ), - call( - [ - "nix", - "--extra-experimental-features", - "nix-command flakes", - "build", - "/path/to/file^*", - "--print-out-paths", - "--build", - ], - remote=build_host, - stdout=PIPE, - ), - ] - ) - - -@patch( - get_qualified_name(n.run_wrapper, n), - autospec=True, - return_value=CompletedProcess([], 0, stdout=" \n/path/to/file\n "), -) -def test_nixos_remote_build(mock_run: Any, monkeypatch: Any) -> None: - build_host = m.Remote("user@host", ["--ssh", "opts"], None) - assert n.nixos_remote_build( - "attr", - m.BuildAttr("", "preAttr"), - build_host, - build_flags={"build": True}, - instantiate_flags={"inst": True}, - copy_flags={"copy": True}, - ) == Path("/path/to/file") - mock_run.assert_has_calls( - [ - call( - [ - "nix-instantiate", - "--raw", - "", - "--attr", - "preAttr.config.system.build.attr", - "--inst", - ], - stdout=PIPE, - ), - call( - [ - "nix-copy-closure", - "--copy", - "--to", - "user@host", - Path("/path/to/file"), - ], - extra_env={"NIX_SSHOPTS": "--ssh opts"}, - remote=None, - ), - call( - ["nix-store", "--realise", Path("/path/to/file"), "--build"], - remote=build_host, - stdout=PIPE, - ), - ] - ) - - @patch(get_qualified_name(n.run_wrapper, n), autospec=True) def test_repl(mock_run: Any) -> None: n.repl("attr", m.BuildAttr("", None), nix_flag=True)