Compare commits

...

No commits in common. 'c9' and 'i10c-beta' have entirely different histories.

@ -5,8 +5,10 @@
-- python(abi) = MAJOR.MINOR -- python(abi) = MAJOR.MINOR
-- (Don't match against -config tools e.g. /usr/bin/python2.6-config) -- (Don't match against -config tools e.g. /usr/bin/python2.6-config)
local path = rpm.expand('%1') local path = rpm.expand('%1')
if path:match('/usr/bin/python%d+%.%d+$') then -- Use /usr prefix by default, and /app for flatpak builds
local provides = path:gsub('.*/usr/bin/python(%d+%.%d+)', 'python(abi) = %1') local prefix = rpm.expand('%{?!flatpak:/usr}%{?flatpak:/app}')
if path:match(prefix .. '/bin/python%d+%.%d+$') then
local provides = path:gsub('.*' .. prefix .. '/bin/python(%d+%.%d+)', 'python(abi) = %1')
print(provides) print(provides)
end end
} }
@ -18,10 +20,12 @@
-- generating a line of the form: -- generating a line of the form:
-- python(abi) = MAJOR.MINOR -- python(abi) = MAJOR.MINOR
local path = rpm.expand('%1') local path = rpm.expand('%1')
if path:match('/usr/lib%d*/python%d+%.%d+/.*') then -- Use /usr prefix by default, and /app for flatpak builds
local requires = path:gsub('.*/usr/lib%d*/python(%d+%.%d+)/.*', 'python(abi) = %1') local prefix = rpm.expand('%{?!flatpak:/usr}%{?flatpak:/app}')
if path:match(prefix .. '/lib%d*/python%d+%.%d+/.*') then
local requires = path:gsub('.*' .. prefix .. '/lib%d*/python(%d+%.%d+)/.*', 'python(abi) = %1')
print(requires) print(requires)
end end
} }
%__python_path ^((%{_prefix}/lib(64)?/python[[:digit:]]+\\.[[:digit:]]+/.*\\.(py[oc]?|so))|(%{_bindir}/python[[:digit:]]+\\.[[:digit:]]+))$ %__python_path ^((%{?!flatpak:/usr}%{?flatpak:/app}/lib(64)?/python[[:digit:]]+\\.[[:digit:]]+/.*\\.(py[oc]?|so))|(%{_bindir}/python[[:digit:]]+\\.[[:digit:]]+))$

@ -4,7 +4,7 @@
# This program is free software. # This program is free software.
# #
# It is placed in the public domain or under the CC0-1.0-Universal license, # It is placed in the public domain or under the CC0-1.0-Universal license,
# whichever is more permissive. # whichever you choose.
# #
# Alternatively, it may be redistributed and/or modified under the terms of # Alternatively, it may be redistributed and/or modified under the terms of
# the LGPL version 2.1 (or later) or GPL version 2 (or later). # the LGPL version 2.1 (or later) or GPL version 2 (or later).
@ -15,33 +15,37 @@
import pathlib import pathlib
import sys import sys
# inject parse_version import to pythondistdeps from packaging import requirements
# not the nicest API, but :/
from pkg_resources import parse_version
import pythondistdeps
pythondistdeps.parse_version = parse_version
import pythondistdeps
def generate_bundled_provides(path, namespace): def generate_bundled_provides(paths, namespace):
provides = set() provides = set()
for line in path.read_text().splitlines(): for path in paths:
line, _, comment = line.partition('#') for line in path.read_text().splitlines():
if comment.startswith('egg='): line, _, comment = line.partition('#')
# not a real comment if comment.startswith('egg='):
# e.g. git+https://github.com/monty/spam.git@master#egg=spam&... # not a real comment
egg, *_ = comment.strip().partition(' ') # e.g. git+https://github.com/monty/spam.git@master#egg=spam&...
egg, *_ = egg.strip().partition('&') egg, *_ = comment.strip().partition(' ')
name = pythondistdeps.normalize_name(egg[4:]) egg, *_ = egg.strip().partition('&')
provides.add(f'Provides: bundled({namespace}({name}))') name = pythondistdeps.normalize_name(egg[4:])
continue provides.add(f'Provides: bundled({namespace}({name}))')
line = line.strip() continue
if line: line = line.strip()
name, _, version = line.partition('==') if line:
name = pythondistdeps.normalize_name(name) requirement = requirements.Requirement(line)
bundled_name = f"bundled({namespace}({name}))" for spec in requirement.specifier:
python_provide = pythondistdeps.convert(bundled_name, '==', version) if spec.operator == '==':
provides.add(f'Provides: {python_provide}') version = spec.version
break
else:
raise ValueError('pythonbundles.py only handles exactly one == requirement')
name = pythondistdeps.normalize_name(requirement.name)
bundled_name = f"bundled({namespace}({name}))"
python_provide = pythondistdeps.convert(bundled_name, '==', version)
provides.add(f'Provides: {python_provide}')
return provides return provides
@ -70,7 +74,7 @@ if __name__ == '__main__':
parser = argparse.ArgumentParser(prog=sys.argv[0], parser = argparse.ArgumentParser(prog=sys.argv[0],
formatter_class=argparse.ArgumentDefaultsHelpFormatter) formatter_class=argparse.ArgumentDefaultsHelpFormatter)
parser.add_argument('vendored', metavar='VENDORED.TXT', parser.add_argument('vendored', metavar='VENDORED.TXT', nargs='+', type=pathlib.Path,
help='Upstream information about vendored libraries') help='Upstream information about vendored libraries')
parser.add_argument('-c', '--compare-with', action='store', parser.add_argument('-c', '--compare-with', action='store',
help='A string value to compare with and verify') help='A string value to compare with and verify')
@ -78,7 +82,7 @@ if __name__ == '__main__':
help='What namespace of provides will used', default='python3dist') help='What namespace of provides will used', default='python3dist')
args = parser.parse_args() args = parser.parse_args()
provides = generate_bundled_provides(pathlib.Path(args.vendored), args.namespace) provides = generate_bundled_provides(args.vendored, args.namespace)
if args.compare_with: if args.compare_with:
given = args.compare_with.splitlines() given = args.compare_with.splitlines()

