diff --git a/spin/cmds/meson.py b/spin/cmds/meson.py index 08a7cf3..49719fa 100644 --- a/spin/cmds/meson.py +++ b/spin/cmds/meson.py @@ -385,6 +385,8 @@ def build( if not (os.path.exists(build_dir) and _meson_version_configured(build_dir)): p = _run(setup_cmd, sys_exit=False, output=not quiet) if p.returncode != 0: + if quiet: + print(p.stdout.decode("utf-8"), end="") raise RuntimeError( "Meson configuration failed; please try `spin build` again with the `--clean` flag." ) diff --git a/spin/tests/test_meson.py b/spin/tests/test_meson.py index 79aaf2d..2ec7a29 100644 --- a/spin/tests/test_meson.py +++ b/spin/tests/test_meson.py @@ -4,11 +4,72 @@ from os.path import join as pjoin from os.path import normpath +import click import pytest from spin.cmds import meson from spin.containers import DotDict +# Fake meson: prints to stdout and stderr, and fails for subcommands in FAILING_CMDS +FAKE_MESON = """ +import sys + +FAILING_CMDS = {failing_cmds!r} + +subcommand = sys.argv[1] +print("fake meson " + subcommand + ": stdout") +print("fake meson " + subcommand + ": stderr", file=sys.stderr) +sys.exit(1 if subcommand in FAILING_CMDS else 0) +""" + + +@pytest.fixture +def fake_meson(tmp_path, monkeypatch): + """Return a factory that installs a fake meson and returns a build dir.""" + + def make(failing_cmds=()): + script = tmp_path / "meson.py" + script.write_text(FAKE_MESON.format(failing_cmds=list(failing_cmds))) + # Run the fake script in place of the meson binary + monkeypatch.setattr(meson, "_meson_cli", lambda: [sys.executable, str(script)]) + monkeypatch.setattr(meson, "get_config", lambda: DotDict({})) + return str(tmp_path / "build") + + return make + + +def test_quiet_configuration_failure_output(fake_meson, capfd): + build_dir = fake_meson(failing_cmds=["setup"]) + with pytest.raises(RuntimeError, match="Meson configuration failed"): + meson.build.callback( + meson_args=(), build_dir=build_dir, prefix="/usr", quiet=True + ) + captured = capfd.readouterr() + output = captured.out + captured.err + assert output.count("fake meson setup: stdout") == 1 + assert output.count("fake meson setup: stderr") == 1 + + +def test_run_configuration_failure_output(fake_meson, monkeypatch, capfd): + build_dir = fake_meson(failing_cmds=["setup"]) + monkeypatch.setattr(meson, "_get_configured_command", lambda name: meson.build) + with ( + click.Context(meson.run), + pytest.raises(RuntimeError, match="Meson configuration failed"), + ): + meson.run.callback(args=("unused-command",), build=True, build_dir=build_dir) + captured = capfd.readouterr() + assert "fake meson setup: stdout" in captured.err + assert "fake meson setup: stderr" in captured.err + assert "fake meson setup" not in captured.out + + +def test_successful_quiet_build_output(fake_meson, capfd): + build_dir = fake_meson() + meson.build.callback(meson_args=(), build_dir=build_dir, prefix="/usr", quiet=True) + captured = capfd.readouterr() + assert "fake meson" not in captured.out + captured.err + def make_paths(root, paths): for p in paths: