diff --git a/doc/manual/rl-next/nix-doctor.md b/doc/manual/rl-next/nix-doctor.md new file mode 100644 index 000000000..fcf2cd2be --- /dev/null +++ b/doc/manual/rl-next/nix-doctor.md @@ -0,0 +1,12 @@ +--- +synopsis: "Improve nix doctor" +cls: [5316, 5317, 5318, 5319, 5320] +category: Features +credits: [rootile, raito] +--- +The `nix doctor` diagnosics interface now provides a lot more useful information including, but not limited to: +- General system information (OS, Hardware etc) +- Nix Information like Sandbox, Version, Store, State and other directories +- Flake registry +- Search path Information +- Nixpkgs provenance diff --git a/lix/nix/doctor.cc b/lix/nix/doctor.cc index b7a36df36..b5062f59a 100644 --- a/lix/nix/doctor.cc +++ b/lix/nix/doctor.cc @@ -113,6 +113,10 @@ struct CmdDoctor : StoreCommand printInfo("Collecting information about the ambient Nix search paths"); success &= checkAmbientNixSearchPaths(); } + { + printInfo("Collecting information about Nixpkgs provenance"); + success &= checkNixpkgsProvenance(); + } if (!success) throw Exit(2); @@ -221,6 +225,41 @@ struct CmdDoctor : StoreCommand checkInfo(fmt("Overridden Nix configuration search path: %s", nixPathS)); } + // Parse all entries one by one to construct the search path. + for (auto entry : evalSettings.nixPath.get()) { + auto elem = SearchPath::Elem::parse(entry); + auto prefix = elem.prefix.s.empty() ? elem.path.s : elem.prefix.s; + searchPathFacts[prefix] = { + .originReference = entry, + }; + } + + return true; + } + + bool checkNixpkgsProvenance() + { + if (!searchPathFacts.contains("nixpkgs")) { + return checkFail( + "Search path does not contain nixpkgs. All evaluations using nixpkgs (including nix-shell) " + "will fail." + ); + } + + auto entry = searchPathFacts["nixpkgs"]; + checkInfo(fmt("Nixpkgs provenance: %s", entry.originReference)); + try { + auto nixpkgsVersion = aio().blockOn(runProgram( + "nix-instantiate", + true, + {"--eval", "--raw", "--expr", "(import { }).lib.version"}, + false + )); + checkInfo(fmt("Nixpkgs version: %s", nixpkgsVersion)); + } catch (...) { + return checkFail("Failed obtaining the nixpkgs version: nixpkgs is either broken or invalid"); + } + return true; } diff --git a/tests/functional/remote-store.sh b/tests/functional/remote-store.sh index e8d8e20f3..7dac4f47f 100644 --- a/tests/functional/remote-store.sh +++ b/tests/functional/remote-store.sh @@ -2,9 +2,6 @@ source common.sh clearStore -# Ensure "fake ssh" remote store works just as legacy fake ssh would. -nix --store ssh-ng://localhost?remote-store=$TEST_ROOT/other-store doctor - # Ensure that store ping trusted works with ssh-ng:// nix --store ssh-ng://localhost?remote-store=$TEST_ROOT/other-store store ping --json | jq -e '.trusted' diff --git a/tests/functional2/cli/test_doctor.py b/tests/functional2/cli/test_doctor.py new file mode 100644 index 000000000..9d61569bb --- /dev/null +++ b/tests/functional2/cli/test_doctor.py @@ -0,0 +1,39 @@ +from testlib.fixtures.nix import Nix +import pytest + + +pytestmark = pytest.mark.no_daemon + + +@pytest.mark.usefixtures("fake_nixpkgs") +def test_doctor_local_store(nix: Nix): + res = nix.nix(["doctor", "-v"]).run().ok() + out = res.stderr_plain + assert "[PASS] All profiles are gcroots." in out + assert "[PASS] Client protocol matches store protocol." in out + assert "You are trusted" in out + assert "[FAIL] Error: current generation cannot be discovered" in out + + +@pytest.mark.usefixtures("fake_nixpkgs") +def test_doctor_remote_store(nix: Nix): + res = ( + nix.nix( + [ + "--store", + f"ssh-ng://localhost?remote-store={nix.env.dirs.test_root}/other-store", + "doctor", + ] + ) + .run() + .ok() + ) + assert "Running checks against store uri ssh-ng://localhost" in res.stderr_plain + + +@pytest.mark.usefixtures("fake_nixpkgs") +def test_doctor_nixpkgs(nix: Nix): + res = nix.nix(["doctor", "-v"], flake=True).run().ok() + out = res.stderr_plain + + assert "[INFO] Nixpkgs provenance: nixpkgs=" in out diff --git a/tests/functional2/store/test_local_store.py b/tests/functional2/store/test_local_store.py index 35ac0495b..2ad5ce106 100644 --- a/tests/functional2/store/test_local_store.py +++ b/tests/functional2/store/test_local_store.py @@ -39,6 +39,7 @@ class TestLocalStore: info = nix.nix(["--store", "./x", "store", "ping", "--json"]).run().json() assert info["trusted"] + @pytest.mark.usefixtures("fake_nixpkgs") def test_doctor_shows_trust(self, nix: Nix): result = nix.nix(["--store", "./x", "doctor"]).run().ok() assert "You are trusted by" in result.stderr_plain