Closes #496 When running nix-build ../nixpkgs --arg config.allowUnfree true -A hello-unfree the package `hello-unfree` is now built rather than getting an eval-error rejecting instantiation. This is because `config.allowUnfree` is now interpreted as nested attribute-set declaration, similar to how it's done in `nix repl`. To prevent sudden breakage, this behavior was carefully deprecated with Nix throwing an error if the identifier for `--arg` is not a pure identifier, but an expression as above. Any kind of merging is rejected. I.e. doing nix-build ../nixpkgs --arg config '{cudaSupport = true;}' --arg config.allowUnfree true is prohibited. That way we don't have to think about merge semantics for cases like this (or even worse `--arg config 'rec { ... }'`). Another nice side-effect of this is that we don't need to create an EvalState to force the values and implement merging. Change-Id: I8b560883a4468a3f32f915764b08f5fdd8fe71bb
111 lines
3.0 KiB
Python
111 lines
3.0 KiB
Python
from typing import Any
|
|
|
|
import pytest
|
|
|
|
from testlib.fixtures.nix import Nix
|
|
|
|
|
|
def do_evaluate(nix: Nix, args: list[str], expect_success: bool = True) -> dict[str, Any] | str:
|
|
res = (
|
|
nix.nix_instantiate(
|
|
[
|
|
"--eval",
|
|
"--json",
|
|
"-E",
|
|
"{ arg1, arg2 ? null }: { inherit arg1 arg2; }",
|
|
"--strict",
|
|
*args,
|
|
]
|
|
)
|
|
.run()
|
|
.expect(0 if expect_success else 1)
|
|
)
|
|
|
|
if expect_success:
|
|
return res.json()
|
|
return res.stderr_s
|
|
|
|
|
|
def test_trivial(nix: Nix):
|
|
res = do_evaluate(nix, args=["--arg", "arg1", "[ 1 2 3 ]", "--arg", "arg2", "1"])
|
|
|
|
assert res["arg1"] == [1, 2, 3]
|
|
assert res["arg2"] == 1
|
|
|
|
|
|
def test_recursive(nix: Nix):
|
|
res = do_evaluate(
|
|
nix,
|
|
args=["--arg", "arg1.foo.bar", "1", "--arg", "arg1.foo.baz", "2", "--arg", "arg1.bar", "3"],
|
|
)
|
|
|
|
assert res["arg1"] == {"foo": {"bar": 1, "baz": 2}, "bar": 3}
|
|
assert res["arg2"] is None
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
("attribute_path", "expected"),
|
|
[("arg1", 2), ("arg1.foo", {"foo": 2}), ("arg1.foo.bar", {"foo": {"bar": 2}})],
|
|
)
|
|
def test_override(nix: Nix, attribute_path: str, expected: Any):
|
|
res = do_evaluate(nix, args=["--arg", attribute_path, "1", "--arg", attribute_path, "2"])
|
|
|
|
assert res["arg1"] == expected
|
|
|
|
|
|
def test_quoting(nix: Nix):
|
|
res = do_evaluate(
|
|
nix,
|
|
args=[
|
|
"--arg",
|
|
"arg1.foo.bar",
|
|
"1",
|
|
"--arg",
|
|
'arg1."foo bar baz".baz',
|
|
"2",
|
|
"--arg",
|
|
"arg1.bar",
|
|
"2",
|
|
],
|
|
)
|
|
|
|
assert res["arg1"] == {"foo": {"bar": 1}, "bar": 2, "foo bar baz": {"baz": 2}}
|
|
assert res["arg2"] is None
|
|
|
|
|
|
def test_quoting_error(nix: Nix):
|
|
res = do_evaluate(nix, ["--arg", 'arg1."foo bar.baz', "1"], expect_success=False)
|
|
assert "error: missing closing quote in selection path 'arg1.\"foo bar.baz'" in res
|
|
|
|
|
|
def test_trailing_dot(nix: Nix):
|
|
# This is what `parseAttrPath` from `libutil` does and is consistent with the selection path
|
|
# passed to e.g. `nix-build -A`.
|
|
res = do_evaluate(nix, args=["--arg", "arg1.bar.", "[ 1 2 3 ]"], expect_success=False)
|
|
|
|
assert (
|
|
"error: Trailing dot on the right-hand side of path expr 'arg1.bar.' is not allowed!" in res
|
|
)
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"args",
|
|
[
|
|
["--arg", "arg1.foo", "1", "--arg", "arg1.foo.bar", "2"],
|
|
["--arg", "arg1.foo.bar", "2", "--arg", "arg1.foo", "1"],
|
|
],
|
|
)
|
|
def test_conflict(nix: Nix, args: list[str]):
|
|
res = do_evaluate(nix, args, expect_success=False)
|
|
|
|
assert (
|
|
"error: Cannot set arg1.foo.bar via --arg/--argstr when it's the path-extension of another auto-argument!"
|
|
in res
|
|
)
|
|
|
|
|
|
@pytest.mark.parametrize("selection", ["foo..bar", "foo.bar.."])
|
|
def test_no_empty_items(nix: Nix, selection: str):
|
|
res = do_evaluate(nix, ["--arg", selection, "1"], expect_success=False)
|
|
assert f"error: consecutive dots not allowed in selection path '{selection}'" in res
|