When `max-jobs = 0`, our async semaphores have null capacity and therefore no slot token can be acquired. In addition, a derivation with `preferLocalBuild = true` with `max-jobs = 0` which is not a built-in derivation is not considered suitable for being possible to build. Our documentation in `max-jobs` writes: > `0` is useful when using remote builders to prevent any local builds (except for preferLocalBuild derivation attribute which executes locally regardless). A valid interpretation is that `preferLocalBuild` derivations (all of them) will always execute even if `max-jobs = 0`. This CL achieves this promise by enabling `preferLocalBuild = true` derivations to draw in priority capacity from a `preferLocalBuild`-only pool and then fall back to the build pool (`maxBuildJobs`). If there's non-zero max-jobs, we make the `preferLocalBuild`-only pool empty. If there's zero max-jobs, we make the `preferLocalBuild`-only pool non-empty (capacity: 1). Remark 1: if `max-jobs = 0`, no non-`preferLocalBuild = true` derivations can be built without a remote builder and `preferLocalBuild = true` derivations can be built one at a time if `extra-local-jobs` is not overridden. Remark 2: if `max-jobs != 0`, no `preferLocalBuild = true` derivations can bypass capacity limits, i.e. `max-jobs` unless `extra-local-jobs` is overridden. Fixes #855. Change-Id: I00a0acac7375a881aec6281ebb13a4530b26e460 Signed-off-by: Raito Bezarius <raito@lix.systems>
65 lines
1.9 KiB
Python
65 lines
1.9 KiB
Python
import pytest
|
|
from testlib.fixtures.nix import Nix
|
|
from testlib.utils import get_global_asset
|
|
from testlib.fixtures.file_helper import with_files, File
|
|
|
|
|
|
drv = """
|
|
builtins.derivation {
|
|
name = "foo";
|
|
builder = /bin/sh;
|
|
system = builtins.currentSystem;
|
|
requiredSystemFeatures = [ "glitter" ];
|
|
}
|
|
"""
|
|
|
|
local_drv = """
|
|
with import ./config.nix; mkDerivation {
|
|
name = "foo";
|
|
buildCommand = ''
|
|
touch $out
|
|
'';
|
|
preferLocalBuild = true;
|
|
requiredSystemFeatures = [ "glitter" ];
|
|
}
|
|
"""
|
|
|
|
|
|
@pytest.fixture(autouse=True)
|
|
def set_features(nix: Nix):
|
|
nix.settings.system_features = "glitter"
|
|
|
|
|
|
def test_j0_without_remotes_fails(nix: Nix):
|
|
result = nix.nix_build(["-j0", "--expr", drv, "--builders", ""]).run().expect(1)
|
|
assert (
|
|
"error: unable to start any build; either set '--max-jobs' to a non-zero value or enable remote builds."
|
|
in result.stderr_s
|
|
)
|
|
|
|
|
|
def test_j0_with_mismatched_remotes_fails(nix: Nix):
|
|
remote = f"ssh://localhost?remote-store={nix.env.dirs.home}/machine1"
|
|
result = nix.nix_build(["-j0", "--expr", drv, "--builders", remote]).run().expect(1)
|
|
assert (
|
|
"error: unable to start any build; remote machines may not have all required system features."
|
|
in result.stderr_s
|
|
)
|
|
|
|
|
|
@with_files({"config.nix": get_global_asset("config.nix"), "default.nix": File(local_drv)})
|
|
def test_j0_without_local_jobs(nix: Nix):
|
|
result = nix.nix_build(["-j0", "--extra-local-jobs", "0"]).run().expect(1)
|
|
assert (
|
|
"error: unable to start any build; either set '--max-jobs' to a non-zero value or enable remote builds."
|
|
in result.stderr_s
|
|
)
|
|
|
|
|
|
@with_files({"config.nix": get_global_asset("config.nix"), "default.nix": File(local_drv)})
|
|
def test_j0_with_local_jobs(nix: Nix):
|
|
nix.nix_build(["-j0"]).run().ok()
|
|
|
|
|
|
# TODO(Raito): test -j1 --extra-local-jobs=1 in another file and ensure that preferLocalBuild *AND* another build job can run properly at the same time.
|