scripts/pythondistdeps: Implement provides/requires for extras packages

This commit is contained in:
Tomas Orsava 2020-06-02 21:12:11 +02:00
parent 3b1100ba1f
commit 0c9665427c
2 changed files with 52 additions and 25 deletions

View File

@ -1,3 +1,3 @@
%__pythondist_provides %{_rpmconfigdir}/pythondistdeps.py --provides --normalized-names-format pep503 --normalized-names-provide-both --majorver-provides-versions 2.7,%{__default_python3_version}
%__pythondist_requires %{_rpmconfigdir}/pythondistdeps.py --requires --normalized-names-format pep503
%__pythondist_provides %{_rpmconfigdir}/pythondistdeps.py --provides --normalized-names-format pep503 --package-name %{name} --normalized-names-provide-both --majorver-provides-versions 2.7,%{__default_python3_version}
%__pythondist_requires %{_rpmconfigdir}/pythondistdeps.py --requires --normalized-names-format pep503 --package-name %{name}
%__pythondist_path ^/usr/lib(64)?/python[[:digit:]]\\.[[:digit:]]+/site-packages/[^/]+\\.(dist-info|egg-info|egg-link)$

View File

@ -157,7 +157,7 @@ if __name__ == "__main__":
group.add_argument('-R', '--requires', action='store_true', help='Print Requires')
group.add_argument('-r', '--recommends', action='store_true', help='Print Recommends')
group.add_argument('-C', '--conflicts', action='store_true', help='Print Conflicts')
group.add_argument('-E', '--extras', action='store_true', help='Print Extras')
group.add_argument('-E', '--extras', action='store_true', help='[Unused] Generate spec file snippets for extras subpackages')
group_majorver = parser.add_mutually_exclusive_group()
group_majorver.add_argument('-M', '--majorver-provides', action='store_true', help='Print extra Provides with Python major version only')
group_majorver.add_argument('--majorver-provides-versions', action='append',
@ -171,7 +171,9 @@ if __name__ == "__main__":
help='Provide both `pep503` and `legacy-dots` format of normalized names (useful for a transition period)')
parser.add_argument('-L', '--legacy-provides', action='store_true', help='Print extra legacy pythonegg Provides')
parser.add_argument('-l', '--legacy', action='store_true', help='Print legacy pythonegg Provides/Requires instead')
parser.add_argument('--package-name', action='store', help="Name of the RPM package that's being inspected")
parser.add_argument('--require-extras-subpackages', action='store_true',
help="If there is a dependency on a package with extras functionality, require the extras subpackage")
parser.add_argument('--package-name', action='store', help="Name of the RPM package that's being inspected. Required for extras requires/provides to work.")
parser.add_argument('files', nargs=argparse.REMAINDER, help="Files from the RPM package that are to be inspected, can also be supplied on stdin")
args = parser.parse_args()
@ -198,6 +200,12 @@ if __name__ == "__main__":
# At least one type of normalization must be provided
assert normalized_names_provide_pep503 or normalized_names_provide_legacy
# Is this script being run for an extras subpackage?
extras_subpackage = None
if args.package_name:
package_name_parts = args.package_name.partition('+')
extras_subpackage = package_name_parts[2] or None
for f in (args.files or stdin.readlines()):
f = f.strip()
lower = f.lower()
@ -268,11 +276,18 @@ if __name__ == "__main__":
# See https://bugzilla.redhat.com/show_bug.cgi?id=1791530
normalized_name = normalize_name(dist.project_name)
# If we're processing an extras subpackage, check that the extras exists
if extras_subpackage and extras_subpackage not in dist.extras:
print(f"\nError: The package name contains an extras name `{extras_subpackage}` that was not found in the metadata.\n"
"Check if the extras were removed from the project. If so, consider removing the subpackage and obsoleting it from another.")
exit(65) # os.EX_DATAERR
if args.majorver_provides or args.majorver_provides_versions or \
args.majorver_only or args.legacy_provides or args.legacy:
# Get the Python major version
pyver_major = dist.py_version.split('.')[0]
if args.provides:
extras_suffix = f"[{extras_subpackage}]" if extras_subpackage else ""
# If egg/dist metadata says package name is python, we provide python(abi)
if dist.key == 'python':
name = 'python(abi)'
@ -281,21 +296,21 @@ if __name__ == "__main__":
py_deps[name].append(('==', dist.py_version))
if not args.legacy or not args.majorver_only:
if normalized_names_provide_legacy:
name = 'python{}dist({})'.format(dist.py_version, dist.key)
name = 'python{}dist({}{})'.format(dist.py_version, dist.key, extras_suffix)
if name not in py_deps:
py_deps[name] = []
if normalized_names_provide_pep503:
name_ = 'python{}dist({})'.format(dist.py_version, normalized_name)
name_ = 'python{}dist({}{})'.format(dist.py_version, normalized_name, extras_suffix)
if name_ not in py_deps:
py_deps[name_] = []
if args.majorver_provides or args.majorver_only or \
(args.majorver_provides_versions and dist.py_version in args.majorver_provides_versions):
if normalized_names_provide_legacy:
pymajor_name = 'python{}dist({})'.format(pyver_major, dist.key)
pymajor_name = 'python{}dist({}{})'.format(pyver_major, dist.key, extras_suffix)
if pymajor_name not in py_deps:
py_deps[pymajor_name] = []
if normalized_names_provide_pep503:
pymajor_name_ = 'python{}dist({})'.format(pyver_major, normalized_name)
pymajor_name_ = 'python{}dist({}{})'.format(pyver_major, normalized_name, extras_suffix)
if pymajor_name_ not in py_deps:
py_deps[pymajor_name_] = []
if args.legacy or args.legacy_provides:
@ -342,6 +357,9 @@ if __name__ == "__main__":
if dep in deps:
depsextras.remove(dep)
deps = depsextras
elif extras_subpackage:
# Extras requires also contain the base requires included
deps = [d for d in dist.requires(extras=[extras_subpackage]) if d not in dist.requires()]
# console_scripts/gui_scripts entry points need pkg_resources from setuptools
if ((dist.get_entry_map('console_scripts') or
dist.get_entry_map('gui_scripts')) and
@ -351,25 +369,34 @@ if __name__ == "__main__":
deps.insert(0, Requirement.parse('setuptools'))
# add requires/recommends based on egg/dist metadata
for dep in deps:
if normalized_names_require_pep503:
dep_normalized_name = normalize_name(dep.project_name)
else:
dep_normalized_name = dep.key
if args.legacy:
name = 'pythonegg({})({})'.format(pyver_major, dep.key)
else:
if args.majorver_only:
name = 'python{}dist({})'.format(pyver_major, dep_normalized_name)
# Even if we're requiring `foo[bar]`, also require `foo`
# to be safe, and to make it discoverable through
# `repoquery --whatrequires`
extras_suffixes = [""]
if args.require_extras_subpackages and dep.extras:
# A dependency can have more than one extras,
# i.e. foo[bar,baz], so let's go through all of them
extras_suffixes += [f"[{e}]" for e in dep.extras]
for extras_suffix in extras_suffixes:
if normalized_names_require_pep503:
dep_normalized_name = normalize_name(dep.project_name)
else:
name = 'python{}dist({})'.format(dist.py_version, dep_normalized_name)
for spec in dep.specs:
if name not in py_deps:
dep_normalized_name = dep.key
if args.legacy:
name = 'pythonegg({})({})'.format(pyver_major, dep.key)
else:
if args.majorver_only:
name = 'python{}dist({}{})'.format(pyver_major, dep_normalized_name, extras_suffix)
else:
name = 'python{}dist({}{})'.format(dist.py_version, dep_normalized_name, extras_suffix)
for spec in dep.specs:
if name not in py_deps:
py_deps[name] = []
if spec not in py_deps[name]:
py_deps[name].append(spec)
if not dep.specs:
py_deps[name] = []
if spec not in py_deps[name]:
py_deps[name].append(spec)
if not dep.specs:
py_deps[name] = []
# Unused, for automatic sub-package generation based on 'extras' from egg/dist metadata
# TODO: implement in rpm later, or...?
if args.extras: