summaryrefslogtreecommitdiffstats
path: root/meta/recipes-devtools/python/python-smartpm/smart-recommends.patch
diff options
context:
space:
mode:
authorRobert Yang <liezhi.yang@windriver.com>2015-07-08 00:23:48 -0700
committerRichard Purdie <richard.purdie@linuxfoundation.org>2015-07-09 18:00:18 +0100
commit05b02d27d2115c0af32988bb3b43286f7943471c (patch)
tree436f4bb3fef2875da1051a41630530b7aeafdae0 /meta/recipes-devtools/python/python-smartpm/smart-recommends.patch
parentf9ac3f3e200e4fd0dfe0f45ddc606ce945ea0143 (diff)
downloadpoky-05b02d27d2115c0af32988bb3b43286f7943471c.tar.gz
python-smartpm: 1.4.1 -> 1.5
* Remove the following patches since the are already in the source: smart-config-ignore-all-recommends.patch smart-conflict-provider.patch smart-dflags.patch smart-filename-NAME_MAX.patch smart-flag-exclude-packages.patch smart-flag-ignore-recommends.patch smart-metadata-match.patch smart-multilib-fixes.patch smart-rpm-extra-macros.patch smart-rpm-md-parse.patch smart-rpm-root.patch smart-tmpdir.patch smart-yaml-error.patch * Update the following patches, part of the code are already in the source: smart-attempt.patch smart-improve-error-reporting.patch smart-recommends.patch smartpm-rpm5-nodig.patch * Use github and git repo as the SRC_URI. (From OE-Core rev: 5fc580fc444e45d00de0e50d32b6e6e0b2e6b7ea) Signed-off-by: Robert Yang <liezhi.yang@windriver.com> Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
Diffstat (limited to 'meta/recipes-devtools/python/python-smartpm/smart-recommends.patch')
-rw-r--r--meta/recipes-devtools/python/python-smartpm/smart-recommends.patch1051
1 files changed, 35 insertions, 1016 deletions
diff --git a/meta/recipes-devtools/python/python-smartpm/smart-recommends.patch b/meta/recipes-devtools/python/python-smartpm/smart-recommends.patch
index a41b1beaa9..d607fc4752 100644
--- a/meta/recipes-devtools/python/python-smartpm/smart-recommends.patch
+++ b/meta/recipes-devtools/python/python-smartpm/smart-recommends.patch
@@ -10,10 +10,10 @@ Upstream-Status: Pending
10Signed-off-by: Paul Eggleton <paul.eggleton@linux.intel.com> 10Signed-off-by: Paul Eggleton <paul.eggleton@linux.intel.com>
11 11
12diff --git a/smart/backends/rpm/base.py b/smart/backends/rpm/base.py 12diff --git a/smart/backends/rpm/base.py b/smart/backends/rpm/base.py
13index 0489e11..b9e9cb2 100644 13index 9332ea0..4fcfbee 100644
14--- a/smart/backends/rpm/base.py 14--- a/smart/backends/rpm/base.py
15+++ b/smart/backends/rpm/base.py 15+++ b/smart/backends/rpm/base.py
16@@ -198,6 +198,29 @@ class RPMPackage(Package): 16@@ -225,6 +225,52 @@ class RPMPackage(Package):
17 break 17 break
18 else: 18 else:
19 return False 19 return False
@@ -40,413 +40,37 @@ index 0489e11..b9e9cb2 100644
40+ break 40+ break
41+ else: 41+ else:
42+ return False 42+ return False
43+ srecs = fk(self.recommends)
44+ orecs = fk(other.recommends)
45+ if srecs != orecs:
46+ for srec in srecs:
47+ if srec.name[0] == "/" or srec in orecs:
48+ continue
49+ for orec in orecs:
50+ if (srec.name == orec.name and
51+ srec.relation == orec.relation and
52+ checkver(srec.version, orec.version)):
53+ break
54+ else:
55+ return False
56+ for orec in orecs:
57+ if orec.name[0] == "/" or orec in srecs:
58+ continue
59+ for srec in srecs:
60+ if (srec.name == orec.name and
61+ srec.relation == orec.relation and
62+ checkver(srec.version, orec.version)):
63+ break
64+ else:
65+ return False
43 return True 66 return True
44 67
45 def coexists(self, other): 68 def coexists(self, other):
46diff --git a/smart/backends/rpm/header.py b/smart/backends/rpm/header.py
47index 31786cc..4880f43 100644
48--- a/smart/backends/rpm/header.py
49+++ b/smart/backends/rpm/header.py
50@@ -292,6 +292,7 @@ class RPMHeaderLoader(Loader):
51 f = [0]
52 elif type(f) != list:
53 f = [f]
54+ recdict = {}
55 reqdict = {}
56 for i in range(len(n)):
57 ni = n[i]
58@@ -308,10 +309,16 @@ class RPMHeaderLoader(Loader):
59 # RPMSENSE_SCRIPT_PREUN |
60 # RPMSENSE_SCRIPT_POST |
61 # RPMSENSE_SCRIPT_POSTUN == 7744
62- reqdict[(f[i]&7744 and PreReq or Req,
63- intern(ni), r, vi)] = True
64+ if (f[i]&rpm.RPMSENSE_MISSINGOK):
65+ recdict[(f[i]&7744 and PreReq or Req,
66+ intern(ni), r, vi)] = True
67+ else:
68+ reqdict[(f[i]&7744 and PreReq or Req,
69+ intern(ni), r, vi)] = True
70+ recargs = collapse_libc_requires(recdict.keys())
71 reqargs = collapse_libc_requires(reqdict.keys())
72 else:
73+ recargs = None
74 reqargs = None
75
76 n = h[1054] # RPMTAG_CONFLICTNAME
77@@ -365,7 +372,7 @@ class RPMHeaderLoader(Loader):
78 versionarch = "%s@%s" % (distversion, arch)
79
80 pkg = self.buildPackage((Pkg, name, versionarch),
81- prvargs, reqargs, upgargs, cnfargs)
82+ prvargs, reqargs, upgargs, cnfargs, recargs)
83 pkg.loaders[self] = offset
84 self._offsets[offset] = pkg
85 self._groups[pkg] = intern(h[rpm.RPMTAG_GROUP])
86@@ -583,8 +590,8 @@ class URPMILoader(RPMHeaderListLoader):
87 def setErrataFlags(self, flagdict):
88 self._flagdict = flagdict
89
90- def buildPackage(self, pkgargs, prvargs, reqargs, upgargs, cnfargs):
91- pkg = Loader.buildPackage(self, pkgargs, prvargs, reqargs, upgargs, cnfargs)
92+ def buildPackage(self, pkgargs, prvargs, reqargs, upgargs, cnfargs, recargs):
93+ pkg = Loader.buildPackage(self, pkgargs, prvargs, reqargs, upgargs, cnfargs, recargs)
94 name = pkgargs[1]
95 if hasattr(self, '_flagdict') and self._flagdict and name in self._flagdict:
96 if sysconf.getReadOnly():
97diff --git a/smart/backends/rpm/metadata.py b/smart/backends/rpm/metadata.py
98index 2c54f39..568fe06 100644
99--- a/smart/backends/rpm/metadata.py
100+++ b/smart/backends/rpm/metadata.py
101@@ -165,6 +165,7 @@ class RPMMetaDataLoader(Loader):
102 distepoch = None
103 info = {}
104 reqdict = {}
105+ recdict = {}
106 prvdict = {}
107 upgdict = {}
108 cnfdict = {}
109@@ -287,12 +288,16 @@ class RPMMetaDataLoader(Loader):
110
111 lasttag = queue[-1].tag
112 if lasttag == REQUIRES:
113- if elem.get("pre") == "1":
114- reqdict[(RPMPreRequires,
115- ename, erelation, eversion)] = True
116+ if elem.get("missingok") == "1":
117+ recdict[(RPMRequires,
118+ ename, erelation, eversion)] = True
119 else:
120- reqdict[(RPMRequires,
121- ename, erelation, eversion)] = True
122+ if elem.get("pre") == "1":
123+ reqdict[(RPMPreRequires,
124+ ename, erelation, eversion)] = True
125+ else:
126+ reqdict[(RPMRequires,
127+ ename, erelation, eversion)] = True
128
129 elif lasttag == PROVIDES:
130 if ename[0] == "/":
131@@ -328,6 +333,12 @@ class RPMMetaDataLoader(Loader):
132 (RPMProvides, x[1], x[3]) in prvdict or
133 system_provides.match(*x[:3]))]
134 reqargs = collapse_libc_requires(reqargs)
135+
136+ recargs = [x for x in recdict
137+ if not ((x[2] is None or "=" in x[2]) and
138+ (RPMProvides, x[1], x[3]) in prvdict or
139+ system_provides.match(*x[:3]))]
140+
141 prvargs = prvdict.keys()
142 cnfargs = cnfdict.keys()
143 upgargs = upgdict.keys()
144@@ -339,7 +350,7 @@ class RPMMetaDataLoader(Loader):
145 versionarch = "%s@%s" % (distversion, arch)
146
147 pkg = self.buildPackage((RPMPackage, name, versionarch),
148- prvargs, reqargs, upgargs, cnfargs)
149+ prvargs, reqargs, upgargs, cnfargs, recargs)
150 pkg.loaders[self] = info
151
152 # Store the provided files for future usage.
153@@ -362,6 +373,7 @@ class RPMMetaDataLoader(Loader):
154 distepoch = None
155 pkgid = None
156 reqdict.clear()
157+ recdict.clear()
158 prvdict.clear()
159 upgdict.clear()
160 cnfdict.clear()
161diff --git a/smart/cache.py b/smart/cache.py
162index b829825..cec8bb3 100644
163--- a/smart/cache.py
164+++ b/smart/cache.py
165@@ -32,7 +32,8 @@ class Package(object):
166 self.name = name
167 self.version = version
168 self.provides = ()
169- self.requires = ()
170+ self.requires = []
171+ self.recommends = []
172 self.upgrades = ()
173 self.conflicts = ()
174 self.installed = False
175@@ -55,7 +56,9 @@ class Package(object):
176 fk([x for x in self.provides if x.name[0] != "/"]) !=
177 fk([x for x in other.provides if x.name[0] != "/"]) or
178 fk([x for x in self.requires if x.name[0] != "/"]) !=
179- fk([x for x in other.requires if x.name[0] != "/"])):
180+ fk([x for x in other.requires if x.name[0] != "/"]) or
181+ fk([x for x in self.recommends if x.name[0] != "/"]) !=
182+ fk([x for x in other.recommends if x.name[0] != "/"])):
183 return False
184 return True
185
186@@ -110,6 +113,7 @@ class Package(object):
187 self.version,
188 self.provides,
189 self.requires,
190+ self.recommends,
191 self.upgrades,
192 self.conflicts,
193 self.installed,
194@@ -122,6 +126,7 @@ class Package(object):
195 self.version,
196 self.provides,
197 self.requires,
198+ self.recommends,
199 self.upgrades,
200 self.conflicts,
201 self.installed,
202@@ -274,6 +279,7 @@ class Provides(object):
203 self.version = version
204 self.packages = []
205 self.requiredby = ()
206+ self.recommendedby = ()
207 self.upgradedby = ()
208 self.conflictedby = ()
209
210@@ -401,7 +407,7 @@ class Loader(object):
211 def loadFileProvides(self, fndict):
212 pass
213
214- def buildPackage(self, pkgargs, prvargs, reqargs, upgargs, cnfargs):
215+ def buildPackage(self, pkgargs, prvargs, reqargs, upgargs, cnfargs, recargs = None):
216 cache = self._cache
217 pkg = pkgargs[0](*pkgargs[1:])
218 relpkgs = []
219@@ -427,6 +433,17 @@ class Loader(object):
220 relpkgs.append(req.packages)
221 pkg.requires.append(req)
222
223+ if recargs:
224+ pkg.recommends = []
225+ for args in recargs:
226+ rec = cache._objmap.get(args)
227+ if not rec:
228+ rec = args[0](*args[1:])
229+ cache._objmap[args] = rec
230+ cache._recommends.append(rec)
231+ relpkgs.append(rec.packages)
232+ pkg.recommends.append(rec)
233+
234 if upgargs:
235 pkg.upgrades = []
236 for args in upgargs:
237@@ -572,6 +589,7 @@ class Cache(object):
238 self._packages = []
239 self._provides = []
240 self._requires = []
241+ self._recommends = []
242 self._upgrades = []
243 self._conflicts = []
244 self._objmap = {}
245@@ -581,6 +599,8 @@ class Cache(object):
246 del prv.packages[:]
247 if prv.requiredby:
248 del prv.requiredby[:]
249+ if prv.recommendedby:
250+ del prv.recommendedby[:]
251 if prv.upgradedby:
252 del prv.upgradedby[:]
253 if prv.conflictedby:
254@@ -589,6 +609,10 @@ class Cache(object):
255 del req.packages[:]
256 if req.providedby:
257 del req.providedby[:]
258+ for rec in self._recommends:
259+ del rec.packages[:]
260+ if rec.providedby:
261+ del rec.providedby[:]
262 for upg in self._upgrades:
263 del upg.packages[:]
264 if upg.providedby:
265@@ -600,6 +624,7 @@ class Cache(object):
266 del self._packages[:]
267 del self._provides[:]
268 del self._requires[:]
269+ del self._recommends[:]
270 del self._upgrades[:]
271 del self._conflicts[:]
272 self._objmap.clear()
273@@ -621,6 +646,7 @@ class Cache(object):
274 packages = {}
275 provides = {}
276 requires = {}
277+ recommends = {}
278 upgrades = {}
279 conflicts = {}
280 objmap = self._objmap
281@@ -646,6 +672,11 @@ class Cache(object):
282 if req not in requires:
283 objmap[req.getInitArgs()] = req
284 requires[req] = True
285+ for rec in pkg.recommends[:]:
286+ rec.packages.append(pkg)
287+ if rec not in recommends:
288+ objmap[rec.getInitArgs()] = rec
289+ recommends[rec] = True
290 for upg in pkg.upgrades:
291 upg.packages.append(pkg)
292 if upg not in upgrades:
293@@ -659,6 +690,7 @@ class Cache(object):
294 self._packages[:] = packages.keys()
295 self._provides[:] = provides.keys()
296 self._requires[:] = requires.keys()
297+ self._recommends[:] = recommends.keys()
298 self._upgrades[:] = upgrades.keys()
299 self._conflicts[:] = conflicts.keys()
300
301@@ -710,6 +742,14 @@ class Cache(object):
302 lst.append(req)
303 else:
304 reqnames[name] = [req]
305+ recnames = {}
306+ for rec in self._recommends:
307+ for name in rec.getMatchNames():
308+ lst = recnames.get(name)
309+ if lst:
310+ lst.append(rec)
311+ else:
312+ recnames[name] = [rec]
313 upgnames = {}
314 for upg in self._upgrades:
315 for name in upg.getMatchNames():
316@@ -739,6 +779,18 @@ class Cache(object):
317 prv.requiredby.append(req)
318 else:
319 prv.requiredby = [req]
320+ lst = recnames.get(prv.name)
321+ if lst:
322+ for rec in lst:
323+ if rec.matches(prv):
324+ if rec.providedby:
325+ rec.providedby.append(prv)
326+ else:
327+ rec.providedby = [prv]
328+ if prv.recommendedby:
329+ prv.recommendedby.append(rec)
330+ else:
331+ prv.recommendedby = [rec]
332 lst = upgnames.get(prv.name)
333 if lst:
334 for upg in lst:
335@@ -782,6 +834,12 @@ class Cache(object):
336 else:
337 return [x for x in self._requires if x.name == name]
338
339+ def getRecommends(self, name=None):
340+ if not name:
341+ return self._recommends
342+ else:
343+ return [x for x in self._recommends if x.name == name]
344+
345 def getUpgrades(self, name=None):
346 if not name:
347 return self._upgrades
348@@ -807,6 +865,12 @@ class Cache(object):
349 for req in self._requires:
350 if prvname in req.getMatchNames() and req.matches(prv):
351 searcher.addResult(req)
352+ if searcher.recommends:
353+ for prv in searcher.recommends:
354+ prvname = prv.name
355+ for req in self._recommends:
356+ if prvname in req.getMatchNames() and req.matches(prv):
357+ searcher.addResult(req)
358 if searcher.upgrades:
359 for prv in searcher.upgrades:
360 prvname = prv.name
361@@ -839,6 +903,7 @@ class Cache(object):
362 self._packages = state["_packages"]
363 provides = {}
364 requires = {}
365+ recommends = {}
366 upgrades = {}
367 conflicts = {}
368 for pkg in self._packages:
369@@ -848,6 +913,9 @@ class Cache(object):
370 for req in pkg.requires:
371 req.packages.append(pkg)
372 requires[req] = True
373+ for rec in pkg.recommends:
374+ rec.packages.append(pkg)
375+ recommends[rec] = True
376 for upg in pkg.upgrades:
377 upg.packages.append(pkg)
378 upgrades[upg] = True
379@@ -856,6 +924,7 @@ class Cache(object):
380 conflicts[cnf] = True
381 self._provides = provides.keys()
382 self._requires = requires.keys()
383+ self._recommends = recommends.keys()
384 self._upgrades = upgrades.keys()
385 self._conflicts = conflicts.keys()
386 self._objmap = {}
387diff --git a/smart/ccache.c b/smart/ccache.c 69diff --git a/smart/ccache.c b/smart/ccache.c
388index 7541e26..7193185 100644 70index 7193185..8b66515 100644
389--- a/smart/ccache.c 71--- a/smart/ccache.c
390+++ b/smart/ccache.c 72+++ b/smart/ccache.c
391@@ -82,6 +82,7 @@ typedef struct { 73@@ -500,6 +500,46 @@ Package_equals(PackageObject *self, PackageObject *other)
392 PyObject *version;
393 PyObject *provides;
394 PyObject *requires;
395+ PyObject *recommends;
396 PyObject *upgrades;
397 PyObject *conflicts;
398 PyObject *installed;
399@@ -96,6 +97,7 @@ typedef struct {
400 PyObject *version;
401 PyObject *packages;
402 PyObject *requiredby;
403+ PyObject *recommendedby;
404 PyObject *upgradedby;
405 PyObject *conflictedby;
406 } ProvidesObject;
407@@ -123,6 +125,7 @@ typedef struct {
408 PyObject *_packages;
409 PyObject *_provides;
410 PyObject *_requires;
411+ PyObject *_recommends;
412 PyObject *_upgrades;
413 PyObject *_conflicts;
414 PyObject *_objmap;
415@@ -211,7 +214,8 @@ Package_init(PackageObject *self, PyObject *args)
416 Py_INCREF(self->name);
417 Py_INCREF(self->version);
418 self->provides = PyTuple_New(0);
419- self->requires = PyTuple_New(0);
420+ self->requires = PyList_New(0);
421+ self->recommends = PyList_New(0);
422 self->upgrades = PyTuple_New(0);
423 self->conflicts = PyTuple_New(0);
424 Py_INCREF(Py_False);
425@@ -228,6 +232,7 @@ Package_traverse(PackageObject *self, visitproc visit, void *arg)
426 {
427 Py_VISIT(self->provides);
428 Py_VISIT(self->requires);
429+ Py_VISIT(self->recommends);
430 Py_VISIT(self->upgrades);
431 Py_VISIT(self->conflicts);
432 Py_VISIT(self->loaders);
433@@ -239,6 +244,7 @@ Package_clear(PackageObject *self)
434 {
435 Py_CLEAR(self->provides);
436 Py_CLEAR(self->requires);
437+ Py_CLEAR(self->recommends);
438 Py_CLEAR(self->upgrades);
439 Py_CLEAR(self->conflicts);
440 Py_CLEAR(self->loaders);
441@@ -252,6 +258,7 @@ Package_dealloc(PackageObject *self)
442 Py_XDECREF(self->version);
443 Py_XDECREF(self->provides);
444 Py_XDECREF(self->requires);
445+ Py_XDECREF(self->recommends);
446 Py_XDECREF(self->upgrades);
447 Py_XDECREF(self->conflicts);
448 Py_XDECREF(self->installed);
449@@ -453,6 +460,46 @@ Package_equals(PackageObject *self, PackageObject *other)
450 } 74 }
451 } 75 }
452 76
@@ -493,156 +117,7 @@ index 7541e26..7193185 100644
493 exit: 117 exit:
494 Py_INCREF(ret); 118 Py_INCREF(ret);
495 return ret; 119 return ret;
496@@ -606,13 +653,14 @@ Package_getPriority(PackageObject *self, PyObject *args) 120@@ -1813,6 +1853,59 @@ Loader_buildPackage(LoaderObject *self, PyObject *args)
497 static PyObject *
498 Package__getstate__(PackageObject *self, PyObject *args)
499 {
500- PyObject *state = PyTuple_New(10);
501+ PyObject *state = PyTuple_New(11);
502 if (!state) return NULL;
503
504 Py_INCREF(self->name);
505 Py_INCREF(self->version);
506 Py_INCREF(self->provides);
507 Py_INCREF(self->requires);
508+ Py_INCREF(self->recommends);
509 Py_INCREF(self->upgrades);
510 Py_INCREF(self->conflicts);
511 Py_INCREF(self->installed);
512@@ -620,16 +668,17 @@ Package__getstate__(PackageObject *self, PyObject *args)
513 Py_INCREF(self->priority);
514 Py_INCREF(self->loaders);
515
516- PyTuple_SET_ITEM(state, 0, self->name);
517- PyTuple_SET_ITEM(state, 1, self->version);
518- PyTuple_SET_ITEM(state, 2, self->provides);
519- PyTuple_SET_ITEM(state, 3, self->requires);
520- PyTuple_SET_ITEM(state, 4, self->upgrades);
521- PyTuple_SET_ITEM(state, 5, self->conflicts);
522- PyTuple_SET_ITEM(state, 6, self->installed);
523- PyTuple_SET_ITEM(state, 7, self->essential);
524- PyTuple_SET_ITEM(state, 8, self->priority);
525- PyTuple_SET_ITEM(state, 9, self->loaders);
526+ PyTuple_SET_ITEM(state, 0, self->name);
527+ PyTuple_SET_ITEM(state, 1, self->version);
528+ PyTuple_SET_ITEM(state, 2, self->provides);
529+ PyTuple_SET_ITEM(state, 3, self->requires);
530+ PyTuple_SET_ITEM(state, 4, self->recommends);
531+ PyTuple_SET_ITEM(state, 5, self->upgrades);
532+ PyTuple_SET_ITEM(state, 6, self->conflicts);
533+ PyTuple_SET_ITEM(state, 7, self->installed);
534+ PyTuple_SET_ITEM(state, 8, self->essential);
535+ PyTuple_SET_ITEM(state, 9, self->priority);
536+ PyTuple_SET_ITEM(state, 10, self->loaders);
537
538 return state;
539 }
540@@ -637,7 +686,7 @@ Package__getstate__(PackageObject *self, PyObject *args)
541 static PyObject *
542 Package__setstate__(PackageObject *self, PyObject *state)
543 {
544- if (!PyTuple_Check(state) || PyTuple_GET_SIZE(state) != 10) {
545+ if (!PyTuple_Check(state) || PyTuple_GET_SIZE(state) != 11) {
546 PyErr_SetString(StateVersionError, "");
547 return NULL;
548 }
549@@ -645,18 +694,20 @@ Package__setstate__(PackageObject *self, PyObject *state)
550 self->version = PyTuple_GET_ITEM(state, 1);
551 self->provides = PyTuple_GET_ITEM(state, 2);
552 self->requires = PyTuple_GET_ITEM(state, 3);
553- self->upgrades = PyTuple_GET_ITEM(state, 4);
554- self->conflicts = PyTuple_GET_ITEM(state, 5);
555- self->installed = PyTuple_GET_ITEM(state, 6);
556- self->essential = PyTuple_GET_ITEM(state, 7);
557- self->priority = PyTuple_GET_ITEM(state, 8);
558- self->loaders = PyTuple_GET_ITEM(state, 9);
559+ self->recommends = PyTuple_GET_ITEM(state, 4);
560+ self->upgrades = PyTuple_GET_ITEM(state, 5);
561+ self->conflicts = PyTuple_GET_ITEM(state, 6);
562+ self->installed = PyTuple_GET_ITEM(state, 7);
563+ self->essential = PyTuple_GET_ITEM(state, 8);
564+ self->priority = PyTuple_GET_ITEM(state, 9);
565+ self->loaders = PyTuple_GET_ITEM(state, 10);
566
567
568 Py_INCREF(self->name);
569 Py_INCREF(self->version);
570 Py_INCREF(self->provides);
571 Py_INCREF(self->requires);
572+ Py_INCREF(self->recommends);
573 Py_INCREF(self->upgrades);
574 Py_INCREF(self->conflicts);
575 Py_INCREF(self->installed);
576@@ -686,6 +737,7 @@ static PyMemberDef Package_members[] = {
577 {"version", T_OBJECT, OFF(version), 0, 0},
578 {"provides", T_OBJECT, OFF(provides), 0, 0},
579 {"requires", T_OBJECT, OFF(requires), 0, 0},
580+ {"recommends", T_OBJECT, OFF(recommends), 0, 0},
581 {"upgrades", T_OBJECT, OFF(upgrades), 0, 0},
582 {"conflicts", T_OBJECT, OFF(conflicts), 0, 0},
583 {"installed", T_OBJECT, OFF(installed), 0, 0},
584@@ -750,6 +802,7 @@ Provides_init(ProvidesObject *self, PyObject *args)
585 Py_INCREF(self->version);
586 self->packages = PyList_New(0);
587 self->requiredby = PyTuple_New(0);
588+ self->recommendedby = PyTuple_New(0);
589 self->upgradedby = PyTuple_New(0);
590 self->conflictedby = PyTuple_New(0);
591 return 0;
592@@ -760,6 +813,7 @@ Provides_traverse(ProvidesObject *self, visitproc visit, void *arg)
593 {
594 Py_VISIT(self->packages);
595 Py_VISIT(self->requiredby);
596+ Py_VISIT(self->recommendedby);
597 Py_VISIT(self->upgradedby);
598 Py_VISIT(self->conflictedby);
599 return 0;
600@@ -770,6 +824,7 @@ Provides_clear(ProvidesObject *self)
601 {
602 Py_CLEAR(self->packages);
603 Py_CLEAR(self->requiredby);
604+ Py_CLEAR(self->recommendedby);
605 Py_CLEAR(self->upgradedby);
606 Py_CLEAR(self->conflictedby);
607 return 0;
608@@ -782,6 +837,7 @@ Provides_dealloc(ProvidesObject *self)
609 Py_XDECREF(self->version);
610 Py_XDECREF(self->packages);
611 Py_XDECREF(self->requiredby);
612+ Py_XDECREF(self->recommendedby);
613 Py_XDECREF(self->upgradedby);
614 Py_XDECREF(self->conflictedby);
615 self->ob_type->tp_free((PyObject *)self);
616@@ -960,6 +1016,7 @@ static PyMemberDef Provides_members[] = {
617 {"version", T_OBJECT, OFF(version), 0, 0},
618 {"packages", T_OBJECT, OFF(packages), 0, 0},
619 {"requiredby", T_OBJECT, OFF(requiredby), 0, 0},
620+ {"recommendedby", T_OBJECT, OFF(recommendedby), 0, 0},
621 {"upgradedby", T_OBJECT, OFF(upgradedby), 0, 0},
622 {"conflictedby", T_OBJECT, OFF(conflictedby), 0, 0},
623 {NULL}
624@@ -1555,6 +1612,7 @@ Loader_buildPackage(LoaderObject *self, PyObject *args)
625 PyObject *reqargs;
626 PyObject *upgargs;
627 PyObject *cnfargs;
628+ PyObject *recargs = NULL;
629 PyObject *callargs;
630
631 PyObject *pkg;
632@@ -1574,9 +1632,10 @@ Loader_buildPackage(LoaderObject *self, PyObject *args)
633
634 cache = (CacheObject *)self->_cache;
635
636- if (!PyArg_ParseTuple(args, "O!O&O&O&O&", &PyTuple_Type, &pkgargs,
637+ if (!PyArg_ParseTuple(args, "O!O&O&O&O&|O&", &PyTuple_Type, &pkgargs,
638 mylist, &prvargs, mylist, &reqargs,
639- mylist, &upgargs, mylist, &cnfargs))
640+ mylist, &upgargs, mylist, &cnfargs,
641+ mylist, &recargs))
642 return NULL;
643
644 if (PyTuple_GET_SIZE(pkgargs) < 2) {
645@@ -1701,6 +1760,59 @@ Loader_buildPackage(LoaderObject *self, PyObject *args)
646 } 121 }
647 } 122 }
648 123
@@ -702,48 +177,7 @@ index 7541e26..7193185 100644
702 /* if upgargs: */ 177 /* if upgargs: */
703 if (upgargs) { 178 if (upgargs) {
704 int i = 0; 179 int i = 0;
705@@ -2391,6 +2503,7 @@ Cache_init(CacheObject *self, PyObject *args) 180@@ -2592,6 +2685,16 @@ Cache_reset(CacheObject *self, PyObject *args)
706 self->_packages = PyList_New(0);
707 self->_provides = PyList_New(0);
708 self->_requires = PyList_New(0);
709+ self->_recommends = PyList_New(0);
710 self->_upgrades = PyList_New(0);
711 self->_conflicts = PyList_New(0);
712 self->_objmap = PyDict_New();
713@@ -2404,6 +2517,7 @@ Cache_traverse(CacheObject *self, visitproc visit, void *arg)
714 Py_VISIT(self->_packages);
715 Py_VISIT(self->_provides);
716 Py_VISIT(self->_requires);
717+ Py_VISIT(self->_recommends);
718 Py_VISIT(self->_upgrades);
719 Py_VISIT(self->_conflicts);
720 Py_VISIT(self->_objmap);
721@@ -2417,6 +2531,7 @@ Cache_clear(CacheObject *self)
722 Py_CLEAR(self->_packages);
723 Py_CLEAR(self->_provides);
724 Py_CLEAR(self->_requires);
725+ Py_CLEAR(self->_recommends);
726 Py_CLEAR(self->_upgrades);
727 Py_CLEAR(self->_conflicts);
728 Py_CLEAR(self->_objmap);
729@@ -2430,6 +2545,7 @@ Cache_dealloc(CacheObject *self)
730 Py_XDECREF(self->_packages);
731 Py_XDECREF(self->_provides);
732 Py_XDECREF(self->_requires);
733+ Py_XDECREF(self->_recommends);
734 Py_XDECREF(self->_upgrades);
735 Py_XDECREF(self->_conflicts);
736 Py_XDECREF(self->_objmap);
737@@ -2449,6 +2565,8 @@ Cache_reset(CacheObject *self, PyObject *args)
738 LIST_CLEAR(prvobj->packages);
739 if (PyList_Check(prvobj->requiredby))
740 LIST_CLEAR(prvobj->requiredby);
741+ if (PyList_Check(prvobj->recommendedby))
742+ LIST_CLEAR(prvobj->recommendedby);
743 if (PyList_Check(prvobj->upgradedby))
744 LIST_CLEAR(prvobj->upgradedby);
745 if (PyList_Check(prvobj->conflictedby))
746@@ -2464,6 +2582,16 @@ Cache_reset(CacheObject *self, PyObject *args)
747 if (PyList_Check(reqobj->providedby)) 181 if (PyList_Check(reqobj->providedby))
748 LIST_CLEAR(reqobj->providedby); 182 LIST_CLEAR(reqobj->providedby);
749 } 183 }
@@ -760,37 +194,7 @@ index 7541e26..7193185 100644
760 len = PyList_GET_SIZE(self->_upgrades); 194 len = PyList_GET_SIZE(self->_upgrades);
761 for (i = 0; i != len; i++) { 195 for (i = 0; i != len; i++) {
762 DependsObject *upgobj; 196 DependsObject *upgobj;
763@@ -2487,6 +2615,7 @@ Cache_reset(CacheObject *self, PyObject *args) 197@@ -2834,6 +2937,30 @@ Cache__reload(CacheObject *self, PyObject *args)
764 LIST_CLEAR(self->_packages);
765 LIST_CLEAR(self->_provides);
766 LIST_CLEAR(self->_requires);
767+ LIST_CLEAR(self->_recommends);
768 LIST_CLEAR(self->_upgrades);
769 LIST_CLEAR(self->_conflicts);
770 PyDict_Clear(self->_objmap);
771@@ -2534,6 +2663,7 @@ Cache__reload(CacheObject *self, PyObject *args)
772 packages = {}
773 provides = {}
774 requires = {}
775+ recommends = {}
776 upgrades = {}
777 conflicts = {}
778 objmap = self._objmap
779@@ -2541,11 +2671,12 @@ Cache__reload(CacheObject *self, PyObject *args)
780 PyObject *packages = PyDict_New();
781 PyObject *provides = PyDict_New();
782 PyObject *requires = PyDict_New();
783+ PyObject *recommends = PyDict_New();
784 PyObject *upgrades = PyDict_New();
785 PyObject *conflicts = PyDict_New();
786 PyObject *objmap = self->_objmap;
787 int i, ilen;
788- if (!packages || !provides || !requires || !conflicts)
789+ if (!packages || !provides || !requires || !recommends || !conflicts )
790 return NULL;
791
792 /* for loader in loaders: */
793@@ -2679,6 +2810,30 @@ Cache__reload(CacheObject *self, PyObject *args)
794 } 198 }
795 199
796 /* 200 /*
@@ -821,28 +225,7 @@ index 7541e26..7193185 100644
821 for upg in pkg.upgrades: 225 for upg in pkg.upgrades:
822 upg.packages.append(pkg) 226 upg.packages.append(pkg)
823 if upg not in upgrades: 227 if upg not in upgrades:
824@@ -2747,6 +2902,11 @@ Cache__reload(CacheObject *self, PyObject *args) 228@@ -3097,6 +3224,47 @@ Cache_linkDeps(CacheObject *self, PyObject *args)
825 self->_requires = PyDict_Keys(requires);
826 Py_DECREF(requires);
827
828+ /* self._recommends[:] = recommends.keys() */
829+ Py_DECREF(self->_recommends);
830+ self->_recommends = PyDict_Keys(recommends);
831+ Py_DECREF(recommends);
832+
833 /* self._upgrades[:] = upgrades.keys() */
834 Py_DECREF(self->_upgrades);
835 self->_upgrades = PyDict_Keys(upgrades);
836@@ -2852,7 +3012,7 @@ PyObject *
837 Cache_linkDeps(CacheObject *self, PyObject *args)
838 {
839 int i, j, len;
840- PyObject *reqnames, *upgnames, *cnfnames;
841+ PyObject *reqnames, *recnames, *upgnames, *cnfnames;
842 PyObject *lst;
843
844 /* reqnames = {} */
845@@ -2896,6 +3056,47 @@ Cache_linkDeps(CacheObject *self, PyObject *args)
846 Py_DECREF(seq); 229 Py_DECREF(seq);
847 } 230 }
848 231
@@ -890,7 +273,7 @@ index 7541e26..7193185 100644
890 /* upgnames = {} */ 273 /* upgnames = {} */
891 upgnames = PyDict_New(); 274 upgnames = PyDict_New();
892 /* for upg in self._upgrades: */ 275 /* for upg in self._upgrades: */
893@@ -3035,6 +3236,56 @@ Cache_linkDeps(CacheObject *self, PyObject *args) 276@@ -3286,6 +3454,56 @@ Cache_linkDeps(CacheObject *self, PyObject *args)
894 } 277 }
895 } 278 }
896 279
@@ -947,107 +330,7 @@ index 7541e26..7193185 100644
947 /* lst = upgnames.get(prv.name) */ 330 /* lst = upgnames.get(prv.name) */
948 lst = PyDict_GetItem(upgnames, prv->name); 331 lst = PyDict_GetItem(upgnames, prv->name);
949 332
950@@ -3139,6 +3390,7 @@ Cache_linkDeps(CacheObject *self, PyObject *args) 333@@ -3821,6 +4094,21 @@ Cache__setstate__(CacheObject *self, PyObject *state)
951 }
952
953 Py_DECREF(reqnames);
954+ Py_DECREF(recnames);
955 Py_DECREF(upgnames);
956 Py_DECREF(cnfnames);
957
958@@ -3215,6 +3467,29 @@ Cache_getRequires(CacheObject *self, PyObject *args)
959 }
960
961 PyObject *
962+Cache_getRecommends(CacheObject *self, PyObject *args)
963+{
964+ const char *name = NULL;
965+ PyObject *lst;
966+ int i, len;
967+ if (!PyArg_ParseTuple(args, "|s", &name))
968+ return NULL;
969+ if (!name) {
970+ Py_INCREF(self->_recommends);
971+ return self->_recommends;
972+ }
973+ lst = PyList_New(0);
974+ len = PyList_GET_SIZE(self->_recommends);
975+ for (i = 0; i != len; i++) {
976+ DependsObject *rec =
977+ (DependsObject*)PyList_GET_ITEM(self->_recommends, i);
978+ if (strcmp(STR(rec->name), name) == 0)
979+ PyList_Append(lst, (PyObject *)rec);
980+ }
981+ return lst;
982+}
983+
984+PyObject *
985 Cache_getUpgrades(CacheObject *self, PyObject *args)
986 {
987 const char *name = NULL;
988@@ -3324,6 +3599,38 @@ Cache_search(CacheObject *self, PyObject *searcher)
989 }
990 Py_DECREF(lst);
991
992+ lst = PyObject_GetAttrString(searcher, "recommends");
993+ if (lst == NULL || !PyList_Check(lst)) {
994+ PyErr_SetString(PyExc_TypeError, "Invalid recommends attribute");
995+ return NULL;
996+ }
997+ for (i = 0; i != PyList_GET_SIZE(lst); i++) {
998+ ProvidesObject *prv = (ProvidesObject *)PyList_GET_ITEM(lst, i);
999+ for (j = 0; j != PyList_GET_SIZE(self->_recommends); j++) {
1000+ PyObject *rec = PyList_GET_ITEM(self->_recommends, j);
1001+ PyObject *names = PyObject_CallMethod(rec, "getMatchNames", NULL);
1002+ PyObject *seq = PySequence_Fast(names, "getMatchNames() returned "
1003+ "non-sequence object");
1004+ if (seq == NULL) return NULL;
1005+ for (k = 0; k != PySequence_Fast_GET_SIZE(seq); k++) {
1006+ if (strcmp(PyString_AS_STRING(PySequence_Fast_GET_ITEM(seq, k)),
1007+ PyString_AS_STRING(prv->name)) == 0) {
1008+ res = PyObject_CallMethod(rec, "matches", "O", prv);
1009+ if (res == NULL)
1010+ return NULL;
1011+ if (PyObject_IsTrue(res))
1012+ CALLMETHOD(searcher, "addResult", "O", rec);
1013+ Py_DECREF(res);
1014+ break;
1015+ }
1016+ }
1017+
1018+ Py_DECREF(names);
1019+ Py_DECREF(seq);
1020+ }
1021+ }
1022+ Py_DECREF(lst);
1023+
1024 lst = PyObject_GetAttrString(searcher, "upgrades");
1025 if (lst == NULL || !PyList_Check(lst)) {
1026 PyErr_SetString(PyExc_TypeError, "Invalid upgrades attribute");
1027@@ -3420,7 +3727,7 @@ Cache__getstate__(CacheObject *self, PyObject *args)
1028 static PyObject *
1029 Cache__setstate__(CacheObject *self, PyObject *state)
1030 {
1031- PyObject *provides, *requires, *upgrades, *conflicts;
1032+ PyObject *provides, *requires, *recommends, *upgrades, *conflicts;
1033 int i, ilen;
1034 int j, jlen;
1035
1036@@ -3452,11 +3759,13 @@ Cache__setstate__(CacheObject *self, PyObject *state)
1037 /*
1038 provides = {}
1039 requires = {}
1040+ recommends = {}
1041 upgrades = {}
1042 conflicts = {}
1043 */
1044 provides = PyDict_New();
1045 requires = PyDict_New();
1046+ recommends = PyDict_New();
1047 upgrades = PyDict_New();
1048 conflicts = PyDict_New();
1049
1050@@ -3497,6 +3806,21 @@ Cache__setstate__(CacheObject *self, PyObject *state)
1051 } 334 }
1052 335
1053 /* 336 /*
@@ -1069,97 +352,11 @@ index 7541e26..7193185 100644
1069 for upg in pkg.upgrades: 352 for upg in pkg.upgrades:
1070 upg.packages.append(pkg) 353 upg.packages.append(pkg)
1071 upgrades[upg] = True 354 upgrades[upg] = True
1072@@ -3525,6 +3849,7 @@ Cache__setstate__(CacheObject *self, PyObject *state)
1073 PyDict_SetItem(conflicts, cnf, Py_True);
1074 }
1075 }
1076+
1077 }
1078
1079 /* self._provides = provides.keys() */
1080@@ -3535,6 +3860,10 @@ Cache__setstate__(CacheObject *self, PyObject *state)
1081 self->_requires = PyDict_Keys(requires);
1082 Py_DECREF(requires);
1083
1084+ /* self._recommends = recommends.keys() */
1085+ self->_recommends = PyDict_Keys(recommends);
1086+ Py_DECREF(recommends);
1087+
1088 /* self._upgrades = upgrades.keys() */
1089 self->_upgrades = PyDict_Keys(upgrades);
1090 Py_DECREF(upgrades);
1091@@ -3562,6 +3891,7 @@ static PyMethodDef Cache_methods[] = {
1092 {"getPackages", (PyCFunction)Cache_getPackages, METH_VARARGS, NULL},
1093 {"getProvides", (PyCFunction)Cache_getProvides, METH_VARARGS, NULL},
1094 {"getRequires", (PyCFunction)Cache_getRequires, METH_VARARGS, NULL},
1095+ {"getRecommends", (PyCFunction)Cache_getRecommends, METH_VARARGS, NULL},
1096 {"getUpgrades", (PyCFunction)Cache_getUpgrades, METH_VARARGS, NULL},
1097 {"getConflicts", (PyCFunction)Cache_getConflicts, METH_VARARGS, NULL},
1098 {"search", (PyCFunction)Cache_search, METH_O, NULL},
1099@@ -3576,6 +3906,7 @@ static PyMemberDef Cache_members[] = {
1100 {"_packages", T_OBJECT, OFF(_packages), RO, 0},
1101 {"_provides", T_OBJECT, OFF(_provides), RO, 0},
1102 {"_requires", T_OBJECT, OFF(_requires), RO, 0},
1103+ {"_recommends", T_OBJECT, OFF(_recommends), RO, 0},
1104 {"_upgrades", T_OBJECT, OFF(_upgrades), RO, 0},
1105 {"_conflicts", T_OBJECT, OFF(_conflicts), RO, 0},
1106 {"_objmap", T_OBJECT, OFF(_objmap), RO, 0},
1107diff --git a/smart/commands/query.py b/smart/commands/query.py 355diff --git a/smart/commands/query.py b/smart/commands/query.py
1108index 808e53a..9265cd9 100644 356index 9265cd9..b6f5697 100644
1109--- a/smart/commands/query.py 357--- a/smart/commands/query.py
1110+++ b/smart/commands/query.py 358+++ b/smart/commands/query.py
1111@@ -107,6 +107,8 @@ def option_parser(**kwargs): 359@@ -750,6 +750,22 @@ class TextOutput(NullOutput):
1112 help=_("show requires for the given packages"))
1113 parser.add_option("--show-prerequires", action="store_true",
1114 help=_("show requires selecting only pre-dependencies"))
1115+ parser.add_option("--show-recommends", action="store_true",
1116+ help=_("show recommends for the given packages"))
1117 parser.add_option("--show-upgrades", action="store_true",
1118 help=_("show upgrades for the given packages"))
1119 parser.add_option("--show-conflicts", action="store_true",
1120@@ -488,6 +490,19 @@ def main(ctrl, opts, reloadchannels=True):
1121 continue
1122 output.showRequiresProvidedBy(pkg, req,
1123 prv, prvpkg)
1124+ if pkg.recommends and (opts.show_recommends):
1125+ pkg.recommends.sort()
1126+ first = True
1127+ for req in pkg.recommends:
1128+ output.showRecommends(pkg, req)
1129+ if opts.show_providedby and req.providedby:
1130+ for prv in req.providedby:
1131+ prv.packages.sort()
1132+ for prvpkg in prv.packages:
1133+ if opts.installed and not prvpkg.installed:
1134+ continue
1135+ output.showRecommendsProvidedBy(pkg, req,
1136+ prv, prvpkg)
1137 if pkg.upgrades and (opts.show_upgrades or whoupgrades):
1138 pkg.upgrades.sort()
1139 first = True
1140@@ -594,6 +609,12 @@ class NullOutput(object):
1141 def showRequiresProvidedBy(self, pkg, req, prv, prvpkg):
1142 pass
1143
1144+ def showRecommends(self, pkg, req):
1145+ pass
1146+
1147+ def showRecommendsProvidedBy(self, pkg, req, prv, prvpkg):
1148+ pass
1149+
1150 def showUpgrades(self, pkg, upg):
1151 pass
1152
1153@@ -619,6 +640,8 @@ class TextOutput(NullOutput):
1154 self._firstconflictedby = True
1155 self._firstrequires = True
1156 self._firstrequiresprovidedby = True
1157+ self._firstrecommends = True
1158+ self._firstrecommendsprovidedby = True
1159 self._firstupgrades = True
1160 self._firstupgradesprovidedby = True
1161 self._firstconflicts = True
1162@@ -711,6 +734,22 @@ class TextOutput(NullOutput):
1163 name = str(prvpkg) 360 name = str(prvpkg)
1164 print " ", "%s (%s)" % (name, prv) 361 print " ", "%s (%s)" % (name, prv)
1165 362
@@ -1182,181 +379,3 @@ index 808e53a..9265cd9 100644
1182 def showUpgrades(self, pkg, upg): 379 def showUpgrades(self, pkg, upg):
1183 if self._firstupgrades: 380 if self._firstupgrades:
1184 self._firstupgrades = False 381 self._firstupgrades = False
1185@@ -797,6 +836,18 @@ class GraphVizOutput(NullOutput):
1186 self._shown[req, prv] = True
1187 print ' "Requires: %s" -> "Provides: %s";' % (req, prv)
1188
1189+ def showRecommends(self, pkg, req):
1190+ if (pkg, req) not in self._shown:
1191+ self._shown[pkg, req] = True
1192+ print ' "%s" -> "Recommends: %s";' % (pkg, req)
1193+
1194+ def showRecommendsProvidedBy(self, pkg, req, prv, prvpkg):
1195+ self.showPackage(prvpkg)
1196+ self.showProvides(prvpkg, prv)
1197+ if (req, prv) not in self._shown:
1198+ self._shown[req, prv] = True
1199+ print ' "Recommends: %s" -> "Provides: %s";' % (req, prv)
1200+
1201 def showUpgrades(self, pkg, upg):
1202 if (pkg, upg) not in self._shown:
1203 self._shown[pkg, upg] = True
1204diff --git a/smart/control.py b/smart/control.py
1205index fd7083a..d44abe7 100644
1206--- a/smart/control.py
1207+++ b/smart/control.py
1208@@ -447,7 +447,7 @@ class Control(object):
1209 queue = marked.keys()
1210 while queue:
1211 pkg = queue.pop(0)
1212- for req in pkg.requires:
1213+ for req in pkg.requires + pkg.recommends:
1214 for prv in req.providedby:
1215 for prvpkg in prv.packages:
1216 if (prvpkg.installed and
1217@@ -794,7 +794,7 @@ class Control(object):
1218 pkglst = []
1219 for pkg in changeset:
1220 n = 0
1221- for req in pkg.requires:
1222+ for req in pkg.requires + pkg.recommends:
1223 for prv in req.providedby:
1224 for prvpkg in prv.packages:
1225 if changeset.get(prvpkg) is INSTALL:
1226diff --git a/smart/searcher.py b/smart/searcher.py
1227index 216f4ce..32eb825 100644
1228--- a/smart/searcher.py
1229+++ b/smart/searcher.py
1230@@ -45,9 +45,9 @@ class Searcher(object):
1231
1232 - provides is matched in Provides.search(), for the same reason.
1233
1234- - requires, upgrades, and conflicts don't have special searching
1235- methods. Instead, their usual match() method is given an instance
1236- of the Provides type.
1237+ - requires, recommends, upgrades, and conflicts don't have special
1238+ searching methods. Instead, their usual match() method is given
1239+ an instance of the Provides type.
1240
1241 - group, path, url, and other information which is found by
1242 PackageInfo, is searched by the Loader.search() method and
1243@@ -62,6 +62,7 @@ class Searcher(object):
1244 self.nameversion = []
1245 self.provides = []
1246 self.requires = []
1247+ self.recommends = []
1248 self.upgrades = []
1249 self.conflicts = []
1250 self.path = []
1251@@ -76,6 +77,7 @@ class Searcher(object):
1252 del self.nameversion[:]
1253 del self.provides[:]
1254 del self.requires[:]
1255+ del self.recommends[:]
1256 del self.upgrades[:]
1257 del self.conflicts[:]
1258 del self.path[:]
1259@@ -122,6 +124,8 @@ class Searcher(object):
1260 self.addProvides(s[9:], cutoff)
1261 elif s.startswith("requires:"):
1262 self.addRequires(s[9:])
1263+ elif s.startswith("recommends:"):
1264+ self.addRecommends(s[11:])
1265 elif s.startswith("upgrades:"):
1266 self.addUpgrades(s[9:])
1267 elif s.startswith("conflicts:"):
1268@@ -151,6 +155,7 @@ class Searcher(object):
1269 return s and (
1270 s.startswith("provides:") or
1271 s.startswith("requires:") or
1272+ s.startswith("recommends:") or
1273 s.startswith("upgrades:") or
1274 s.startswith("conflicts:") or
1275 s.startswith("url:") or
1276@@ -182,6 +187,9 @@ class Searcher(object):
1277 def addRequires(self, s):
1278 self.requires.append(self._buildProvides(s))
1279
1280+ def addRecommends(self, s):
1281+ self.recommends.append(self._buildProvides(s))
1282+
1283 def addUpgrades(self, s):
1284 self.upgrades.append(self._buildProvides(s))
1285
1286diff --git a/smart/transaction.py b/smart/transaction.py
1287index eb320d2..300b9cc 100644
1288--- a/smart/transaction.py
1289+++ b/smart/transaction.py
1290@@ -573,7 +573,7 @@ class Transaction(object):
1291 self._remove(namepkg, changeset, locked, pending, depth)
1292
1293 # Install packages required by this one.
1294- for req in pkg.requires:
1295+ for req in pkg.requires + pkg.recommends:
1296
1297 # Check if someone is already providing it.
1298 prvpkgs = {}
1299@@ -596,8 +596,12 @@ class Transaction(object):
1300
1301 if not prvpkgs:
1302 # No packages provide it at all. Give up.
1303- raise Failed, _("Can't install %s: no package provides %s") % \
1304- (pkg, req)
1305+ if req in pkg.requires:
1306+ raise Failed, _("Can't install %s: no package provides %s") % \
1307+ (pkg, req)
1308+ else:
1309+ # It's only a recommend, skip
1310+ continue
1311
1312 if len(prvpkgs) == 1:
1313 # Don't check locked here. prvpkgs was
1314@@ -1359,7 +1363,7 @@ class ChangeSetSplitter(object):
1315 set = self._changeset
1316
1317 # Check all dependencies needed by this package.
1318- for req in pkg.requires:
1319+ for req in pkg.requires + pkg.recommends:
1320
1321 # Check if any already installed or to be installed
1322 # package will solve the problem.
1323@@ -1424,8 +1428,9 @@ class ChangeSetSplitter(object):
1324
1325 # There are no solutions for the problem.
1326 # Should we really care about it?
1327- if (self._forcerequires or
1328- isinstance(req, PreRequires)):
1329+ if ((self._forcerequires or
1330+ isinstance(req, PreRequires))
1331+ and req in pkg.requires):
1332 raise Error, _("No providers for '%s', "
1333 "required by '%s'") % (req, pkg)
1334
1335@@ -1625,7 +1630,7 @@ def recursiveInternalRequires(pkgmap, pkg, numrel, done=None):
1336 return n
1337
1338 def forwardRequires(pkg, map):
1339- for req in pkg.requires:
1340+ for req in pkg.requires + pkg.recommends:
1341 if req not in map:
1342 map[req] = True
1343 for prv in req.providedby:
1344@@ -1794,6 +1799,15 @@ def checkPackages(cache, checkset, relateset, report=False):
1345 iface.info(_("Unsatisfied dependency: %s requires %s") %
1346 (pkg, req))
1347
1348+ for req in pkg.recommends:
1349+ for prv in req.providedby:
1350+ for prvpkg in prv.packages:
1351+ if prvpkg in relateset:
1352+ break
1353+ else:
1354+ continue
1355+ break
1356+
1357 if not pkg.installed:
1358 continue
1359
1360--
13611.7.9.5
1362