Allow passing config_settings to the build backend
Resolves: https://bugzilla.redhat.com/2192581
This commit is contained in:
parent
638ba27daf
commit
156e2fc8fe
@ -4,4 +4,4 @@
|
||||
# this macro will cause the package with the real macro to be installed.
|
||||
# When macros.pyproject is installed, it overrides this macro.
|
||||
# Note: This needs to maintain the same set of options as the real macro.
|
||||
%pyproject_buildrequires(rRxtNwe:) echo 'pyproject-rpm-macros' && exit 0
|
||||
%pyproject_buildrequires(rRxtNwe:C:) echo 'pyproject-rpm-macros' && exit 0
|
||||
|
@ -26,11 +26,11 @@
|
||||
# The value is read and used by the %%pytest and %%tox macros:
|
||||
%_set_pytest_addopts %global __pytest_addopts --ignore=%{_pyproject_builddir}
|
||||
|
||||
%pyproject_wheel() %{expand:\\\
|
||||
%pyproject_wheel(C:) %{expand:\\\
|
||||
%_set_pytest_addopts
|
||||
mkdir -p "%{_pyproject_builddir}"
|
||||
CFLAGS="${CFLAGS:-${RPM_OPT_FLAGS}}" LDFLAGS="${LDFLAGS:-${RPM_LD_FLAGS}}" TMPDIR="%{_pyproject_builddir}" \\\
|
||||
%{__python3} -Bs %{_rpmconfigdir}/redhat/pyproject_wheel.py %{_pyproject_wheeldir}
|
||||
%{__python3} -Bs %{_rpmconfigdir}/redhat/pyproject_wheel.py %{?**} %{_pyproject_wheeldir}
|
||||
}
|
||||
|
||||
|
||||
@ -140,7 +140,7 @@ fi
|
||||
|
||||
|
||||
# Note: Keep the options in sync with this macro from macros.aaa-pyproject-srpm
|
||||
%pyproject_buildrequires(rRxtNwe:) %{expand:\\\
|
||||
%pyproject_buildrequires(rRxtNwe:C:) %{expand:\\\
|
||||
%_set_pytest_addopts
|
||||
# The _auto_set_build_flags feature does not do this in %%generate_buildrequires section,
|
||||
# but we want to get an environment consistent with %%build:
|
||||
|
@ -13,7 +13,7 @@ License: MIT
|
||||
# Increment Y and reset Z when new macros or features are added
|
||||
# Increment Z when this is a bugfix or a cosmetic change
|
||||
# Dropping support for EOL Fedoras is *not* considered a breaking change
|
||||
Version: 1.8.1
|
||||
Version: 1.9.0
|
||||
Release: 1%{?dist}
|
||||
|
||||
# Macro files
|
||||
@ -161,6 +161,10 @@ export HOSTNAME="rpmbuild" # to speedup tox in network-less mock, see rhbz#1856
|
||||
|
||||
|
||||
%changelog
|
||||
* Wed May 31 2023 Maxwell G <maxwell@gtmx.me> - 1.9.0-1
|
||||
- Allow passing config_settings to the build backend.
|
||||
- Resolves: rhbz#2192581
|
||||
|
||||
* Wed May 31 2023 Miro Hrončok <mhroncok@redhat.com> - 1.8.1-1
|
||||
- On Python older than 3.11, use tomli instead of deprecated toml
|
||||
- Fix literal %% handling in %%{pyproject_files} on RPM 4.19
|
||||
|
@ -14,6 +14,7 @@ import pathlib
|
||||
import zipfile
|
||||
|
||||
from pyproject_requirements_txt import convert_requirements_txt
|
||||
from pyproject_wheel import parse_config_settings_args
|
||||
|
||||
|
||||
# Some valid Python version specifiers are not supported.
|
||||
@ -67,7 +68,7 @@ def guess_reason_for_invalid_requirement(requirement_str):
|
||||
class Requirements:
|
||||
"""Requirement gatherer. The macro will eventually print out output_lines."""
|
||||
def __init__(self, get_installed_version, extras=None,
|
||||
generate_extras=False, python3_pkgversion='3'):
|
||||
generate_extras=False, python3_pkgversion='3', config_settings=None):
|
||||
self.get_installed_version = get_installed_version
|
||||
self.output_lines = []
|
||||
self.extras = set()
|
||||
@ -81,6 +82,7 @@ class Requirements:
|
||||
|
||||
self.generate_extras = generate_extras
|
||||
self.python3_pkgversion = python3_pkgversion
|
||||
self.config_settings = config_settings
|
||||
|
||||
def add_extras(self, *extras):
|
||||
self.extras |= set(e.strip() for e in extras)
|
||||
@ -269,7 +271,7 @@ def get_backend(requirements):
|
||||
def generate_build_requirements(backend, requirements):
|
||||
get_requires = getattr(backend, 'get_requires_for_build_wheel', None)
|
||||
if get_requires:
|
||||
new_reqs = get_requires()
|
||||
new_reqs = get_requires(config_settings=requirements.config_settings)
|
||||
requirements.extend(new_reqs, source='get_requires_for_build_wheel')
|
||||
requirements.check(source='get_requires_for_build_wheel')
|
||||
|
||||
@ -303,7 +305,7 @@ def generate_run_requirements_hook(backend, requirements):
|
||||
'Use the provisional -w flag to build the wheel and parse the metadata from it, '
|
||||
'or use the -R flag not to generate runtime dependencies.'
|
||||
)
|
||||
dir_basename = prepare_metadata('.')
|
||||
dir_basename = prepare_metadata('.', config_settings=requirements.config_settings)
|
||||
with open(dir_basename + '/METADATA') as metadata_file:
|
||||
name, requires = package_name_and_requires_from_metadata_file(metadata_file)
|
||||
for key, req in requires.items():
|
||||
@ -327,7 +329,11 @@ def generate_run_requirements_wheel(backend, requirements, wheeldir):
|
||||
wheel = find_built_wheel(wheeldir)
|
||||
if not wheel:
|
||||
import pyproject_wheel
|
||||
returncode = pyproject_wheel.build_wheel(wheeldir=wheeldir, stdout=sys.stderr)
|
||||
returncode = pyproject_wheel.build_wheel(
|
||||
wheeldir=wheeldir,
|
||||
stdout=sys.stderr,
|
||||
config_settings=requirements.config_settings,
|
||||
)
|
||||
if returncode != 0:
|
||||
raise RuntimeError('Failed to build the wheel for %pyproject_buildrequires -w.')
|
||||
wheel = find_built_wheel(wheeldir)
|
||||
@ -415,7 +421,7 @@ def generate_requires(
|
||||
*, include_runtime=False, build_wheel=False, wheeldir=None, toxenv=None, extras=None,
|
||||
get_installed_version=importlib.metadata.version, # for dep injection
|
||||
generate_extras=False, python3_pkgversion="3", requirement_files=None, use_build_system=True,
|
||||
output,
|
||||
output, config_settings=None,
|
||||
):
|
||||
"""Generate the BuildRequires for the project in the current directory
|
||||
|
||||
@ -426,7 +432,8 @@ def generate_requires(
|
||||
requirements = Requirements(
|
||||
get_installed_version, extras=extras or [],
|
||||
generate_extras=generate_extras,
|
||||
python3_pkgversion=python3_pkgversion
|
||||
python3_pkgversion=python3_pkgversion,
|
||||
config_settings=config_settings,
|
||||
)
|
||||
|
||||
try:
|
||||
@ -516,6 +523,12 @@ def main(argv):
|
||||
metavar='REQUIREMENTS.TXT',
|
||||
help=('Add buildrequires from file'),
|
||||
)
|
||||
parser.add_argument(
|
||||
'-C',
|
||||
dest='config_settings',
|
||||
action='append',
|
||||
help='Configuration settings to pass to the PEP 517 backend',
|
||||
)
|
||||
|
||||
args = parser.parse_args(argv)
|
||||
|
||||
@ -550,6 +563,7 @@ def main(argv):
|
||||
requirement_files=args.requirement_files,
|
||||
use_build_system=args.use_build_system,
|
||||
output=args.output,
|
||||
config_settings=parse_config_settings_args(args.config_settings),
|
||||
)
|
||||
except Exception:
|
||||
# Log the traceback explicitly (it's useful debug info)
|
||||
|
@ -986,3 +986,40 @@ Self-referencing extras (maze):
|
||||
python3dist(rightdep)
|
||||
python3dist(startdep)
|
||||
result: 0
|
||||
|
||||
config_settings_control:
|
||||
include_runtime: false
|
||||
config_settings:
|
||||
pyproject.toml: |
|
||||
[build-system]
|
||||
build-backend = "test_backend"
|
||||
backend-path = ["."]
|
||||
test_backend.py: |
|
||||
def get_requires_for_build_wheel(config_settings=None):
|
||||
if not (config_settings is None or isinstance(config_settings, dict)):
|
||||
raise TypeError
|
||||
if config_settings and "test-config-setting" in config_settings:
|
||||
return ["test-config-setting"]
|
||||
return ["test-no-config-setting"]
|
||||
expected: |
|
||||
python3dist(test-no-config-setting)
|
||||
result: 0
|
||||
|
||||
config_settings:
|
||||
include_runtime: false
|
||||
config_settings:
|
||||
test-config-setting: ""
|
||||
pyproject.toml: |
|
||||
[build-system]
|
||||
build-backend = "test_backend"
|
||||
backend-path = ["."]
|
||||
test_backend.py: |
|
||||
def get_requires_for_build_wheel(config_settings=None):
|
||||
if not (config_settings is None or isinstance(config_settings, dict)):
|
||||
raise TypeError
|
||||
if config_settings and "test-config-setting" in config_settings:
|
||||
return ["test-config-setting"]
|
||||
return ["test-no-config-setting"]
|
||||
expected: |
|
||||
python3dist(test-config-setting)
|
||||
result: 0
|
||||
|
@ -1,8 +1,37 @@
|
||||
import argparse
|
||||
import sys
|
||||
import subprocess
|
||||
|
||||
|
||||
def build_wheel(*, wheeldir, stdout=None):
|
||||
def parse_config_settings_args(config_settings):
|
||||
"""
|
||||
Given a list of config `KEY=VALUE` formatted config settings,
|
||||
return a dictionary that can be passed to PEP 517 hook functions.
|
||||
"""
|
||||
if not config_settings:
|
||||
return config_settings
|
||||
new_config_settings = {}
|
||||
for arg in config_settings:
|
||||
key, _, value = arg.partition('=')
|
||||
new_config_settings[key] = value
|
||||
return new_config_settings
|
||||
|
||||
|
||||
def get_config_settings_args(config_settings):
|
||||
"""
|
||||
Given a dictionary of PEP 517 backend config_settings,
|
||||
yield --config-settings args that can be passed to pip's CLI
|
||||
"""
|
||||
if not config_settings:
|
||||
return
|
||||
for key, value in config_settings.items():
|
||||
if value == '':
|
||||
yield f'--config-settings={key}'
|
||||
else:
|
||||
yield f'--config-settings={key}={value}'
|
||||
|
||||
|
||||
def build_wheel(*, wheeldir, stdout=None, config_settings=None):
|
||||
command = (
|
||||
sys.executable,
|
||||
'-m', 'pip',
|
||||
@ -15,11 +44,26 @@ def build_wheel(*, wheeldir, stdout=None):
|
||||
'--no-clean',
|
||||
'--progress-bar', 'off',
|
||||
'--verbose',
|
||||
*get_config_settings_args(config_settings),
|
||||
'.',
|
||||
)
|
||||
cp = subprocess.run(command, stdout=stdout)
|
||||
return cp.returncode
|
||||
|
||||
|
||||
def parse_args(argv=None):
|
||||
parser = argparse.ArgumentParser(prog='%pyproject_wheel')
|
||||
parser.add_argument('wheeldir', help=argparse.SUPPRESS)
|
||||
parser.add_argument(
|
||||
'-C',
|
||||
dest='config_settings',
|
||||
action='append',
|
||||
help='Configuration settings to pass to the PEP 517 backend',
|
||||
)
|
||||
args = parser.parse_args(argv)
|
||||
args.config_settings = parse_config_settings_args(args.config_settings)
|
||||
return args
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.exit(build_wheel(wheeldir=sys.argv[1]))
|
||||
sys.exit(build_wheel(**vars(parse_args())))
|
||||
|
@ -63,6 +63,7 @@ def test_data(case_name, capfd, tmp_path, monkeypatch):
|
||||
requirement_files=requirement_files,
|
||||
use_build_system=use_build_system,
|
||||
output=output,
|
||||
config_settings=case.get('config_settings'),
|
||||
)
|
||||
except SystemExit as e:
|
||||
assert e.code == case['result']
|
||||
|
50
tests/config-settings-test.spec
Normal file
50
tests/config-settings-test.spec
Normal file
@ -0,0 +1,50 @@
|
||||
Name: config-settings-test
|
||||
Version: 1.0.0
|
||||
Release: 1%{?dist}
|
||||
Summary: Test config_settings support
|
||||
|
||||
License: MIT
|
||||
URL: ...
|
||||
Source0: config_settings_test_backend.py
|
||||
|
||||
|
||||
%description
|
||||
%{summary}.
|
||||
|
||||
|
||||
%prep
|
||||
%autosetup -cT
|
||||
|
||||
cp -p %{sources} .
|
||||
|
||||
cat <<'EOF' >config_settings.py
|
||||
"""
|
||||
This is a test package
|
||||
"""
|
||||
EOF
|
||||
|
||||
cat <<'EOF' >pyproject.toml
|
||||
[build-system]
|
||||
build-backend = "config_settings_test_backend"
|
||||
backend-path = ["."]
|
||||
requires = ["flit-core"]
|
||||
|
||||
[project]
|
||||
name = "config_settings"
|
||||
version = "%{version}"
|
||||
dynamic = ["description"]
|
||||
EOF
|
||||
|
||||
|
||||
%generate_buildrequires
|
||||
%pyproject_buildrequires -C abc=123 -C xyz=456 -C--option-with-dashes=1
|
||||
%pyproject_buildrequires -C abc=123 -C xyz=456 -C--option-with-dashes=1 -w
|
||||
|
||||
|
||||
%build
|
||||
%pyproject_wheel -C abc=123 -C xyz=456 -C--option-with-dashes=1
|
||||
|
||||
|
||||
%changelog
|
||||
* Fri May 19 2023 Maxwell G <maxwell@gtmx.me>
|
||||
- Initial package
|
31
tests/config_settings_test_backend.py
Normal file
31
tests/config_settings_test_backend.py
Normal file
@ -0,0 +1,31 @@
|
||||
"""
|
||||
This is a test backend for pyproject-rpm-macros' integration tests
|
||||
It is not compliant with PEP 517 and omits some required hooks.
|
||||
"""
|
||||
|
||||
from flit_core import buildapi
|
||||
|
||||
EXPECTED_CONFIG_SETTINGS = {"abc": "123", "xyz": "456", "--option-with-dashes": "1"}
|
||||
|
||||
|
||||
def _verify_config_settings(config_settings):
|
||||
print(f"config_settings={config_settings}")
|
||||
if config_settings != EXPECTED_CONFIG_SETTINGS:
|
||||
raise ValueError(
|
||||
f"{config_settings!r} does not match expected {EXPECTED_CONFIG_SETTINGS!r}"
|
||||
)
|
||||
|
||||
|
||||
def build_wheel(wheel_directory, config_settings=None, metadata_directory=None):
|
||||
_verify_config_settings(config_settings)
|
||||
return buildapi.build_wheel(wheel_directory, None, metadata_directory)
|
||||
|
||||
|
||||
def get_requires_for_build_wheel(config_settings=None):
|
||||
_verify_config_settings(config_settings)
|
||||
return buildapi.get_requires_for_build_wheel(None)
|
||||
|
||||
|
||||
def prepare_metadata_for_build_wheel(metadata_directory, config_settings=None):
|
||||
_verify_config_settings(config_settings)
|
||||
return buildapi.prepare_metadata_for_build_wheel(metadata_directory, None)
|
@ -94,6 +94,9 @@
|
||||
- escape_percentages:
|
||||
dir: .
|
||||
run: ./mocktest.sh escape_percentages
|
||||
- config-settings-test:
|
||||
dir: .
|
||||
run: ./mocktest.sh config-settings-test
|
||||
required_packages:
|
||||
- mock
|
||||
- rpmdevtools
|
||||
|
Loading…
Reference in New Issue
Block a user