@ -1,3 +1,3 @@
%__pythondist_provides %{_rpmconfigdir}/pythondistdeps.py --provides --normalized-names-format pep503 --package-name %{name} --normalized-names-provide-both --majorver-provides-versions %{__default_python3_version} %__pythondist_provides %{_rpmconfigdir}/pythondistdeps.py --provides --normalized-names-format pep503 --package-name %{name} --majorver-provides-versions %{__default_python3_version} %{?!_python_dist_allow_version_zero:--fail-if-zero}
%__pythondist_requires %{_rpmconfigdir}/pythondistdeps.py --requires --normalized-names-format pep503 --package-name %{name} %{?!_python_no_extras_requires:--require-extras-subpackages} --console-scripts-nodep-setuptools-since 3.10 %__pythondist_requires %{_rpmconfigdir}/pythondistdeps.py --requires --normalized-names-format pep503 --package-name %{name} %{?!_python_no_extras_requires:--require-extras-subpackages} --console-scripts-nodep-setuptools-since 3.10
%__pythondist_path ^/usr/lib(64)?/python[3-9]\\.[[:digit:]]+/site-packages/[^/]+\\.(dist-info|egg-info|egg-link)$ %__pythondist_path ^%{?!flatpak:/usr}%{?flatpak:/app}/lib(64)?/python[3-9]\\.[[:digit:]]+/site-packages/[^/]+\\.(dist-info|egg-info|egg-link)$

