diff --git a/README.md b/README.md index 812f959..a654d83 100644 --- a/README.md +++ b/README.md @@ -190,11 +190,14 @@ Is roughly equivalent to: If you use `%pyproject_wheel` to build multiple wheels, for example like this: - %pyproject_wheel -d project_a - %pyproject_wheel -d project_b + %pyproject_wheel --directory directory1/ + %pyproject_wheel --directory directory2/ You still only call `%pyproject_install` once and it will install all such wheels. -Support for `%pyproject_save_files` with multiple wheels is not implemented. +To use `%pyproject_save_files` (and optionally `%pyproject_check_import`) with multiple wheels, +use the `-D`/`--dist-name` option to select a specific package, +for details, see *Generating the %files section* +(and *Performing an import check on all importable modules*). If you use `%pyproject_buildrequires -d ...` for multiple co-dependent packages in one spec file, it will create one or more build time dependencies @@ -413,6 +416,17 @@ If you wish to rename, remove or otherwise change the installed files of a packa If possible, remove/rename such files in `%prep`. If not possible, avoid using `%pyproject_save_files` or edit/replace `%{pyproject_files}`. +When processing files from multiple Python packages +(most likely as a result of multiple `%pyproject_wheel` invocations), +use the `-D`/`--dist-name` option to select a specific package +in `%pyproject_save_files` and `%{pyproject_files}`: + + %pyproject_save_files --dist-name package_a module_glob_a... + %pyproject_save_files --dist-name package_b module_glob_b... + + %files -n python3-package-a -f %{pyproject_files -D package_a} + %files -n python3-package-b -f %{pyproject_files -D package_b} + Performing an import check on all importable modules ---------------------------------------------------- @@ -460,6 +474,15 @@ The `%pyproject_check_import` macro also accepts positional arguments with additional qualified module names to check, useful for example if some modules are installed manually. Note that filtering by `-t`/`--top-level-only`/`-e`/`--exclude` also applies to the positional arguments. +When listing files from multiple Python packages via `%pyproject_save_files -D`/`--dist-name`, +pass `-D`/`--dist-name` to `%pyproject_check_import` as well. + + %pyproject_save_files --dist-name package_a module_glob_a... + %pyproject_save_files --dist-name package_b module_glob_b... + + %pyproject_check_import --dist-name package_a + %pyproject_check_import --dist-name package_b + Another macro, `%_pyproject_check_import_allow_no_modules` allows to pass the import check, even if no Python modules are detected in the package. This may be a valid case for packages containing e.g. typing stubs. @@ -496,6 +519,13 @@ These arguments are still required: * Positional arguments: the extra name(s). Multiple subpackages are generated when multiple names are provided. +When processing files from multiple Python packages +(see *Generating the %files section* for details), +pass `-D` to `%pyproject_extras_subpkg` as well: + + %pyproject_extras_subpkg -n python3-package-a -D package_a extra1 + %pyproject_extras_subpkg -n python3-package-b -D package_b extra2 + Provisional: Declarative Buildsystem (RPM 4.20+) ------------------------------------------------ @@ -603,19 +633,21 @@ Here is a complete reference of all options: ### `%pyproject_save_files` -| Short | Long | Description | -|-------|-----------------------|-------------------------------------------------| -| `-l` | `--assert-license` | Fail when no License-File (PEP 639) is found | -| `-L` | `--no-assert-license` | Don't fail on missing License-File (default) | -| `-M` | `--allow-no-modules` | Allow no module globs | -| `-a` | `--auto` | Include non-module files (same as `+auto`) | +| Short | Long | Description | +|------------|------------------------|--------------------------------------------------------------| +| `-l` | `--assert-license` | Fail when no License-File (PEP 639) is found | +| `-L` | `--no-assert-license` | Don't fail on missing License-File (default) | +| `-M` | `--allow-no-modules` | Allow no module globs | +| `-D NAME` | `--dist-name NAME` | Save files for a specific distribution package (multi-wheel) | +| `-a` | `--auto` | Include non-module files (same as `+auto`) | ### `%pyproject_check_import` -| Short | Long | Description | -|-----------|--------------------|------------------------------------| -| `-e GLOB` | `--exclude GLOB` | Exclude module names matching glob | -| `-t` | `--top-level-only` | Only check top-level modules | +| Short | Long | Description | +|-----------|-----------------------|---------------------------------------------------| +| `-e GLOB` | `--exclude GLOB` | Exclude module names matching glob | +| `-D NAME` | `--dist-name NAME` | Check imports for a specific distribution package | +| `-t` | `--top-level-only` | Only check top-level modules | ### `%tox` diff --git a/macros.pyproject b/macros.pyproject index 4fcfde3..ce3065d 100644 --- a/macros.pyproject +++ b/macros.pyproject @@ -20,9 +20,28 @@ # %%_pyproject_files_prefix defined in srpm macros -%pyproject_files %{_builddir}/%{_pyproject_files_prefix}-pyproject-files -%_pyproject_modules %{_builddir}/%{_pyproject_files_prefix}-pyproject-modules -%_pyproject_ghost_distinfo %{_builddir}/%{_pyproject_files_prefix}-pyproject-ghost-distinfo +# PEP 503 name normalization: lowercase, one or more [-_.] → single - +%__pyproject_normalize_name(-) %{lua:print((rpm.expand("%1"):lower():gsub("[%-_.]+", "-")))} + +%_pyproject_files_base %{_builddir}/%{_pyproject_files_prefix}-pyproject-files +%_pyproject_modules_base %{_builddir}/%{_pyproject_files_prefix}-pyproject-modules +%_pyproject_ghost_distinfo_base %{_builddir}/%{_pyproject_files_prefix}-pyproject-ghost-distinfo + +%pyproject_files(-) %{lua: +require("fedora.rpm.pyproject_getopt").getopt({ + {short="D", long="dist-name", value=true}, +})}%{_pyproject_files_base}%{?__pyproject_opt_D:-%{__pyproject_normalize_name %{__pyproject_opt_D}}} + +%_pyproject_modules(-) %{lua: +require("fedora.rpm.pyproject_getopt").getopt({ + {short="D", long="dist-name", value=true}, +})}%{_pyproject_modules_base}%{?__pyproject_opt_D:-%{__pyproject_normalize_name %{__pyproject_opt_D}}} + +%_pyproject_ghost_distinfo(-) %{lua: +require("fedora.rpm.pyproject_getopt").getopt({ + {short="D", long="dist-name", value=true}, +})}%{_pyproject_ghost_distinfo_base}%{?__pyproject_opt_D:-%{__pyproject_normalize_name %{__pyproject_opt_D}}} + %_pyproject_record %{_builddir}/%{_pyproject_files_prefix}-pyproject-record %_pyproject_buildrequires %{_builddir}/%{_pyproject_files_prefix}-pyproject-buildrequires # %%_pyproject_dep_overrides defined in srpm macros @@ -95,7 +114,7 @@ if [ -d %{buildroot}%{_bindir} ]; then %py3_shebang_fix %{buildroot}%{_bindir}/* rm -rfv %{buildroot}%{_bindir}/__pycache__ fi -rm -f %{_pyproject_ghost_distinfo} +rm -f %{_pyproject_ghost_distinfo_base} site_dirs=() # Process %%{python3_sitelib} if exists if [ -d %{buildroot}%{python3_sitelib} ]; then @@ -108,7 +127,12 @@ fi # Process all *.dist-info dirs in sitelib/sitearch for site_dir in ${site_dirs[@]}; do for distinfo in %{buildroot}$site_dir/*.dist-info; do - echo "%ghost %dir ${distinfo#%{buildroot}}" >> %{_pyproject_ghost_distinfo} + echo "%ghost %dir ${distinfo#%{buildroot}}" >> %{_pyproject_ghost_distinfo_base} + _normalized=$(PYTHONPATH=%{_rpmconfigdir}/redhat \\ + %{__python3} -sBc \\ + "import sys; from pyproject_save_files import canonical_name_from_distinfo; print(canonical_name_from_distinfo(sys.argv[1]))" \\ + "$(basename ${distinfo})") + echo "%ghost %dir ${distinfo#%{buildroot}}" >> "%{_pyproject_ghost_distinfo_base}-${_normalized}" sed -i 's/pip/rpm/' ${distinfo}/INSTALLER PYTHONPATH=%{_rpmconfigdir}/redhat \\ %{__python3} -B %{_rpmconfigdir}/redhat/pyproject_preprocess_record.py \\ @@ -122,16 +146,17 @@ for site_dir in ${site_dirs[@]}; do fi done done -lines=$(wc -l %{_pyproject_ghost_distinfo} | cut -f1 -d" ") +lines=$(wc -l %{_pyproject_ghost_distinfo_base} | cut -f1 -d" ") if [ $lines -ne 1 ]; then - echo -e "\\n\\nWARNING: %%%%pyproject_extras_subpkg won't work without explicit -i or -F, found $lines dist-info directories.\\n\\n" >&2 - rm %{_pyproject_ghost_distinfo} # any attempt to use this will fail + echo -e "%%%%pyproject_extras_subpkg will require -D or explicit -i/-F with multiple dist-info directories (found $lines)." >&2 + rm %{_pyproject_ghost_distinfo_base} # any attempt to use this will fail fi } # Note: the three times nested questionmarked -i -f -F pattern means: If none of those options was used -- in that case, we inject our own -f -%pyproject_extras_subpkg(n:i:f:FaA) %{expand:%{?python_extras_subpkg:%{python_extras_subpkg%{!?-i:%{!?-f:%{!?-F: -f %{_pyproject_ghost_distinfo}}}} %**}}} +# -D selects the per-package ghost distinfo file for multi-wheel installs +%pyproject_extras_subpkg(n:i:f:FaAD:) %{expand:%{?python_extras_subpkg:%{python_extras_subpkg%{!?-i:%{!?-f:%{!?-F: -f %{_pyproject_ghost_distinfo %{?-D}}}}} %{?-n} %{?-i} %{?-f} %{?-F} %{?-a} %{?-A} %*}}} # Escaping shell-globs, percentage signs and spaces was reworked in RPM 4.19+ @@ -144,12 +169,13 @@ fi {short="L", long="no-assert-license"}, {short="M", long="allow-no-modules"}, {short="a", long="auto"}, + {short="D", long="dist-name", value=true}, })}\ %{expand:\\\ %{expr:v"0%{?rpmversion}" >= v"4.18.90" ? "RPM_FILES_ESCAPE=4.19" : "RPM_FILES_ESCAPE=4.18" } \\ %{__python3} %{_rpmconfigdir}/redhat/pyproject_save_files.py \\ - --output-files "%{pyproject_files}" \\ - --output-modules "%{_pyproject_modules}" \\ + --output-files "%{pyproject_files %{?__pyproject_opt_D:-D %{__pyproject_opt_D}}}" \\ + --output-modules "%{_pyproject_modules %{?__pyproject_opt_D:-D %{__pyproject_opt_D}}}" \\ --buildroot "%{buildroot}" \\ --sitelib "%{python3_sitelib}" \\ --sitearch "%{python3_sitearch}" \\ @@ -162,23 +188,32 @@ fi %pyproject_check_import(-) \ %{lua:require("fedora.rpm.pyproject_getopt").getopt({ {short="e", long="exclude", value=true, separator=" -e "}, + {short="D", long="dist-name", value=true}, {short="t", long="top-level-only"}, })}\ %{expand:\\\ -if [ ! -f "%{_pyproject_modules}" ]; then - echo 'ERROR: %%%%pyproject_check_import only works when %%%%pyproject_save_files is used' >&2 +if [ ! -f "%{_pyproject_modules %{?__pyproject_opt_D:-D %{__pyproject_opt_D}}}" ]; then + _modules_glob=( %{_pyproject_modules_base}-* ) + if [ -e "${_modules_glob[0]}" ]; then + _available=$(printf '%%s\n' "${_modules_glob[@]}" | sed 's|.*-pyproject-modules-||' | tr '\n' ' ') + echo "ERROR: %%%%pyproject_check_import requires -D when %%%%pyproject_save_files was called with -D" >&2 + echo "Available -D values: ${_available}" >&2 + else + echo 'ERROR: %%%%pyproject_check_import only works when %%%%pyproject_save_files is used' >&2 + fi exit 1 fi -%py3_check_import -f "%{_pyproject_modules}" %{?__pyproject_opt_e:-e %{__pyproject_opt_e}} %{?__pyproject_opt_t:-t} %{?__pyproject_positional_args} +%py3_check_import -f "%{_pyproject_modules %{?__pyproject_opt_D:-D %{__pyproject_opt_D}}}" %{?__pyproject_opt_e:-e %{__pyproject_opt_e}} %{?__pyproject_opt_t:-t} %{?__pyproject_positional_args} } %_pyproject_check_import_allow_no_modules(-) \ %{lua:require("fedora.rpm.pyproject_getopt").getopt({ {short="e", long="exclude", value=true, separator=" -e "}, + {short="D", long="dist-name", value=true}, {short="t", long="top-level-only"}, })}\ -if [ -z "$(cat %{_pyproject_modules})" ]; then\ +if [ -z "$(cat %{_pyproject_modules %{?__pyproject_opt_D:-D %{__pyproject_opt_D}}})" ]; then\ echo "No modules to check found, exiting check"\ else\ %pyproject_check_import %{?**}\ diff --git a/pyproject-rpm-macros.spec b/pyproject-rpm-macros.spec index 7c22dc4..58ce702 100644 --- a/pyproject-rpm-macros.spec +++ b/pyproject-rpm-macros.spec @@ -14,7 +14,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.22.2 +Version: 1.23.0 Release: 1%{?dist} # Macro files @@ -179,6 +179,9 @@ export HOSTNAME="rpmbuild" # to speedup tox in network-less mock, see rhbz#1856 %changelog +* Mon May 18 2026 Miro Hrončok - 1.23.0-1 +- %%pyproject_save_files: Implement support for multi-package specfiles + * Thu May 14 2026 Miro Hrončok - 1.22.2-1 - %%pyproject_buildrequires: Fix "Requirement satisfied/not satisfied" messages to show overridden constraints from %%pyproject_patch_dependency - %%pyproject_buildrequires: Stop using deprecated argparse.FileType diff --git a/pyproject_save_files.py b/pyproject_save_files.py index 46fbbda..f5df963 100644 --- a/pyproject_save_files.py +++ b/pyproject_save_files.py @@ -8,6 +8,7 @@ from collections import defaultdict from keyword import iskeyword from pathlib import PosixPath, PurePosixPath from importlib.metadata import Distribution +from packaging.utils import canonicalize_name # From RPM's build/files.c strtokWithQuotes delim argument @@ -45,6 +46,24 @@ MANDIRS = [ ] +def canonical_name_from_distinfo(distinfo_dir_name): + """Extract the canonicalized distribution name from a .dist-info directory name. + + Examples: + + >>> canonical_name_from_distinfo('MarkupSafe-2.0.1.dist-info') + 'markupsafe' + + >>> canonical_name_from_distinfo('tldr-0.5.dist-info') + 'tldr' + + >>> canonical_name_from_distinfo('My.Package_name-1.0.dist-info') + 'my-package-name' + """ + raw = distinfo_dir_name.removesuffix('.dist-info').rsplit('-', 1)[0] + return canonicalize_name(raw) + + class BuildrootPath(PurePosixPath): """ This path represents a path in a buildroot. @@ -760,15 +779,31 @@ def parse_varargs(varargs): return globs, include_auto -def load_parsed_record(pyproject_record): +def load_parsed_record(pyproject_record, dist_name=None): parsed_record = {} with open(pyproject_record) as pyproject_record_file: content = json.load(pyproject_record_file) - if len(content) > 1: - raise FileExistsError("%pyproject_install has found more than one *.dist-info/RECORD file. " - "Currently, %pyproject_save_files supports only one wheel → one file list mapping. " - "Feel free to open a bugzilla for pyproject-rpm-macros and describe your usecase.") + # Map each record path to its canonical dist name + dist_names = {rp: canonical_name_from_distinfo(BuildrootPath(rp).parent.name) + for rp in content} + available = sorted(dist_names.values()) # used in error messages + + if dist_name: + normalized_target = canonicalize_name(dist_name) + content = {rp: files for rp, files in content.items() + if dist_names[rp] == normalized_target} + if not content: + raise ValueError( + f"No dist-info found matching dist name '{dist_name}'. " + f"Available: {', '.join(available)}" + ) + elif len(content) > 1: + raise ValueError( + "%pyproject_install has found more than one *.dist-info/RECORD file. " + "Use %pyproject_save_files -D to select a package. " + f"Available: {', '.join(available)}" + ) # Redefine strings stored in JSON to BuildRootPaths for record_path, files in content.items(): @@ -786,12 +821,12 @@ def dist_metadata(buildroot, record_path): return dist.metadata -def pyproject_save_files_and_modules(buildroot, sitelib, sitearch, python_version, pyproject_record, prefix, assert_license, allow_no_modules, auto, varargs): +def pyproject_save_files_and_modules(buildroot, sitelib, sitearch, python_version, pyproject_record, prefix, assert_license, allow_no_modules, auto, varargs, dist_name=None): """ Takes arguments from the %{pyproject_save_files} macro - Returns tuple: list of paths for the %files section and list of module names - for the %check section + Returns tuple: list of paths for the %files section, list of module names + for the %check section, and list of record paths (BuildrootPaths) Raises ValueError when assert_license is true and no License-File (PEP 639) is found. @@ -811,7 +846,7 @@ def pyproject_save_files_and_modules(buildroot, sitelib, sitearch, python_versio raise ValueError( "%pyproject_save_files -M cannot be used together with module globs." ) - parsed_records = load_parsed_record(pyproject_record) + parsed_records = load_parsed_record(pyproject_record, dist_name) final_file_list = [] final_module_list = [] @@ -842,11 +877,11 @@ def pyproject_save_files_and_modules(buildroot, sitelib, sitearch, python_versio "and include the %license file in %files manually." ) - return final_file_list, final_module_list + return final_file_list, final_module_list, list(parsed_records) def main(cli_args): - file_section, module_names = pyproject_save_files_and_modules( + file_section, module_names, record_paths = pyproject_save_files_and_modules( cli_args.buildroot, cli_args.sitelib, cli_args.sitearch, @@ -857,10 +892,24 @@ def main(cli_args): cli_args.allow_no_modules, cli_args.auto, cli_args.varargs, + cli_args.dist_name, ) - cli_args.output_files.write_text("\n".join(file_section) + "\n", encoding="utf-8") - cli_args.output_modules.write_text("\n".join(module_names) + "\n", encoding="utf-8") + files_text = "\n".join(file_section) + "\n" + modules_text = "\n".join(module_names) + "\n" + + cli_args.output_files.write_text(files_text, encoding="utf-8") + cli_args.output_modules.write_text(modules_text, encoding="utf-8") + + # When no -D was given, also write to the named path (derived from dist-info) + # so that %{pyproject_files -D name} works even without -D in %pyproject_save_files + if not cli_args.dist_name: + record_path = record_paths[0] + normalized = canonical_name_from_distinfo(record_path.parent.name) + named_files = PosixPath(f"{cli_args.output_files}-{normalized}") + named_modules = PosixPath(f"{cli_args.output_modules}-{normalized}") + named_files.write_text(files_text, encoding="utf-8") + named_modules.write_text(modules_text, encoding="utf-8") def argparser(): @@ -897,6 +946,10 @@ def argparser(): "-M", "--allow-no-modules", action="store_true", default=False, help="Don't fail when no globs are provided, only include non-modules data in the generated filelist.", ) + parser.add_argument( + "-D", "--dist-name", type=str, default=None, + help="Save files for a specific distribution package (for multi-wheel installs).", + ) parser.add_argument( "-a", "--auto", action="store_true", default=False, help="Include all non-module, non-sitelib files (same as +auto).", diff --git a/test_pyproject_save_files.py b/test_pyproject_save_files.py index 5ee5893..0486201 100755 --- a/test_pyproject_save_files.py +++ b/test_pyproject_save_files.py @@ -6,7 +6,7 @@ from pprint import pprint from pyproject_preprocess_record import parse_record, read_record, save_parsed_record -from pyproject_save_files import argparser, generate_file_list, BuildrootPath +from pyproject_save_files import argparser, canonical_name_from_distinfo, generate_file_list, BuildrootPath from pyproject_save_files import main as save_files_main from pyproject_save_files import module_names_from_path @@ -242,12 +242,12 @@ def test_cli_no_pyproject_record(tmp_path, pyproject_record): def test_cli_too_many_RECORDS(tldr_root, output_files, output_modules, pyproject_record): # Two calls to simulate how %pyproject_install process more than one RECORD file prepare_pyproject_record(tldr_root, - content=("foo/bar/dist-info/RECORD", [])) + content=("foo/bar-1.0.dist-info/RECORD", [])) prepare_pyproject_record(tldr_root, - content=("foo/baz/dist-info/RECORD", [])) + content=("foo/baz-2.0.dist-info/RECORD", [])) cli_args = argparser().parse_args([*default_options(output_files, output_modules, tldr_root, pyproject_record), "tldr*"]) - with pytest.raises(FileExistsError): + with pytest.raises(ValueError, match="Use %pyproject_save_files -D"): save_files_main(cli_args) @@ -277,3 +277,66 @@ def test_cli_bad_namespace(tldr_root, output_files, output_modules, pyproject_re with pytest.raises(ValueError): save_files_main(cli_args) + + +def test_canonical_name_from_distinfo(): + assert canonical_name_from_distinfo("MarkupSafe-2.0.1.dist-info") == "markupsafe" + assert canonical_name_from_distinfo("tldr-0.5.dist-info") == "tldr" + assert canonical_name_from_distinfo("my_package-1.0.0.dist-info") == "my-package" + assert canonical_name_from_distinfo("zope.event-1.0.dist-info") == "zope-event" + + +def test_cli_with_dist_name(tldr_root, pyproject_record): + output_files = tldr_root / "files" + output_modules = tldr_root / "modules" + cli_args = argparser().parse_args([ + *default_options(output_files, output_modules, tldr_root, pyproject_record), + "-D", "tldr", + "tldr*", + ]) + save_files_main(cli_args) + assert output_files.exists() + assert "tldr" in output_files.read_text() + assert output_modules.exists() + + +def test_cli_with_dist_name_case_insensitive(tldr_root, pyproject_record): + output_files = tldr_root / "files" + output_modules = tldr_root / "modules" + cli_args = argparser().parse_args([ + *default_options(output_files, output_modules, tldr_root, pyproject_record), + "-D", "TLDR", + "tldr*", + ]) + save_files_main(cli_args) + assert output_files.exists() + + +def test_cli_dist_name_not_found(tldr_root, pyproject_record): + output_files = tldr_root / "files" + output_modules = tldr_root / "modules" + cli_args = argparser().parse_args([ + *default_options(output_files, output_modules, tldr_root, pyproject_record), + "-D", "nonexistent", + "tldr*", + ]) + with pytest.raises(ValueError, match="No dist-info found matching"): + save_files_main(cli_args) + + +def test_cli_single_record_named_output(tldr_root, pyproject_record): + output_files = tldr_root / "files" + output_modules = tldr_root / "modules" + cli_args = argparser().parse_args([ + *default_options(output_files, output_modules, tldr_root, pyproject_record), + "tldr*", + ]) + save_files_main(cli_args) + # Without -D, base output should exist + assert output_files.exists() + # Named output (derived from dist-info) should also exist + named_files = tldr_root / "files-tldr" + named_modules = tldr_root / "modules-tldr" + assert named_files.exists() + assert named_modules.exists() + assert output_files.read_text() == named_files.read_text() diff --git a/tests/double-install.spec b/tests/double-install.spec index 13fe33d..3bef819 100644 --- a/tests/double-install.spec +++ b/tests/double-install.spec @@ -14,7 +14,23 @@ BuildRequires: python3-devel %description This package tests that we can build and install 2 wheels at once. One of them is "noarch" and one has an extension module. -This also tests the -d option for %%pyproject_buildrequires/%%pyproject_wheel. +This also tests the -d option for %%pyproject_buildrequires/%%pyproject_wheel +and the -D option for %%pyproject_save_files/%%pyproject_check_import. + + +%package -n python3-double-markupsafe +Summary: MarkupSafe from double-install test + +%description -n python3-double-markupsafe +MarkupSafe subpackage. + + +%package -n python3-double-tldr +Summary: tldr from double-install test +BuildArch: noarch + +%description -n python3-double-tldr +tldr subpackage. %prep @@ -25,7 +41,7 @@ tar xf %{SOURCE2} %generate_buildrequires %pyproject_buildrequires --no-runtime --directory markupsafe-%{markupsafe_version} -%pyproject_buildrequires --no-runtime --directory tldr-%{tldr_version} +%pyproject_buildrequires --directory tldr-%{tldr_version} %build @@ -39,7 +55,8 @@ set -o pipefail # This should install both the wheels: %pyproject_install ) 2>&1 | tee install.log -#pyproject_save_files is not possible with 2 dist-infos +%pyproject_save_files --dist-name markupsafe markupsafe +%pyproject_save_files -D tldr tldr +auto %check @@ -56,11 +73,11 @@ cd .. # Internal regression check for %%pyproject_install with multiple wheels grep 'binary operator expected' install.log && exit 1 || true grep 'too many arguments' install.log && exit 1 || true +# Check that %%pyproject_check_import -D works +%pyproject_check_import -D markupsafe +%pyproject_check_import -D tldr -%files -%{_bindir}/tldr* -%pycached %{python3_sitelib}/tldr.py -%{python3_sitelib}/tldr-%{tldr_version}.dist-info/ -%{python3_sitearch}/[Mm]arkup[Ss]afe-%{markupsafe_version}.dist-info/ -%{python3_sitearch}/markupsafe/ +%files -n python3-double-markupsafe -f %{pyproject_files -D markupsafe} + +%files -n python3-double-tldr -f %{pyproject_files --dist-name tldr}