diff --git a/pkgs/by-name/ni/nixos-rebuild-ng/README.md b/pkgs/by-name/ni/nixos-rebuild-ng/README.md index a6199e873060..f34c3d4996ef 100644 --- a/pkgs/by-name/ni/nixos-rebuild-ng/README.md +++ b/pkgs/by-name/ni/nixos-rebuild-ng/README.md @@ -126,7 +126,7 @@ ruff format . - [ ] Change module system to allow easier opt-in, like `system.switch.enableNg` for `switch-to-configuration-ng` - [ ] Improve documentation -- [ ] `nixos-rebuild repl` (calling old `nixos-rebuild` for now) +- [x] `nixos-rebuild repl` - [ ] `nix` build/bootstrap - [ ] Generate tab completion via [`shtab`](https://docs.iterative.ai/shtab/) - [x] Reduce build closure diff --git a/pkgs/by-name/ni/nixos-rebuild-ng/package.nix b/pkgs/by-name/ni/nixos-rebuild-ng/package.nix index b111c7cb108a..4ef9d29807f5 100644 --- a/pkgs/by-name/ni/nixos-rebuild-ng/package.nix +++ b/pkgs/by-name/ni/nixos-rebuild-ng/package.nix @@ -39,11 +39,6 @@ python3Packages.buildPythonApplication rec { nix ]; - preBuild = '' - substituteInPlace nixos_rebuild/__init__.py \ - --subst-var-by nixos_rebuild ${lib.getExe nixos-rebuild} - ''; - postInstall = '' installManPage ${nixos-rebuild}/share/man/man8/nixos-rebuild.8 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 a83718c89587..f57991800404 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 @@ -1,7 +1,6 @@ import argparse import atexit import json -import os import sys from pathlib import Path from subprocess import run 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 4009996609c7..aeaea3bf03c9 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 @@ -1,6 +1,8 @@ import os from datetime import datetime +from importlib.resources import files from pathlib import Path +from string import Template from subprocess import PIPE, CalledProcessError from typing import Final @@ -18,6 +20,7 @@ from .process import run_wrapper from .utils import Args, dict_to_flags, info FLAKE_FLAGS: Final = ["--extra-experimental-features", "nix-command flakes"] +FLAKE_REPL_TEMPLATE: Final = "repl.template.nix" def copy_closure( @@ -279,6 +282,41 @@ def nixos_build_flake( return Path(r.stdout.strip()) +def repl(attr: str, build_attr: BuildAttr | None, **nix_flags: Args) -> None: + run_args: list[str | Path] = ["nix", "repl", "--file"] + if build_attr: + run_args.append(build_attr.path) + if build_attr.attr: + run_args.append(build_attr.attr) + run_wrapper([*run_args, *dict_to_flags(nix_flags)]) + else: + run_wrapper([*run_args, "", *dict_to_flags(nix_flags)]) + + +def repl_flake(attr: str, flake: Flake, **flake_flags: Args) -> None: + expr = Template( + files(__package__).joinpath(FLAKE_REPL_TEMPLATE).read_text() + ).substitute( + flake_path=flake.path, + flake_attr=flake.attr, + bold="\033[1m", + blue="\033[34;1m", + attention="\033[35;1m", + reset="\033[0m", + ) + run_wrapper( + [ + "nix", + *FLAKE_FLAGS, + "repl", + "--impure", + "--expr", + expr, + *dict_to_flags(flake_flags), + ] + ) + + def rollback(profile: Profile, target_host: Remote | None, sudo: bool) -> Path: "Rollback Nix profile, like one created by `nixos-rebuild switch`." run_wrapper( diff --git a/pkgs/by-name/ni/nixos-rebuild-ng/src/nixos_rebuild/repl.template.nix b/pkgs/by-name/ni/nixos-rebuild-ng/src/nixos_rebuild/repl.template.nix new file mode 100644 index 000000000000..0fffd6ecc746 --- /dev/null +++ b/pkgs/by-name/ni/nixos-rebuild-ng/src/nixos_rebuild/repl.template.nix @@ -0,0 +1,40 @@ +let + flake = builtins.getFlake ''${flake_path}''; + configuration = flake.${flake_attr}; + motd = '' + $${"\n"} + Hello and welcome to the NixOS configuration + ${flake_attr} + in ${flake_path} + + The following is loaded into nix repl's scope: + + - ${blue}config${reset} All option values + - ${blue}options${reset} Option data and metadata + - ${blue}pkgs${reset} Nixpkgs package set + - ${blue}lib${reset} Nixpkgs library functions + - other module arguments + + - ${blue}flake${reset} Flake outputs, inputs and source info of ${flake_path} + + Use tab completion to browse around ${blue}config${reset}. + + Use ${bold}:r${reset} to ${bold}reload${reset} everything after making a change in the flake. + (assuming ${flake_path} is a mutable flake ref) + + See ${bold}:?${reset} for more repl commands. + + ${attention}warning:${reset} nixos-rebuild repl does not currently enforce pure evaluation. + ''; + scope = + assert configuration._type or null == ''configuration''; + assert configuration.class or ''nixos'' == ''nixos''; + configuration._module.args + // configuration._module.specialArgs + // { + inherit (configuration) config options; + lib = configuration.lib or configuration.pkgs.lib; + inherit flake; + }; +in +builtins.seq scope builtins.trace motd scope diff --git a/pkgs/by-name/ni/nixos-rebuild-ng/src/pyproject.toml b/pkgs/by-name/ni/nixos-rebuild-ng/src/pyproject.toml index f26b3cba7056..0dc662814c33 100644 --- a/pkgs/by-name/ni/nixos-rebuild-ng/src/pyproject.toml +++ b/pkgs/by-name/ni/nixos-rebuild-ng/src/pyproject.toml @@ -9,6 +9,9 @@ version = "0.0.0" [project.scripts] nixos-rebuild = "nixos_rebuild:main" +[tool.setuptools.package-data] +nixos_rebuild = ["*.template.nix"] + [tool.mypy] # `--strict` config, but explicit options to avoid breaking build when mypy is # updated diff --git a/pkgs/by-name/ni/nixos-rebuild-ng/src/tests/test_models.py b/pkgs/by-name/ni/nixos-rebuild-ng/src/tests/test_models.py index a2646eaec416..1a604ad53164 100644 --- a/pkgs/by-name/ni/nixos-rebuild-ng/src/tests/test_models.py +++ b/pkgs/by-name/ni/nixos-rebuild-ng/src/tests/test_models.py @@ -17,9 +17,7 @@ def test_building_attr_from_arg() -> None: assert m.BuildAttr.from_arg("attr", "file.nix") == m.BuildAttr( Path("file.nix"), "attr" ) - assert m.BuildAttr.from_arg(None, "file.nix") == m.BuildAttr( - Path("file.nix"), None - ) + assert m.BuildAttr.from_arg(None, "file.nix") == m.BuildAttr(Path("file.nix"), None) def test_flake_parse() -> None: 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 0d6079e8eb5b..92411a0f5488 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 @@ -248,6 +248,25 @@ def test_nixos_build(mock_run: Any, monkeypatch: Any) -> None: ) +@patch(get_qualified_name(n.run_wrapper, n), autospec=True) +def test_repl(mock_run: Any) -> None: + n.repl("attr", None, nix_flag=True) + mock_run.assert_called_with( + ["nix", "repl", "--file", "", "--nix-flag"] + ) + + n.repl("attr", m.BuildAttr(Path("file.nix"), "myAttr")) + mock_run.assert_called_with(["nix", "repl", "--file", Path("file.nix"), "myAttr"]) + + +@patch(get_qualified_name(n.run_wrapper, n), autospec=True) +def test_repl_flake(mock_run: Any) -> None: + n.repl_flake("attr", m.Flake(Path("flake.nix"), "myAttr"), nix_flag=True) + # This method would be really annoying to test, and it is not that important + # So just check that we are at least calling it + assert mock_run.called + + @patch(get_qualified_name(n.run_wrapper, n), autospec=True) def test_rollback(mock_run: Any, tmp_path: Path) -> None: path = tmp_path / "test"