From ebb2f2ee0d1472f030b8596a417d9e49cd26d179 Mon Sep 17 00:00:00 2001 From: Marcus Huewe Date: Tue, 26 Dec 2017 23:14:47 +0100 Subject: [PATCH] Add support for querying weak dependencies The following abstract methods are added to the PackageQueryResult class: recommends(), suggests(), supplements(), and enhances(). Note that not all package/metadata formats have a notion of these weak dependencies. rpm rpmmd deb arch recommends x x x suggests x x x x supplements x x enhances x x x (where "x" represents "supported"). In case of an unsupported weak dependency, the implementation returns an empty list. We need the weak dependency support in order to fix #363 ("osc build -p ../rpms/tw doesnt send recommends to the server which makes client side build behave differently to server side build"). --- osc/util/archquery.py | 18 ++++++++++++++++++ osc/util/debquery.py | 16 ++++++++++++++++ osc/util/packagequery.py | 12 ++++++++++++ osc/util/repodata.py | 12 ++++++++++++ osc/util/rpmquery.py | 37 +++++++++++++++++++++++++++++++++++-- 5 files changed, 93 insertions(+), 2 deletions(-) diff --git a/osc/util/archquery.py b/osc/util/archquery.py index 2af87ded..72fa0242 100644 --- a/osc/util/archquery.py +++ b/osc/util/archquery.py @@ -95,6 +95,24 @@ class ArchQuery(packagequery.PackageQuery, packagequery.PackageQueryResult): def obsoletes(self): return self.fields['replaces'] if 'replaces' in self.fields else [] + def recommends(self): + # a .PKGINFO has no notion of "recommends" + return [] + + def suggests(self): + # libsolv treats an optdepend as a "suggests", hence we do the same + if 'optdepend' not in self.fields: + return [] + return [re.sub(':.*', '', entry) for entry in self.fields['optdepend']] + + def supplements(self): + # a .PKGINFO has no notion of "recommends" + return [] + + def enhances(self): + # a .PKGINFO has no notion of "enhances" + return [] + def canonname(self): pkgver = self.fields['pkgver'][0] if 'pkgver' in self.fields else None return self.name() + '-' + pkgver + '-' + self.arch() + '.' + self.pkgsuffix diff --git a/osc/util/debquery.py b/osc/util/debquery.py index 7d3c7545..4c2e0e5f 100644 --- a/osc/util/debquery.py +++ b/osc/util/debquery.py @@ -90,6 +90,9 @@ class DebQuery(packagequery.PackageQuery, packagequery.PackageQueryResult): self.fields['pre_depends'] = [ i.strip() for i in re.split(',\s*', self.fields.get('pre_depends', '')) if i ] self.fields['conflicts'] = [ i.strip() for i in re.split(',\s*', self.fields.get('conflicts', '')) if i ] self.fields['breaks'] = [ i.strip() for i in re.split(',\s*', self.fields.get('breaks', '')) if i ] + self.fields['recommends'] = [ i.strip() for i in re.split(',\s*', self.fields.get('recommends', '')) if i ] + self.fields['suggests'] = [ i.strip() for i in re.split(',\s*', self.fields.get('suggests', '')) if i ] + self.fields['enhances'] = [ i.strip() for i in re.split(',\s*', self.fields.get('enhances', '')) if i ] if self_provides: # add self provides entry self.fields['provides'].append('%s (= %s)' % (self.name(), '-'.join(versrel))) @@ -137,6 +140,19 @@ class DebQuery(packagequery.PackageQuery, packagequery.PackageQueryResult): def obsoletes(self): return [] + def recommends(self): + return self.fields['recommends'] + + def suggests(self): + return self.fields['suggests'] + + def supplements(self): + # a control file has no notion of "supplements" + return [] + + def enhances(self): + return self.fields['enhances'] + def gettag(self, num): return self.fields.get(num, None) diff --git a/osc/util/packagequery.py b/osc/util/packagequery.py index d3add697..1e6bec35 100644 --- a/osc/util/packagequery.py +++ b/osc/util/packagequery.py @@ -127,6 +127,18 @@ class PackageQueryResult: def obsoletes(self): raise NotImplementedError + def recommends(self): + raise NotImplementedError + + def suggests(self): + raise NotImplementedError + + def supplements(self): + raise NotImplementedError + + def enhances(self): + raise NotImplementedError + def gettag(self, tag): raise NotImplementedError diff --git a/osc/util/repodata.py b/osc/util/repodata.py index 7f952f54..c57ae7dc 100644 --- a/osc/util/repodata.py +++ b/osc/util/repodata.py @@ -154,6 +154,18 @@ class RepoDataQueryResult(osc.util.packagequery.PackageQueryResult): def obsoletes(self): return self.__parseEntryCollection('obsoletes') + def recommends(self): + return self.__parseEntryCollection('recommends') + + def suggests(self): + return self.__parseEntryCollection('suggests') + + def supplements(self): + return self.__parseEntryCollection('supplements') + + def enhances(self): + return self.__parseEntryCollection('enhances') + def canonname(self): return osc.util.rpmquery.RpmQuery.filename(self.name(), None, self.version(), self.release(), self.arch()) diff --git a/osc/util/rpmquery.py b/osc/util/rpmquery.py index de05ff53..cba67d8a 100644 --- a/osc/util/rpmquery.py +++ b/osc/util/rpmquery.py @@ -58,11 +58,18 @@ class RpmQuery(packagequery.PackageQuery, packagequery.PackageQueryResult): GREATER = 1 << 2 EQUAL = 1 << 3 + SENSE_STRONG = 1 << 27 + default_tags = (1000, 1001, 1002, 1003, 1004, 1022, 1005, 1020, 1047, 1112, 1113, # provides 1049, 1048, 1050, # requires 1054, 1053, 1055, # conflicts - 1090, 1114, 1115 # obsoletes + 1090, 1114, 1115, # obsoletes + 1156, 1158, 1157, # oldsuggests + 5046, 5047, 5048, # recommends + 5049, 5051, 5050, # suggests + 5052, 5053, 5054, # supplements + 5055, 5056, 5057 # enhances ) def __init__(self, fh): @@ -156,7 +163,7 @@ class RpmQuery(packagequery.PackageQuery, packagequery.PackageQueryResult): else: raise RpmHeaderError(self.__path, 'unsupported tag type \'%d\' (tag: \'%s\'' % (entry.type, entry.tag)) - def __reqprov(self, tag, flags, version): + def __reqprov(self, tag, flags, version, strong=None): pnames = self.header.gettag(tag) if not pnames: return [] @@ -167,6 +174,14 @@ class RpmQuery(packagequery.PackageQuery, packagequery.PackageQueryResult): raise RpmError(self.__path, 'cannot get provides/requires, tags are missing') res = [] for name, flags, ver in zip(pnames, pflags, pvers): + if strong is not None: + # compat code for the obsolete RPMTAG_OLDSUGGESTSNAME tag + # strong == 1 => return only "recommends" + # strong == 0 => return only "suggests" + if strong == 1: + strong = self.SENSE_STRONG + if (flags & self.SENSE_STRONG) != strong: + continue # RPMSENSE_SENSEMASK = 15 (see rpmlib.h) but ignore RPMSENSE_SERIAL (= 1 << 0) therefore use 14 if flags & 14: name += ' ' @@ -236,6 +251,24 @@ class RpmQuery(packagequery.PackageQuery, packagequery.PackageQueryResult): def obsoletes(self): return self.__reqprov(1090, 1114, 1115) + def recommends(self): + recommends = self.__reqprov(5046, 5048, 5047) + if not recommends: + recommends = self.__reqprov(1156, 1158, 1157, 1) + return recommends + + def suggests(self): + suggests = self.__reqprov(5049, 5051, 5050) + if not suggests: + suggests = self.__reqprov(1156, 1158, 1157, 0) + return suggests + + def supplements(self): + return self.__reqprov(5052, 5054, 5053) + + def enhances(self): + return self.__reqprov(5055, 5057, 5506) + def is_src(self): # SOURCERPM = 1044 return self.gettag(1044) is None