@ -73,6 +73,14 @@ class Requirement(Requirement_):
class Distribution(PathDistribution): class Distribution(PathDistribution):
def __init__(self, path): def __init__(self, path):
super(Distribution, self).__init__(Path(path)) super(Distribution, self).__init__(Path(path))
# Check that the initialization went well and metadata are not missing or corrupted
# name is the most important attribute, if it doesn't exist, import failed
if not self.name or not isinstance(self.name, str):
print("*** PYTHON_METADATA_FAILED_TO_PARSE_ERROR___SEE_STDERR ***")
print('Error: Python metadata at `{}` are missing or corrupted.'.format(path), file=stderr)
exit(65) # os.EX_DATAERR
self.normalized_name = normalize_name(self.name) self.normalized_name = normalize_name(self.name)
self.legacy_normalized_name = legacy_normalize_name(self.name) self.legacy_normalized_name = legacy_normalize_name(self.name)
self.requirements = [Requirement(r) for r in self.requires or []] self.requirements = [Requirement(r) for r in self.requires or []]
@ -86,8 +94,8 @@ class Distribution(PathDistribution):
# that it works also on previous Python/importlib_metadata versions. # that it works also on previous Python/importlib_metadata versions.
@property @property
def name(self): def name(self):
"""Return the 'Name' metadata for the distribution package.""" """Return the 'Name' metadata for the distribution package or None."""
return self.metadata['Name'] return self.metadata.get('Name')
def _parse_py_version(self, path): def _parse_py_version(self, path):
# Try to parse the Python version from the path the metadata # Try to parse the Python version from the path the metadata
@ -104,10 +112,17 @@ class Distribution(PathDistribution):
def requirements_for_extra(self, extra): def requirements_for_extra(self, extra):
extra_deps = [] extra_deps = []
# we are only interested in dependencies with extra == 'our_extra' marker
for req in self.requirements: for req in self.requirements:
# no marker at all, nothing to evaluate
if not req.marker: if not req.marker:
continue continue
if req.marker.evaluate(get_marker_env(self, extra)): # does the marker include extra == 'our_extra'?
# we can only evaluate the marker as a whole,
# so we evaluate it twice (using 2 different marker_envs)
# and see if it only evaluates to True with our extra
if (req.marker.evaluate(get_marker_env(self, extra)) and
not req.marker.evaluate(get_marker_env(self, None))):
extra_deps.append(req) extra_deps.append(req)
return extra_deps return extra_deps
@ -126,6 +141,12 @@ class RpmVersion():
self.pre = version._version.pre self.pre = version._version.pre
self.dev = version._version.dev self.dev = version._version.dev
self.post = version._version.post self.post = version._version.post
# version.local is ignored as it is not expected to appear
# in public releases
# https://www.python.org/dev/peps/pep-0440/#local-version-identifiers
def is_legacy(self):
return isinstance(self.version, str)
def increment(self): def increment(self):
self.version[-1] += 1 self.version[-1] += 1
@ -134,8 +155,11 @@ class RpmVersion():
self.post = None self.post = None
return self return self
def is_zero(self):
return self.__str__() == '0'
def __str__(self): def __str__(self):
if isinstance(self.version, str): if self.is_legacy():
return self.version return self.version
if self.epoch: if self.epoch:
rpm_epoch = str(self.epoch) + ':' rpm_epoch = str(self.epoch) + ':'
@ -161,6 +185,11 @@ def convert_compatible(name, operator, version_id):
print('Invalid requirement: {} {} {}'.format(name, operator, version_id), file=stderr) print('Invalid requirement: {} {} {}'.format(name, operator, version_id), file=stderr)
exit(65) # os.EX_DATAERR exit(65) # os.EX_DATAERR
version = RpmVersion(version_id) version = RpmVersion(version_id)
if version.is_legacy():
# LegacyVersions are not supported in this context
print("*** INVALID_REQUIREMENT_ERROR___SEE_STDERR ***")
print('Invalid requirement: {} {} {}'.format(name, operator, version_id), file=stderr)
exit(65) # os.EX_DATAERR
if len(version.version) == 1: if len(version.version) == 1:
print("*** INVALID_REQUIREMENT_ERROR___SEE_STDERR ***") print("*** INVALID_REQUIREMENT_ERROR___SEE_STDERR ***")
print('Invalid requirement: {} {} {}'.format(name, operator, version_id), file=stderr) print('Invalid requirement: {} {} {}'.format(name, operator, version_id), file=stderr)
@ -193,18 +222,32 @@ def convert_not_equal(name, operator, version_id):
if version_id.endswith('.*'): if version_id.endswith('.*'):
version_id = version_id[:-2] version_id = version_id[:-2]
version = RpmVersion(version_id) version = RpmVersion(version_id)
lower_version = RpmVersion(version_id).increment() if version.is_legacy():
# LegacyVersions are not supported in this context
print("*** INVALID_REQUIREMENT_ERROR___SEE_STDERR ***")
print('Invalid requirement: {} {} {}'.format(name, operator, version_id), file=stderr)
exit(65) # os.EX_DATAERR
version_gt = RpmVersion(version_id).increment()
version_gt_operator = '>='
# Prevent dev and pre-releases from satisfying a < requirement
version = '{}~~'.format(version)
else: else:
version = RpmVersion(version_id) version = RpmVersion(version_id)
lower_version = version version_gt = version
return '({} < {} or {} > {})'.format( version_gt_operator = '>'
name, version, name, lower_version) return '({} < {} or {} {} {})'.format(
name, version, name, version_gt_operator, version_gt)
def convert_ordered(name, operator, version_id): def convert_ordered(name, operator, version_id):
if version_id.endswith('.*'): if version_id.endswith('.*'):
# PEP 440 does not define semantics for prefix matching # PEP 440 does not define semantics for prefix matching
# with ordered comparisons # with ordered comparisons
# see: https://github.com/pypa/packaging/issues/320
# and: https://github.com/pypa/packaging/issues/321
# This style of specifier is officially "unsupported",
# even though it is processed. Support may be removed
# in version 21.0.
version_id = version_id[:-2] version_id = version_id[:-2]
version = RpmVersion(version_id) version = RpmVersion(version_id)
if operator == '>': if operator == '>':
@ -215,6 +258,14 @@ def convert_ordered(name, operator, version_id):
operator = '<' operator = '<'
else: else:
version = RpmVersion(version_id) version = RpmVersion(version_id)
# For backwards compatibility, fallback to previous behavior with LegacyVersions
if not version.is_legacy():
# Prevent dev and pre-releases from satisfying a < requirement
if operator == '<' and not version.pre and not version.dev and not version.post:
version = '{}~~'.format(version)
# Prevent post-releases from satisfying a > requirement
if operator == '>' and not version.pre and not version.dev and not version.post:
version = '{}.0'.format(version)
return '{} {} {}'.format(name, operator, version) return '{} {} {}'.format(name, operator, version)
@ -252,10 +303,10 @@ def get_marker_env(dist, extra):
"extra": extra} "extra": extra}
if __name__ == "__main__": def main():
"""To allow this script to be importable (and its classes/functions """To allow this script to be importable (and its classes/functions
reused), actions are performed only when run as a main script.""" reused), actions are defined in the main function and are performed only
when run as a main script."""
parser = argparse.ArgumentParser(prog=argv[0]) parser = argparse.ArgumentParser(prog=argv[0])
group = parser.add_mutually_exclusive_group(required=True) group = parser.add_mutually_exclusive_group(required=True)
group.add_argument('-P', '--provides', action='store_true', help='Print Provides') group.add_argument('-P', '--provides', action='store_true', help='Print Provides')
@ -285,9 +336,14 @@ if __name__ == "__main__":
parser.add_argument('--require-extras-subpackages', action='store_true', 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") 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('--package-name', action='store', help="Name of the RPM package that's being inspected. Required for extras requires/provides to work.")
parser.add_argument('--namespace', action='store', help="Namespace for the printed Requires, Provides, Recommends and Conflicts")
parser.add_argument('--fail-if-zero', action='store_true', help='Fail the script if the automatically generated Provides version was 0, which usually indicates a packaging error.')
parser.add_argument('files', nargs=argparse.REMAINDER, help="Files from the RPM package that are to be inspected, can also be supplied on stdin") 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() args = parser.parse_args()
if args.fail_if_zero and not args.provides:
raise parser.error('--fail-if-zero only works with --provides')
py_abi = args.requires py_abi = args.requires
py_deps = {} py_deps = {}
@ -333,6 +389,8 @@ if __name__ == "__main__":
package_name_parts = args.package_name.rpartition('+') package_name_parts = args.package_name.rpartition('+')
extras_subpackage = package_name_parts[2].lower() or None extras_subpackage = package_name_parts[2].lower() or None
namespace = (args.namespace + "({})") if args.namespace else "{}"
for f in (args.files or stdin.readlines()): for f in (args.files or stdin.readlines()):
f = f.strip() f = f.strip()
lower = f.lower() lower = f.lower()
@ -389,36 +447,47 @@ if __name__ == "__main__":
extras_suffix = f"[{extras_subpackage}]" if extras_subpackage else "" extras_suffix = f"[{extras_subpackage}]" if extras_subpackage else ""
# If egg/dist metadata says package name is python, we provide python(abi) # If egg/dist metadata says package name is python, we provide python(abi)
if dist.normalized_name == 'python': if dist.normalized_name == 'python':
name = 'python(abi)' name = namespace.format('python(abi)')
if name not in py_deps: if name not in py_deps:
py_deps[name] = [] py_deps[name] = []
py_deps[name].append(('==', dist.py_version)) py_deps[name].append(('==', dist.py_version))
if not args.legacy or not args.majorver_only: if not args.legacy or not args.majorver_only:
if normalized_names_provide_legacy: if normalized_names_provide_legacy:
name = 'python{}dist({}{})'.format(dist.py_version, dist.legacy_normalized_name, extras_suffix) name = namespace.format('python{}dist({}{})').format(dist.py_version, dist.legacy_normalized_name, extras_suffix)
if name not in py_deps: if name not in py_deps:
py_deps[name] = [] py_deps[name] = []
if normalized_names_provide_pep503: if normalized_names_provide_pep503:
name_ = 'python{}dist({}{})'.format(dist.py_version, dist.normalized_name, extras_suffix) name_ = namespace.format('python{}dist({}{})').format(dist.py_version, dist.normalized_name, extras_suffix)
if name_ not in py_deps: if name_ not in py_deps:
py_deps[name_] = [] py_deps[name_] = []
if args.majorver_provides or args.majorver_only or \ if args.majorver_provides or args.majorver_only or \
(args.majorver_provides_versions and dist.py_version in args.majorver_provides_versions): (args.majorver_provides_versions and dist.py_version in args.majorver_provides_versions):
if normalized_names_provide_legacy: if normalized_names_provide_legacy:
pymajor_name = 'python{}dist({}{})'.format(pyver_major, dist.legacy_normalized_name, extras_suffix) pymajor_name = namespace.format('python{}dist({}{})').format(pyver_major, dist.legacy_normalized_name, extras_suffix)
if pymajor_name not in py_deps: if pymajor_name not in py_deps:
py_deps[pymajor_name] = [] py_deps[pymajor_name] = []
if normalized_names_provide_pep503: if normalized_names_provide_pep503:
pymajor_name_ = 'python{}dist({}{})'.format(pyver_major, dist.normalized_name, extras_suffix) pymajor_name_ = namespace.format('python{}dist({}{})').format(pyver_major, dist.normalized_name, extras_suffix)
if pymajor_name_ not in py_deps: if pymajor_name_ not in py_deps:
py_deps[pymajor_name_] = [] py_deps[pymajor_name_] = []
if args.legacy or args.legacy_provides: if args.legacy or args.legacy_provides:
legacy_name = 'pythonegg({})({})'.format(pyver_major, dist.legacy_normalized_name) legacy_name = namespace.format('pythonegg({})({})').format(pyver_major, dist.legacy_normalized_name)
if legacy_name not in py_deps: if legacy_name not in py_deps:
py_deps[legacy_name] = [] py_deps[legacy_name] = []
if dist.version: if dist.version:
version = dist.version version = dist.version
spec = ('==', version) spec = ('==', version)
if args.fail_if_zero:
if RpmVersion(version).is_zero():
print('*** PYTHON_PROVIDED_VERSION_NORMALIZES_TO_ZERO___SEE_STDERR ***')
print(f'\nError: The version in the Python package metadata {version} normalizes to zero.\n'
'It\'s likely a packaging error caused by missing version information\n'
'(e.g. when using a version control system snapshot as a source).\n'
'Try providing the version information manually when building the Python package,\n'
'for example by setting the SETUPTOOLS_SCM_PRETEND_VERSION environment variable if the package uses setuptools_scm.\n'
'If you are confident that the version of the Python package is intentionally zero,\n'
'you may %define the _python_dist_allow_version_zero macro in the spec file to disable this check.\n', file=stderr)
exit(65) # os.EX_DATAERR
if normalized_names_provide_legacy: if normalized_names_provide_legacy:
if spec not in py_deps[name]: if spec not in py_deps[name]:
@ -436,7 +505,7 @@ if __name__ == "__main__":
if spec not in py_deps[legacy_name]: if spec not in py_deps[legacy_name]:
py_deps[legacy_name].append(spec) py_deps[legacy_name].append(spec)
if args.requires or (args.recommends and dist.extras): if args.requires or (args.recommends and dist.extras):
name = 'python(abi)' name = namespace.format('python(abi)')
# If egg/dist metadata says package name is python, we don't add dependency on python(abi) # If egg/dist metadata says package name is python, we don't add dependency on python(abi)
if dist.normalized_name == 'python': if dist.normalized_name == 'python':
py_abi = False py_abi = False
@ -483,12 +552,12 @@ if __name__ == "__main__":
dep_normalized_name = dep.legacy_normalized_name dep_normalized_name = dep.legacy_normalized_name
if args.legacy: if args.legacy:
name = 'pythonegg({})({})'.format(pyver_major, dep.legacy_normalized_name) name = namespace.format('pythonegg({})({})').format(pyver_major, dep.legacy_normalized_name)
else: else:
if args.majorver_only: if args.majorver_only:
name = 'python{}dist({}{})'.format(pyver_major, dep_normalized_name, extras_suffix) name = namespace.format('python{}dist({}{})').format(pyver_major, dep_normalized_name, extras_suffix)
else: else:
name = 'python{}dist({}{})'.format(dist.py_version, dep_normalized_name, extras_suffix) name = namespace.format('python{}dist({}{})').format(dist.py_version, dep_normalized_name, extras_suffix)
if dep.marker and not args.recommends and not extras_subpackage: if dep.marker and not args.recommends and not extras_subpackage:
if not dep.marker.evaluate(get_marker_env(dist, '')): if not dep.marker.evaluate(get_marker_env(dist, '')):
@ -544,3 +613,14 @@ if __name__ == "__main__":
else: else:
# Print out unversioned provides, requires, recommends, conflicts # Print out unversioned provides, requires, recommends, conflicts
print(name) print(name)
if __name__ == "__main__":
"""To allow this script to be importable (and its classes/functions
reused), actions are performed only when run as a main script."""
try:
main()
except Exception as exc:
print("*** PYTHONDISTDEPS_GENERATORS_FAILED ***", flush=True)
raise RuntimeError("Error: pythondistdeps.py generator encountered an unhandled exception and was terminated.") from exc

@ -1,9 +1,6 @@
%__pythonname_provides() %{lua: %__pythonname_provides() %{lua:
local python = require 'fedora.srpm.python' local python = require 'fedora.srpm.python'
-- this macro is called for each file in a package, the path being in %1 local name = rpm.expand('%{name}')
-- but we don't need to know the path, so we would get for each file: Macro %1 defined but not used within scope
-- in here, we expand %name conditionally on %1 to suppress the warning
local name = rpm.expand('%{?1:%{name}}')
local evr = rpm.expand('%{?epoch:%{epoch}:}%{version}-%{release}') local evr = rpm.expand('%{?epoch:%{epoch}:}%{version}-%{release}')
local provides = python.python_altprovides_once(name, evr) local provides = python.python_altprovides_once(name, evr)
-- provides is either an array/table or nil -- provides is either an array/table or nil
@ -23,10 +20,7 @@
-- In Fedora this is not needed as we don't ship ecosystem packages -- In Fedora this is not needed as we don't ship ecosystem packages
-- for alternative Python interpreters. -- for alternative Python interpreters.
local python = require 'fedora.srpm.python' local python = require 'fedora.srpm.python'
-- this macro is called for each file in a package, the path being in %1 local name = rpm.expand('%{name}')
-- but we don't need to know the path, so we would get for each file: Macro %1 defined but not used within scope
-- in here, we expand %name conditionally on %1 to suppress the warning
local name = rpm.expand('%{?1:%{name}}')
local evr = rpm.expand('%{?epoch:%{epoch}:}%{version}-%{release}') local evr = rpm.expand('%{?epoch:%{epoch}:}%{version}-%{release}')
local obsoletes = python.python_altobsoletes_once(name, evr) local obsoletes = python.python_altobsoletes_once(name, evr)
-- obsoletes is either an array/table or nil -- obsoletes is either an array/table or nil

@ -1,19 +1,28 @@
Name: python-rpm-generators Name: python-rpm-generators
Summary: Dependency generators for Python RPMs Summary: Dependency generators for Python RPMs
Version: 12 Version: 14
Release: 8%{?dist} Release: 11%{?dist}
# Originally all those files were part of RPM, so license is kept here Url: https://src.fedoraproject.org/rpms/python-rpm-generators
License: GPLv2+
Url: https://src.fedoraproject.org/python-rpm-generators # Originally the following files were part of RPM, so the license is inherited: GPL-2.0-or-later
# Commit is the last change in following files # The COPYING file is grabbed from the last commit that changed the files
Source0: https://raw.githubusercontent.com/rpm-software-management/rpm/102eab50b3d0d6546dfe082eac0ade21e6b3dbf1/COPYING Source0: https://raw.githubusercontent.com/rpm-software-management/rpm/102eab50b3d0d6546dfe082eac0ade21e6b3dbf1/COPYING
Source1: python.attr Source1: python.attr
Source2: pythondist.attr Source2: pythondist.attr
# This was crafted in-place as a fork of python.attr, hence also GPL-2.0-or-later
Source3: pythonname.attr Source3: pythonname.attr
# This one is also originally from RPM, but it has its own license declaration: LGPL-2.1-or-later
Source4: pythondistdeps.py Source4: pythondistdeps.py
# This was crafted in-place with the following license declaration:
# LicenseRef-Fedora-Public-Domain OR CC0-1.0 OR LGPL-2.1-or-later OR GPL-2.0-or-later
# Note that CC0-1.0 is not allowed for code in Fedora, so we skip it in the package License tag
Source5: pythonbundles.py Source5: pythonbundles.py
# See individual licenses above Source declarations
# Originally, this was simplified to GPL-2.0-or-later, but "effective license" analysis is no longer allowed
License: GPL-2.0-or-later AND LGPL-2.1-or-later AND (LicenseRef-Fedora-Public-Domain OR LGPL-2.1-or-later OR GPL-2.0-or-later)
BuildArch: noarch BuildArch: noarch
%description %description
@ -25,7 +34,7 @@ Requires: python3-packaging
# We have parametric macro generators, we need RPM 4.16 (4.15.90+ is 4.16 alpha) # We have parametric macro generators, we need RPM 4.16 (4.15.90+ is 4.16 alpha)
Requires: rpm > 4.15.90-0 Requires: rpm > 4.15.90-0
# This contains the Lua functions we use: # This contains the Lua functions we use:
Requires: python-srpm-macros >= 3.9-49 Requires: python-srpm-macros >= 3.10-15
%description -n python3-rpm-generators %description -n python3-rpm-generators
%{summary}. %{summary}.
@ -47,27 +56,89 @@ install -Dpm0755 -t %{buildroot}%{_rpmconfigdir} *.py
%{_rpmconfigdir}/pythonbundles.py %{_rpmconfigdir}/pythonbundles.py
%changelog %changelog
* Wed Jan 26 2022 Tomas Orsava <torsava@redhat.com> - 12-8 * Tue Nov 26 2024 MSVSphere Packaging Team <packager@msvsphere-os.ru> - 14-11
- Rebuilt for MSVSphere 10
* Mon Jun 24 2024 Troy Dawson <tdawson@redhat.com> - 14-11
- Bump release for June 2024 mass rebuild
* Fri Jan 26 2024 Fedora Release Engineering <releng@fedoraproject.org> - 14-10
- Rebuilt for https://fedoraproject.org/wiki/Fedora_40_Mass_Rebuild
* Mon Jan 22 2024 Fedora Release Engineering <releng@fedoraproject.org> - 14-9
- Rebuilt for https://fedoraproject.org/wiki/Fedora_40_Mass_Rebuild
* Tue Oct 03 2023 Miro Hrončok <mhroncok@redhat.com> - 14-8
- Avoid DeprecationWarning: Implicit None on return values is deprecated and will raise KeyErrors
* Fri Jul 21 2023 Fedora Release Engineering <releng@fedoraproject.org> - 14-7
- Rebuilt for https://fedoraproject.org/wiki/Fedora_39_Mass_Rebuild
* Wed May 24 2023 Todd Zullinger <tmz@pobox.com> - 14-6
- Fix URL tag
* Fri May 05 2023 Miro Hrončok <mhroncok@redhat.com> - 14-5
- Declare the license via a complex SPDX expression rather than "effective license"
* Mon Apr 17 2023 Kalev Lember <klember@redhat.com> - 14-4
- Generate provides for /app-installed flatpak builds
* Tue Mar 07 2023 Miro Hrončok <mhroncok@redhat.com> - 14-3
- Avoid needless pkg_resources import in pythonbundles.py
- Ignore environment markers in pythonbundles.py
* Fri Jan 20 2023 Fedora Release Engineering <releng@fedoraproject.org> - 14-2
- Rebuilt for https://fedoraproject.org/wiki/Fedora_38_Mass_Rebuild
* Thu Dec 22 2022 Karolina Surma <ksurma@redhat.com> - 14-1
- https://fedoraproject.org/wiki/Changes/Prevent-Providing-python3dist(pkg)=0
* Fri Jul 22 2022 Fedora Release Engineering <releng@fedoraproject.org> - 13-2
- Rebuilt for https://fedoraproject.org/wiki/Fedora_37_Mass_Rebuild
* Thu Jun 02 2022 Miro Hrončok <mhroncok@redhat.com> - 13-1
- https://fedoraproject.org/wiki/Changes/PythonDistPEP503ProvidesOnly
* Fri May 27 2022 Miro Hrončok <mhroncok@redhat.com> - 12-15
- Don't include all requirements with True-evaluating markers in extras subpackages
- Fixes: rhbz#2090186
* Thu Feb 10 2022 Sandro Mani <manisandro@gmail.com> - 12-14
- Add namespace option to pythodistdeps.py to allow mingw-python generatros
* Wed Jan 26 2022 Tomas Orsava <torsava@redhat.com> - 12-13
- From `python3-foo` packages automatically generate `python3.X-foo` Obsoletes - From `python3-foo` packages automatically generate `python3.X-foo` Obsoletes
tags on CentOS/RHEL tags on CentOS/RHEL
- Resolves: rhbz#1990421
* Tue Aug 10 2021 Mohan Boddu <mboddu@redhat.com> - 12-7 * Fri Jan 21 2022 Fedora Release Engineering <releng@fedoraproject.org> - 12-12
- Rebuilt for IMA sigs, glibc 2.34, aarch64 flags - Rebuilt for https://fedoraproject.org/wiki/Fedora_36_Mass_Rebuild
Related: rhbz#1991688
* Sun Dec 19 2021 Gordon Messmer <gordon.messmer@gmail.com> - 12-11
- Handle legacy version specifiers that would previously raise exceptions.
* Fri Oct 29 2021 Gordon Messmer <gordon.messmer@gmail.com> - 12-10
- Additional fix for dev releases.
* Thu Oct 28 2021 Gordon Messmer <gordon.messmer@gmail.com> - 12-9
- Sync dependency conversion with upstream pyreq2rpm.
- Improve handling of > and < operators, and != operator with prefix matching
* Fri Jul 23 2021 Fedora Release Engineering <releng@fedoraproject.org> - 12-8
- Rebuilt for https://fedoraproject.org/wiki/Fedora_35_Mass_Rebuild
* Tue May 25 2021 Tomas Orsava <torsava@redhat.com> - 12-7
- pythondistdeps.py: Detect missing or corrupted metadata
- pythondistdeps.py: Catch all exceptions and terminate the build if one is raised
* Mon Apr 19 2021 Miro Hrončok <mhroncok@redhat.com> - 12-6 * Mon Apr 19 2021 Miro Hrončok <mhroncok@redhat.com> - 12-6
- Get rid of distutils deprecation warning (by not using it) - Get rid of distutils deprecation warning (by not using it)
- The distutils module is deprecated in Python 3.10+ - The distutils module is deprecated in Python 3.10+
- https://www.python.org/dev/peps/pep-0632/ - https://www.python.org/dev/peps/pep-0632/
* Fri Apr 16 2021 Miro Hrončok <mhroncok@redhat.com> - 12-5.1 * Wed Mar 31 2021 Miro Hrončok <mhroncok@redhat.com> - 12-5
- Do not generate setuptools requirement for console_scripts on Python 3.10+ - Do not generate setuptools requirement for console_scripts on Python 3.10+
- See https://fedoraproject.org/wiki/Changes/Reduce_dependencies_on_python3-setuptools - See https://fedoraproject.org/wiki/Changes/Reduce_dependencies_on_python3-setuptools
* Fri Apr 16 2021 Mohan Boddu <mboddu@redhat.com> - 12-5
- Rebuilt for RHEL 9 BETA on Apr 15th 2021. Related: rhbz#1947937
* Thu Mar 11 2021 Tomas Orsava <torsava@redhat.com> - 12-4 * Thu Mar 11 2021 Tomas Orsava <torsava@redhat.com> - 12-4
- scripts/pythondistdeps: Treat extras names case-insensitively and always - scripts/pythondistdeps: Treat extras names case-insensitively and always
output them in lower case (#1936875) output them in lower case (#1936875)

Loading…
Cancel
Save