Commit c2ba67af authored by Thiago Kenji Okada's avatar Thiago Kenji Okada
Browse files

nixos-rebuild-ng: use namespaced imports for services

parent afab9af9
Loading
Loading
Loading
Loading
+7 −15
Original line number Diff line number Diff line
@@ -5,18 +5,10 @@ import sys
from subprocess import CalledProcessError, run
from typing import Final, assert_never

from . import nix
from . import nix, services
from .constants import EXECUTABLE, WITH_NIX_2_18, WITH_REEXEC, WITH_SHELL_FILES
from .models import Action, BuildAttr, Flake, Profile
from .process import Remote
from .services import (
    build_and_activate_system,
    edit,
    list_generations,
    reexec,
    repl,
    write_version_suffix,
)
from .utils import LogFormatter

logger: Final = logging.getLogger(__name__)
@@ -307,7 +299,7 @@ def execute(argv: list[str]) -> None:
        and not args.no_reexec
        and not os.environ.get("_NIXOS_REBUILD_REEXEC")
    ):
        reexec(argv, args, build_flags, flake_build_flags)
        services.reexec(argv, args, build_flags, flake_build_flags)

    profile = Profile.from_arg(args.profile_name)
    target_host = Remote.from_arg(args.target_host, args.ask_sudo_password)
@@ -316,7 +308,7 @@ def execute(argv: list[str]) -> None:
    flake = Flake.from_arg(args.flake, target_host)

    if can_run and not flake:
        write_version_suffix(build_flags)
        services.write_version_suffix(build_flags)

    match action:
        case (
@@ -330,7 +322,7 @@ def execute(argv: list[str]) -> None:
            | Action.BUILD_VM
            | Action.BUILD_VM_WITH_BOOTLOADER
        ):
            build_and_activate_system(
            services.build_and_activate_system(
                action=action,
                args=args,
                build_host=build_host,
@@ -346,16 +338,16 @@ def execute(argv: list[str]) -> None:
            )

        case Action.EDIT:
            edit(flake=flake, flake_build_flags=flake_build_flags)
            services.edit(flake=flake, flake_build_flags=flake_build_flags)

        case Action.DRY_RUN:
            raise AssertionError("DRY_RUN should be a DRY_BUILD alias")

        case Action.LIST_GENERATIONS:
            list_generations(args=args, profile=profile)
            services.list_generations(args=args, profile=profile)

        case Action.REPL:
            repl(
            services.repl(
                flake=flake,
                build_attr=build_attr,
                flake_build_flags=flake_build_flags,
+0 −87
Original line number Diff line number Diff line
@@ -8,7 +8,6 @@ from typing import Any
from unittest.mock import ANY, Mock, call, patch

import pytest
from pytest import MonkeyPatch

import nixos_rebuild as nr
from nixos_rebuild.constants import WITH_NIX_2_18
@@ -128,92 +127,6 @@ def test_parse_args() -> None:
    ]


@patch.dict(os.environ, {}, clear=True)
@patch("os.execve", autospec=True)
@patch(get_qualified_name(nr.nix.build), autospec=True)
def test_reexec(mock_build: Mock, mock_execve: Mock, monkeypatch: MonkeyPatch) -> None:
    monkeypatch.setattr(nr.services, "EXECUTABLE", "nixos-rebuild-ng")
    argv = ["/path/bin/nixos-rebuild-ng", "switch", "--no-flake"]
    args, _ = nr.parse_args(argv)
    mock_build.return_value = Path("/path")

    nr.reexec(argv, args, {"build": True}, {"flake": True})
    mock_build.assert_has_calls(
        [
            call(
                nr.services.NIXOS_REBUILD_ATTR,
                nr.models.BuildAttr(ANY, ANY),
                {"build": True, "no_out_link": True},
            )
        ]
    )
    # do not exec if there is no new version
    mock_execve.assert_not_called()

    mock_build.return_value = Path("/path/new")

    nr.reexec(argv, args, {}, {})
    # exec in the new version successfully
    mock_execve.assert_called_once_with(
        Path("/path/new/bin/nixos-rebuild-ng"),
        ["/path/bin/nixos-rebuild-ng", "switch", "--no-flake"],
        {"_NIXOS_REBUILD_REEXEC": "1"},
    )

    mock_execve.reset_mock()
    mock_execve.side_effect = [OSError("BOOM"), None]

    nr.reexec(argv, args, {}, {})
    # exec in the previous version if the new version fails
    mock_execve.assert_any_call(
        Path("/path/bin/nixos-rebuild-ng"),
        ["/path/bin/nixos-rebuild-ng", "switch", "--no-flake"],
        {"_NIXOS_REBUILD_REEXEC": "1"},
    )


@patch.dict(os.environ, {}, clear=True)
@patch("os.execve", autospec=True)
@patch(get_qualified_name(nr.nix.build_flake), autospec=True)
def test_reexec_flake(
    mock_build: Mock, mock_execve: Mock, monkeypatch: MonkeyPatch
) -> None:
    monkeypatch.setattr(nr.services, "EXECUTABLE", "nixos-rebuild-ng")
    argv = ["/path/bin/nixos-rebuild-ng", "switch", "--flake"]
    args, _ = nr.parse_args(argv)
    mock_build.return_value = Path("/path")

    nr.reexec(argv, args, {"build": True}, {"flake": True})
    mock_build.assert_called_once_with(
        nr.services.NIXOS_REBUILD_ATTR,
        nr.models.Flake(ANY, ANY),
        {"flake": True, "no_link": True},
    )
    # do not exec if there is no new version
    mock_execve.assert_not_called()

    mock_build.return_value = Path("/path/new")

    nr.reexec(argv, args, {}, {})
    # exec in the new version successfully
    mock_execve.assert_called_once_with(
        Path("/path/new/bin/nixos-rebuild-ng"),
        ["/path/bin/nixos-rebuild-ng", "switch", "--flake"],
        {"_NIXOS_REBUILD_REEXEC": "1"},
    )

    mock_execve.reset_mock()
    mock_execve.side_effect = [OSError("BOOM"), None]

    nr.reexec(argv, args, {}, {})
    # exec in the previous version if the new version fails
    mock_execve.assert_any_call(
        Path("/path/bin/nixos-rebuild-ng"),
        ["/path/bin/nixos-rebuild-ng", "switch", "--flake"],
        {"_NIXOS_REBUILD_REEXEC": "1"},
    )


@patch.dict(
    os.environ,
    {"NIXOS_REBUILD_I_UNDERSTAND_THE_CONSEQUENCES_PLEASE_BREAK_MY_SYSTEM": "1"},
+96 −0
Original line number Diff line number Diff line
import os
from pathlib import Path
from unittest.mock import ANY, Mock, call, patch

from pytest import MonkeyPatch

import nixos_rebuild as n
import nixos_rebuild.services as s

from .helpers import get_qualified_name


@patch.dict(os.environ, {}, clear=True)
@patch("os.execve", autospec=True)
@patch(get_qualified_name(s.nix.build), autospec=True)
def test_reexec(mock_build: Mock, mock_execve: Mock, monkeypatch: MonkeyPatch) -> None:
    monkeypatch.setattr(s, "EXECUTABLE", "nixos-rebuild-ng")
    argv = ["/path/bin/nixos-rebuild-ng", "switch", "--no-flake"]
    args, _ = n.parse_args(argv)
    mock_build.return_value = Path("/path")

    s.reexec(argv, args, {"build": True}, {"flake": True})
    mock_build.assert_has_calls(
        [
            call(
                s.NIXOS_REBUILD_ATTR,
                n.models.BuildAttr(ANY, ANY),
                {"build": True, "no_out_link": True},
            )
        ]
    )
    # do not exec if there is no new version
    mock_execve.assert_not_called()

    mock_build.return_value = Path("/path/new")

    s.reexec(argv, args, {}, {})
    # exec in the new version successfully
    mock_execve.assert_called_once_with(
        Path("/path/new/bin/nixos-rebuild-ng"),
        ["/path/bin/nixos-rebuild-ng", "switch", "--no-flake"],
        {"_NIXOS_REBUILD_REEXEC": "1"},
    )

    mock_execve.reset_mock()
    mock_execve.side_effect = [OSError("BOOM"), None]

    s.reexec(argv, args, {}, {})
    # exec in the previous version if the new version fails
    mock_execve.assert_any_call(
        Path("/path/bin/nixos-rebuild-ng"),
        ["/path/bin/nixos-rebuild-ng", "switch", "--no-flake"],
        {"_NIXOS_REBUILD_REEXEC": "1"},
    )


@patch.dict(os.environ, {}, clear=True)
@patch("os.execve", autospec=True)
@patch(get_qualified_name(s.nix.build_flake), autospec=True)
def test_reexec_flake(
    mock_build: Mock, mock_execve: Mock, monkeypatch: MonkeyPatch
) -> None:
    monkeypatch.setattr(s, "EXECUTABLE", "nixos-rebuild-ng")
    argv = ["/path/bin/nixos-rebuild-ng", "switch", "--flake"]
    args, _ = n.parse_args(argv)
    mock_build.return_value = Path("/path")

    s.reexec(argv, args, {"build": True}, {"flake": True})
    mock_build.assert_called_once_with(
        s.NIXOS_REBUILD_ATTR,
        n.models.Flake(ANY, ANY),
        {"flake": True, "no_link": True},
    )
    # do not exec if there is no new version
    mock_execve.assert_not_called()

    mock_build.return_value = Path("/path/new")

    s.reexec(argv, args, {}, {})
    # exec in the new version successfully
    mock_execve.assert_called_once_with(
        Path("/path/new/bin/nixos-rebuild-ng"),
        ["/path/bin/nixos-rebuild-ng", "switch", "--flake"],
        {"_NIXOS_REBUILD_REEXEC": "1"},
    )

    mock_execve.reset_mock()
    mock_execve.side_effect = [OSError("BOOM"), None]

    s.reexec(argv, args, {}, {})
    # exec in the previous version if the new version fails
    mock_execve.assert_any_call(
        Path("/path/bin/nixos-rebuild-ng"),
        ["/path/bin/nixos-rebuild-ng", "switch", "--flake"],
        {"_NIXOS_REBUILD_REEXEC": "1"},
    )