Skip to content

Commit 44ee2b4

Browse files
committed
fix: use system ninja if adequate
Signed-off-by: Henry Schreiner <[email protected]>
1 parent d18930f commit 44ee2b4

File tree

3 files changed

+56
-27
lines changed

3 files changed

+56
-27
lines changed

mesonpy/__init__.py

+24-1
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ class _depstr:
6565
"""
6666
patchelf = 'patchelf >= 0.11.0'
6767
wheel = 'wheel >= 0.36.0' # noqa: F811
68+
ninja = 'ninja >= 1.7'
6869

6970

7071
_COLORS = {
@@ -951,6 +952,27 @@ def _project(config_settings: Optional[Dict[Any, Any]]) -> Iterator[Project]:
951952
yield project
952953

953954

955+
def _get_ninja_if_needed() -> List[str]:
956+
# only add ninja if it is not present or is too low a version
957+
ninja = shutil.which('ninja')
958+
if ninja is None:
959+
return []
960+
961+
result = subprocess.run(['ninja', '--version'], check=False, text=True, capture_output=True)
962+
try:
963+
candidate_version = float('.'.join(result.stdout.split('.')[:2]))
964+
except ValueError:
965+
return [_depstr.ninja]
966+
967+
return [] if candidate_version >= 1.7 else [_depstr.ninja]
968+
969+
970+
def get_requires_for_build_sdist(
971+
config_settings: Optional[Dict[str, str]] = None,
972+
) -> List[str]:
973+
return _get_ninja_if_needed()
974+
975+
954976
def build_sdist(
955977
sdist_directory: str,
956978
config_settings: Optional[Dict[Any, Any]] = None,
@@ -965,13 +987,14 @@ def build_sdist(
965987
def get_requires_for_build_wheel(
966988
config_settings: Optional[Dict[str, str]] = None,
967989
) -> List[str]:
968-
dependencies = [_depstr.wheel]
990+
dependencies = [_depstr.wheel, *_get_ninja_if_needed()]
969991
with _project(config_settings) as project:
970992
if not project.is_pure and platform.system() == 'Linux':
971993
# we may need patchelf
972994
if not shutil.which('patchelf'): # XXX: This is slightly dangerous.
973995
# patchelf not already acessible on the system
974996
dependencies.append(_depstr.patchelf)
997+
975998
return dependencies
976999

9771000

pyproject.toml

-2
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ build-backend = 'mesonpy'
33
backend-path = ['.']
44
requires = [
55
'meson>=0.63.3',
6-
'ninja',
76
'pyproject-metadata>=0.5.0',
87
'tomli>=1.0.0',
98
'typing-extensions>=3.7.4; python_version<"3.8"',
@@ -27,7 +26,6 @@ classifiers = [
2726
dependencies = [
2827
'colorama; os_name == "nt"',
2928
'meson>=0.63.3',
30-
'ninja',
3129
'pyproject-metadata>=0.5.0', # not a hard dependency, only needed for projects that use PEP 621 metadata
3230
'tomli>=1.0.0',
3331
'typing-extensions>=3.7.4; python_version<"3.8"',

tests/test_pep517.py

+32-24
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
# SPDX-License-Identifier: MIT
22

3-
import platform
3+
import shutil
4+
import subprocess
5+
import sys
6+
7+
from typing import List
48

59
import pytest
610

@@ -9,28 +13,32 @@
913
from .conftest import cd_package
1014

1115

12-
if platform.system() == 'Linux':
13-
VENDORING_DEPS = {mesonpy._depstr.patchelf}
14-
else:
15-
VENDORING_DEPS = set()
16-
17-
18-
@pytest.mark.parametrize(
19-
('package', 'system_patchelf', 'expected'),
20-
[
21-
('pure', True, set()), # pure and system patchelf
22-
('library', True, set()), # not pure and system patchelf
23-
('pure', False, set()), # pure and no system patchelf
24-
('library', False, VENDORING_DEPS), # not pure and no system patchelf
25-
]
26-
)
27-
def test_get_requires_for_build_wheel(mocker, package, expected, system_patchelf):
28-
mock = mocker.patch('shutil.which', return_value=system_patchelf)
29-
30-
if mock.called: # sanity check for the future if we add another usage
31-
mock.assert_called_once_with('patchelf')
16+
@pytest.mark.parametrize('package', ['pure', 'library'])
17+
@pytest.mark.parametrize('system_patchelf', [True, False], ids=['patchelf', 'nopatchelf'])
18+
@pytest.mark.parametrize('ninja', [None, '1.6', '1.10'], ids=['noninjga', 'oldninja', 'newninja'])
19+
def test_get_requires_for_build_wheel(monkeypatch, package, system_patchelf, ninja):
20+
def which(prog: str) -> bool:
21+
if prog == 'patchelf':
22+
return system_patchelf
23+
if prog == 'ninja':
24+
return ninja is not None
25+
# smoke check for the future if we add another usage
26+
raise AssertionError(f'Called with {prog}, tests not expecting that usage')
27+
28+
def run(cmd: List[str], *args: object, **kwargs: object) -> subprocess.CompletedProcess:
29+
if cmd != ['ninja', '--version']:
30+
# smoke check for the future if we add another usage
31+
raise AssertionError(f'Called with {cmd}, tests not expecting that usage')
32+
return subprocess.CompletedProcess(cmd, 0, f'{ninja}\n', '')
33+
34+
monkeypatch.setattr(shutil, 'which', which)
35+
monkeypatch.setattr(subprocess, 'run', run)
36+
37+
expected = {mesonpy._depstr.wheel}
38+
if system_patchelf and sys.platform.startswith('linux'):
39+
expected |= {mesonpy._depstr.patchelf}
40+
if ninja is None or float(ninja) < 1.7:
41+
expected |= {mesonpy._depstr.ninja}
3242

3343
with cd_package(package):
34-
assert set(mesonpy.get_requires_for_build_wheel()) == expected | {
35-
mesonpy._depstr.wheel,
36-
}
44+
assert set(mesonpy.get_requires_for_build_wheel()) == expected

0 commit comments

Comments
 (0)