nixos-rebuild-ng: fix --option parse, make --quiet a count (#374063)

This commit is contained in:
Thiago Kenji Okada
2025-01-17 13:17:32 +00:00
committed by GitHub
6 changed files with 87 additions and 20 deletions
@@ -27,6 +27,7 @@ def get_parser() -> tuple[argparse.ArgumentParser, dict[str, argparse.ArgumentPa
default=0,
help="Enable verbose logging (includes nix)",
)
common_flags.add_argument("--quiet", action="count", default=0)
common_flags.add_argument("--max-jobs", "-j")
common_flags.add_argument("--cores")
common_flags.add_argument("--log-format")
@@ -34,12 +35,11 @@ def get_parser() -> tuple[argparse.ArgumentParser, dict[str, argparse.ArgumentPa
common_flags.add_argument("--keep-failed", "-K", action="store_true")
common_flags.add_argument("--fallback", action="store_true")
common_flags.add_argument("--repair", action="store_true")
common_flags.add_argument("--option", nargs=2)
common_flags.add_argument("--option", nargs=2, action="append")
common_build_flags = argparse.ArgumentParser(add_help=False)
common_build_flags.add_argument("--builders")
common_build_flags.add_argument("--include", "-I", action="append")
common_build_flags.add_argument("--quiet", action="store_true")
common_build_flags.add_argument("--print-build-logs", "-L", action="store_true")
common_build_flags.add_argument("--show-trace", action="store_true")
@@ -54,8 +54,8 @@ def get_parser() -> tuple[argparse.ArgumentParser, dict[str, argparse.ArgumentPa
flake_common_flags.add_argument("--no-write-lock-file", action="store_true")
flake_common_flags.add_argument("--no-registries", action="store_true")
flake_common_flags.add_argument("--commit-lock-file", action="store_true")
flake_common_flags.add_argument("--update-input")
flake_common_flags.add_argument("--override-input", nargs=2)
flake_common_flags.add_argument("--update-input", action="append")
flake_common_flags.add_argument("--override-input", nargs=2, action="append")
classic_build_flags = argparse.ArgumentParser(add_help=False)
classic_build_flags.add_argument("--no-build-output", "-Q", action="store_true")
@@ -52,7 +52,7 @@ class BuildAttr:
attr: str | None
def to_attr(self, *attrs: str) -> str:
return f"{self.attr + '.' if self.attr else ''}{".".join(attrs)}"
return f"{self.attr + '.' if self.attr else ''}{'.'.join(attrs)}"
@classmethod
def from_arg(cls, attr: str | None, file: str | None) -> Self:
@@ -68,7 +68,7 @@ class Flake:
_re: ClassVar = re.compile(r"^(?P<path>[^\#]*)\#?(?P<attr>[^\#\"]*)$")
def to_attr(self, *attrs: str) -> str:
return f"{self}.{".".join(attrs)}"
return f"{self}.{'.'.join(attrs)}"
@override
def __str__(self) -> str:
@@ -83,7 +83,7 @@ class Flake:
m = cls._re.match(flake_str)
assert m is not None, f"got no matches for {flake_str}"
attr = m.group("attr")
nixos_attr = f"nixosConfigurations.{attr or hostname_fn() or "default"}"
nixos_attr = f"nixosConfigurations.{attr or hostname_fn() or 'default'}"
path = m.group("path")
if ":" in path:
return cls(path, nixos_attr)
@@ -15,7 +15,7 @@ SSH_DEFAULT_OPTS: Final = [
"-o",
"ControlMaster=auto",
"-o",
f"ControlPath={tmpdir.TMPDIR_PATH / "ssh-%n"}",
f"ControlPath={tmpdir.TMPDIR_PATH / 'ssh-%n'}",
"-o",
"ControlPersist=60",
]
@@ -2,7 +2,7 @@ import logging
from collections.abc import Mapping, Sequence
from typing import Any, assert_never, override
type Arg = bool | str | list[str] | int | None
type Arg = bool | str | list[str] | list[list[str]] | int | None
type Args = dict[str, Arg]
@@ -43,9 +43,13 @@ def dict_to_flags(d: Args | None) -> list[str]:
flags.append(flag)
flags.append(value)
case list():
for v in value:
for vs in value:
flags.append(flag)
flags.append(v)
if isinstance(vs, list):
for v in vs:
flags.append(v)
else:
flags.append(vs)
case _:
assert_never(value)
return flags
@@ -40,8 +40,21 @@ def test_parse_args() -> None:
"--flake",
"/etc/nixos",
"--option",
"foo",
"bar",
"foo1",
"bar1",
"--option",
"foo2",
"bar2",
"--override-input",
"override1",
"input1",
"--override-input",
"override2",
"input2",
"--update-input",
"input1",
"--update-input",
"input2",
]
)
assert nr.logger.level == logging.INFO
@@ -50,8 +63,27 @@ def test_parse_args() -> None:
assert r1.install_grub is True
assert r1.profile_name == "system"
assert r1.action == "switch"
assert r1.option == ["foo", "bar"]
assert g1["common_flags"].option == ["foo", "bar"]
# round-trip test (ensure that we have the same flags as parsed)
assert nr.utils.dict_to_flags(vars(g1["common_flags"])) == [
"--option",
"foo1",
"bar1",
"--option",
"foo2",
"bar2",
]
assert nr.utils.dict_to_flags(vars(g1["flake_common_flags"])) == [
"--update-input",
"input1",
"--update-input",
"input2",
"--override-input",
"override1",
"input1",
"--override-input",
"override2",
"input2",
]
r2, g2 = nr.parse_args(
[
@@ -63,7 +95,13 @@ def test_parse_args() -> None:
"foo",
"--attr",
"bar",
"-I",
"include1",
"-I",
"include2",
"-vvv",
"--quiet",
"--quiet",
]
)
assert nr.logger.level == logging.DEBUG
@@ -72,7 +110,18 @@ def test_parse_args() -> None:
assert r2.action == "dry-build"
assert r2.file == "foo"
assert r2.attr == "bar"
assert g2["common_flags"].v == 3
# round-trip test (ensure that we have the same flags as parsed)
assert nr.utils.dict_to_flags(vars(g2["common_flags"])) == [
"-vvv",
"--quiet",
"--quiet",
]
assert nr.utils.dict_to_flags(vars(g2["common_build_flags"])) == [
"--include",
"include1",
"--include",
"include2",
]
@patch.dict(nr.process.os.environ, {}, clear=True)
@@ -292,6 +341,10 @@ def test_execute_nix_switch_flake(mock_run: Any, tmp_path: Path) -> None:
"--sudo",
"--verbose",
"--fast",
# https://github.com/NixOS/nixpkgs/issues/374050
"--option",
"narinfo-cache-negative-ttl",
"1200",
]
)
@@ -307,6 +360,9 @@ def test_execute_nix_switch_flake(mock_run: Any, tmp_path: Path) -> None:
"--print-out-paths",
"/path/to/config#nixosConfigurations.hostname.config.system.build.toplevel",
"-v",
"--option",
"narinfo-cache-negative-ttl",
"1200",
"--no-link",
],
check=True,
@@ -11,10 +11,11 @@ def test_dict_to_flags() -> None:
"test_flag_2": False,
"test_flag_3": "value",
"test_flag_4": ["v1", "v2"],
"test_flag_5": None,
"test_flag_5": [["o1", "v1"], ["o2", "v2"]],
"test_flag_6": None,
"t": True,
"v": 5,
"verbose": 2,
"quiet": 2,
}
)
assert r1 == [
@@ -25,10 +26,16 @@ def test_dict_to_flags() -> None:
"v1",
"--test-flag-4",
"v2",
"--test-flag-5",
"o1",
"v1",
"--test-flag-5",
"o2",
"v2",
"-t",
"-vvvvv",
"--verbose",
"--verbose",
"--quiet",
"--quiet",
]
r2 = u.dict_to_flags({"verbose": 0, "empty_list": []})
assert r2 == []