From c71a0b35380f07191d157d895fcd1d0fb89f7d13 Mon Sep 17 00:00:00 2001 From: Olav Vitters Date: Wed, 6 May 2020 16:58:29 +0200 Subject: SpecFile: introduce the convert_buildrequires function (logic moved from cmd_clean_spec_multi) --- mgagnome | 359 ++++++++++++++++++++++++++++++++++----------------------------- 1 file changed, 193 insertions(+), 166 deletions(-) diff --git a/mgagnome b/mgagnome index 276573a..00f2a16 100755 --- a/mgagnome +++ b/mgagnome @@ -51,6 +51,7 @@ import collections # for debugging output import pprint +import logging # check-latest import requests @@ -443,6 +444,174 @@ class SpecFile(): """Return the sources""" return self._sources_and_patches(flag=1) + def convert_buildrequires(self): + """Converts BuildRequires into their preferred form + + Requires SpecFile to be initialized with its package argument""" + + made_changes = False + re_prov_get_version = re.compile(r'^[^(]+\([^)]+-(?P[0-9]+\.[0-9][0-9.]*)\)$') + no_alt = set() + no_change = {} + + buildreqs = self.buildrequires + + log = logging.getLogger(None) + debug_enabled = log.isEnabledFor(log.DEBUG) + + convert_brs = { + 'pkgconfig': { + 'desc': 'convert -devel buildrequires into pkgconfig', + 'check_br': lambda req: req.endswith('-devel'), + 'check_provide': lambda prov: prov.startswith('pkgconfig('), + 'basereqs': lambda req: [req[:-len('-devel')]], + 'basereq_no_version': lambda basereqs: [basereq.rstrip('1234567890.') for basereq in basereqs + if basereq[-1] in '1234567890'], + 'versions_from_basereq': lambda basereqs: set((basereq[len(basereq.rstrip('01234567890.')):] + for basereq in basereqs if basereq[-1] in '1234567890')), + 'versions_basereq_extra': lambda versions: set(("%s.0" % version for version in versions + if '.' not in version)), + 'extra': lambda basereqs, versions: \ + ['pkgconfig(%s)' % basereq for basereq in basereqs] + + ['pkgconfig(%s)' % basereq[len('lib'):] + if basereq.startswith('lib') else 'pkgconfig(lib%s)' % basereq + for basereq in basereqs] + + ['pkgconfig(%s-%s)' % (basereq, version) for basereq in basereqs for version in versions], + }, + 'perl': { + 'desc': 'convert perl- buildrequires into perl()', + 'check_br': lambda req: req.startswith('perl-'), + 'check_provide': lambda prov: prov.startswith('perl('), + 'basereqs': lambda req: [req[len('perl-'):]], + 'extra': lambda basereqs, versions: ['perl(%s)' % basereq.replace('-', '::') for basereq in basereqs], + }, + # PySolFC.spec:BuildRequires: python3-setuptools + # $ rpm -q python3-setuptools --provides | grep python3dist + # python3dist(setuptools) + # python3dist(setuptools) = 46.1.3 + # + # There's also provides such as: + # python3.8dist(setuptools) + # pythonegg(3)(setuptools) + 'python-pkg': { + 'disabled': True, + 'desc': 'convert python buildrequires into python3dist()', + 'check_br': lambda req: req.startswith('python3-'), + 'check_provide': lambda prov: prov.startswith('python3dist('), + 'basereqs': lambda req: [req[len('python3-'):]], + 'extra': lambda basereqs, versions: ['python3dist(%s)' % basereq for basereq in basereqs], + }, + 'python-egg': { + 'desc': 'convert pythonegg(3) into python3dist()', + 'check_br': lambda req: req.startswith('pythonegg(3)(') and req.endswith(')'), + 'check_provide': lambda prov: prov.startswith('python3dist('), + 'basereqs': lambda req: [req[len('pythonegg(3)('):-1]], + 'extra': lambda basereqs, versions: ['python3dist(%s)' % basereq for basereq in basereqs], + }, + } + + for keys in convert_brs.values(): + if 'disabled' in keys and keys['disabled']: + continue + + keys['changes'] = {} + br_old = [r for r in list(buildreqs.keys()) if keys['check_br'](r)] + if debug_enabled and br_old: + pprint.pprint(br_old) + for req in br_old: + every_provides, every_ignored_provide = Downstream.alternative_provides(req) + # XXX - document what clean_pkgconfig_prov is for + # maybe integrate clean_pkgconfig_prov in alternative_provides function? + provides = [clean_pkgconfig_prov(prov) + for prov in every_provides + if keys['check_provide'](prov)] + provides_ignored = [clean_pkgconfig_prov(prov) + for prov in every_ignored_provide + if keys['check_provide'](prov)] + change_to = None + if len(provides) == 1 and not provides_ignored: + if debug_enabled: + print("NOTICE: Only one available option, using %s" % provides[0]) + + change_to = provides[0] + elif provides and 'extra' in keys: + # Determine base require (e.g. gtk+3.0-devel --> gtk+3.0) + basereqs = keys['basereqs'](req) + + # Determine version matches + versions = set() + if 'versions_from_basereq' in keys: + # Determine if the basereq has a version at the end (e.g. gtk+3.0 --> 3.0) + versions.update(keys['versions_from_basereq'](basereqs)) + if versions and 'basereq_no_version' in keys: + basereqs.extend(keys['basereq_no_version'](basereqs)) + # Make it unique again, but keep the order + # + # This is done so that e.g. python3-devel changes to pkgconfig(python3), + # even if pkgconfig(python) might be available + basereqs = list(distinct(basereqs)) + if 'versions_basereq_extra' in keys: + versions.update(keys['versions_basereq_extra'](versions)) + + if not versions: + # In case no versions were retrieved from the basereq, + # match with any version found from the alternative + # provides (heuristic matching) + # + # This is only done as a last resort to avoid matching + # e.g. gtk+3.0-devel --> pkgconfig(gtk+2.0) + for prov in provides: + for match in re_prov_get_version.finditer(prov): + if debug_enabled: + print("NOTICE: Heuristically adding version %s from provide %s" \ + % (match.group('version'), prov)) + versions.add(match.group('version')) + + check_for = keys['extra'](basereqs, versions) + + if debug_enabled and versions: + pprint.pprint(versions) + + for check in check_for: + if check in provides: + if debug_enabled: + print("NOTICE: Matched: %s => %s" % (check, provides)) + change_to = check + break + + if change_to is None and provides: + provides_no_versions = [] + for prov in provides: + if re_prov_get_version.fullmatch(prov) is None: + provides_no_versions.append(prov) + + if len(provides_no_versions) == 1 and not provides_ignored: + change_to = provides_no_versions[0] + if debug_enabled: + print("NOTICE: Only one available versionless option, using %s" % change_to) + + + if provides: + if change_to is None: + no_change[req] = (provides, check_for) + else: + no_alt.add(req) + + if change_to is not None: + keys['changes'][req] = change_to + + keys_with_changes = [keys for keys in convert_brs.values() if 'changes' in keys and keys['changes']] +# XXX - seems to cause false messages +# if not keys_with_changes: +# keys_with_changes.append({'changes': [], 'desc': 'unsplit BRs'}) + + for keys in keys_with_changes: + if self.update_br(keys['changes'], change_description=keys['desc']): + made_changes = True + + return made_changes + + def clean_spec(self): """Clean the spec file of deprecated statements""" @@ -1806,174 +1975,23 @@ def _cmd_clean_spec_multi(args): # Convert perl- and -devel buildrequires into perl() and pkgconfig() requires if options.convert_br: - re_prov_get_version = re.compile(r'^[^(]+\([^)]+-(?P[0-9]+\.[0-9][0-9.]*)\)$') - buildreqs = spec.buildrequires - no_alt = set() - no_change = {} - convert_brs = { - 'pkgconfig': { - 'desc': 'convert -devel buildrequires into pkgconfig', - 'check_br': lambda req: req.endswith('-devel'), - 'check_provide': lambda prov: prov.startswith('pkgconfig('), - 'basereqs': lambda req: [req[:-len('-devel')]], - 'basereq_no_version': lambda basereqs: [basereq.rstrip('1234567890.') for basereq in basereqs - if basereq[-1] in '1234567890'], - 'versions_from_basereq': lambda basereqs: set((basereq[len(basereq.rstrip('01234567890.')):] - for basereq in basereqs if basereq[-1] in '1234567890')), - 'versions_basereq_extra': lambda versions: set(("%s.0" % version for version in versions - if '.' not in version)), - 'extra': lambda basereqs, versions: \ - ['pkgconfig(%s)' % basereq for basereq in basereqs] + - ['pkgconfig(%s)' % basereq[len('lib'):] - if basereq.startswith('lib') else 'pkgconfig(lib%s)' % basereq - for basereq in basereqs] + - ['pkgconfig(%s-%s)' % (basereq, version) for basereq in basereqs for version in versions], - }, - 'perl': { - 'desc': 'convert perl- buildrequires into perl()', - 'check_br': lambda req: req.startswith('perl-'), - 'check_provide': lambda prov: prov.startswith('perl('), - 'basereqs': lambda req: [req[len('perl-'):]], - 'extra': lambda basereqs, versions: ['perl(%s)' % basereq.replace('-', '::') for basereq in basereqs], - }, - # PySolFC.spec:BuildRequires: python3-setuptools - # $ rpm -q python3-setuptools --provides | grep python3dist - # python3dist(setuptools) - # python3dist(setuptools) = 46.1.3 - # - # There's also provides such as: - # python3.8dist(setuptools) - # pythonegg(3)(setuptools) - 'python-pkg': { - 'disabled': True, - 'desc': 'convert python buildrequires into python3dist()', - 'check_br': lambda req: req.startswith('python3-'), - 'check_provide': lambda prov: prov.startswith('python3dist('), - 'basereqs': lambda req: [req[len('python3-'):]], - 'extra': lambda basereqs, versions: ['python3dist(%s)' % basereq for basereq in basereqs], - }, - 'python-egg': { - 'desc': 'convert pythonegg(3) into python3dist()', - 'check_br': lambda req: req.startswith('pythonegg(3)(') and req.endswith(')'), - 'check_provide': lambda prov: prov.startswith('python3dist('), - 'basereqs': lambda req: [req[len('pythonegg(3)('):-1]], - 'extra': lambda basereqs, versions: ['python3dist(%s)' % basereq for basereq in basereqs], - }, - } - - for keys in convert_brs.values(): - if 'disabled' in keys and keys['disabled']: - continue - - keys['changes'] = {} - br_old = [r for r in list(buildreqs.keys()) if keys['check_br'](r)] - if options.debug and br_old: - pprint.pprint(br_old) - for req in br_old: - every_provides, every_ignored_provide = Downstream.alternative_provides(req) - # XXX - document what clean_pkgconfig_prov is for - # maybe integrate clean_pkgconfig_prov in alternative_provides function? - provides = [clean_pkgconfig_prov(prov) - for prov in every_provides - if keys['check_provide'](prov)] - provides_ignored = [clean_pkgconfig_prov(prov) - for prov in every_ignored_provide - if keys['check_provide'](prov)] - change_to = None - if len(provides) == 1 and not provides_ignored: - if options.debug: - print("NOTICE: Only one available option, using %s" % provides[0]) - - change_to = provides[0] - elif provides and 'extra' in keys: - # Determine base require (e.g. gtk+3.0-devel --> gtk+3.0) - basereqs = keys['basereqs'](req) - - # Determine version matches - versions = set() - if 'versions_from_basereq' in keys: - # Determine if the basereq has a version at the end (e.g. gtk+3.0 --> 3.0) - versions.update(keys['versions_from_basereq'](basereqs)) - if versions and 'basereq_no_version' in keys: - basereqs.extend(keys['basereq_no_version'](basereqs)) - # Make it unique again, but keep the order - # - # This is done so that e.g. python3-devel changes to pkgconfig(python3), - # even if pkgconfig(python) might be available - basereqs = list(distinct(basereqs)) - if 'versions_basereq_extra' in keys: - versions.update(keys['versions_basereq_extra'](versions)) - - if not versions: - # In case no versions were retrieved from the basereq, - # match with any version found from the alternative - # provides (heuristic matching) - # - # This is only done as a last resort to avoid matching - # e.g. gtk+3.0-devel --> pkgconfig(gtk+2.0) - for prov in provides: - for match in re_prov_get_version.finditer(prov): - if options.debug: - print("NOTICE: Heuristically adding version %s from provide %s" \ - % (match.group('version'), prov)) - versions.add(match.group('version')) - - check_for = keys['extra'](basereqs, versions) - - if options.debug and versions: - pprint.pprint(versions) - - for check in check_for: - if check in provides: - if options.debug: - print("NOTICE: Matched: %s => %s" % (check, provides)) - change_to = check - break - - if change_to is None and provides: - provides_no_versions = [] - for prov in provides: - if re_prov_get_version.fullmatch(prov) is None: - provides_no_versions.append(prov) - - if len(provides_no_versions) == 1 and not provides_ignored: - change_to = provides_no_versions[0] - if options.debug: - print("NOTICE: Only one available versionless option, using %s" % change_to) - - - if provides: - if change_to is None: - no_change[req] = (provides, check_for) - else: - no_alt.add(req) - - if change_to is not None: - keys['changes'][req] = change_to - - if not options.doit: - if options.debug: - for keys in list(convert_brs.items()): - if 'changes' in keys and keys['changes']: - pprint.pprint(keys['changes']) - - if no_alt: - print("WARNING: no alternatives found for: %s" % ", ".join(sorted(no_alt))) - - if no_change and options.debug: - pprint.pprint(no_change) - else: - convert_brs = {} - - keys_with_changes = [keys for keys in convert_brs.values() if 'changes' in keys and keys['changes']] -# XXX - seems to cause false messages -# if not keys_with_changes: -# keys_with_changes.append({'changes': [], 'desc': 'unsplit BRs'}) - - for keys in keys_with_changes: - if spec.update_br(keys['changes'], change_description=keys['desc']): + if spec.convert_buildrequires(): made_changes = True +# if not options.doit: +# if options.debug: +# for keys in list(convert_brs.items()): +# if 'changes' in keys and keys['changes']: +# pprint.pprint(keys['changes']) +# +# if no_alt: +# print("WARNING: no alternatives found for: %s" % ", ".join(sorted(no_alt))) +# +# if no_change and options.debug: +# pprint.pprint(no_change) +# else: +# convert_brs = {} + if spec.clean_spec(): made_changes = True @@ -2469,6 +2487,15 @@ def main(): "Core {0} Updates Testing Source".format(options.distro) Downstream.DISTRO = options.distro + log_format = '%(levelname): %(message)s' + logging.basicConfig(format=log_format) + log = logging.getLogger(None) + if options.debug: + log.setLevel(logging.DEBUG) + else: + log.setLevel(logging.INFO) + + try: options.func(options) except KeyboardInterrupt: -- cgit v1.2.1