generic-poky/meta/recipes-devtools/python/python-smartpm/smart-recommends.patch
Paul Eggleton 69b9c6bd0c python-smartpm: add support for recommends
Implement support within Smart for handling RRECOMMENDS relationships
between RPM packages as used by OE. This includes support within the
base system for caching and resolving these relationships as well as
specific support in the RPM backend for reading the information from
packages, and reading the "missingok" flag added to createrepo for
rpm-md feeds.

(From OE-Core rev: 35e3bc90ec3bae824804bd176b3128efdb5b4e2b)

Signed-off-by: Paul Eggleton <paul.eggleton@linux.intel.com>
Signed-off-by: Saul Wold <sgw@linux.intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-12-06 12:31:05 +00:00

1363 lines
51 KiB
Diff

Handle recommended packages in core and rpm backends
Identify and store recommended packages in the cache, add a query option
to read them and ignore them if they are not present when installing.
Initial identification code from Mark Hatle <mark.hatle@windriver.com>.
Upstream-Status: Pending
Signed-off-by: Paul Eggleton <paul.eggleton@linux.intel.com>
diff --git a/smart/backends/rpm/base.py b/smart/backends/rpm/base.py
index 0489e11..b9e9cb2 100644
--- a/smart/backends/rpm/base.py
+++ b/smart/backends/rpm/base.py
@@ -198,6 +198,29 @@ class RPMPackage(Package):
break
else:
return False
+ srecs = fk(self.recommends)
+ orecs = fk(other.recommends)
+ if srecs != orecs:
+ for srec in srecs:
+ if srec.name[0] == "/" or srec in orecs:
+ continue
+ for orec in orecs:
+ if (srec.name == orec.name and
+ srec.relation == orec.relation and
+ checkver(srec.version, orec.version)):
+ break
+ else:
+ return False
+ for orec in orecs:
+ if orec.name[0] == "/" or orec in srecs:
+ continue
+ for srec in srecs:
+ if (srec.name == orec.name and
+ srec.relation == orec.relation and
+ checkver(srec.version, orec.version)):
+ break
+ else:
+ return False
return True
def coexists(self, other):
diff --git a/smart/backends/rpm/header.py b/smart/backends/rpm/header.py
index 31786cc..4880f43 100644
--- a/smart/backends/rpm/header.py
+++ b/smart/backends/rpm/header.py
@@ -292,6 +292,7 @@ class RPMHeaderLoader(Loader):
f = [0]
elif type(f) != list:
f = [f]
+ recdict = {}
reqdict = {}
for i in range(len(n)):
ni = n[i]
@@ -308,10 +309,16 @@ class RPMHeaderLoader(Loader):
# RPMSENSE_SCRIPT_PREUN |
# RPMSENSE_SCRIPT_POST |
# RPMSENSE_SCRIPT_POSTUN == 7744
- reqdict[(f[i]&7744 and PreReq or Req,
- intern(ni), r, vi)] = True
+ if (f[i]&rpm.RPMSENSE_MISSINGOK):
+ recdict[(f[i]&7744 and PreReq or Req,
+ intern(ni), r, vi)] = True
+ else:
+ reqdict[(f[i]&7744 and PreReq or Req,
+ intern(ni), r, vi)] = True
+ recargs = collapse_libc_requires(recdict.keys())
reqargs = collapse_libc_requires(reqdict.keys())
else:
+ recargs = None
reqargs = None
n = h[1054] # RPMTAG_CONFLICTNAME
@@ -365,7 +372,7 @@ class RPMHeaderLoader(Loader):
versionarch = "%s@%s" % (distversion, arch)
pkg = self.buildPackage((Pkg, name, versionarch),
- prvargs, reqargs, upgargs, cnfargs)
+ prvargs, reqargs, upgargs, cnfargs, recargs)
pkg.loaders[self] = offset
self._offsets[offset] = pkg
self._groups[pkg] = intern(h[rpm.RPMTAG_GROUP])
@@ -583,8 +590,8 @@ class URPMILoader(RPMHeaderListLoader):
def setErrataFlags(self, flagdict):
self._flagdict = flagdict
- def buildPackage(self, pkgargs, prvargs, reqargs, upgargs, cnfargs):
- pkg = Loader.buildPackage(self, pkgargs, prvargs, reqargs, upgargs, cnfargs)
+ def buildPackage(self, pkgargs, prvargs, reqargs, upgargs, cnfargs, recargs):
+ pkg = Loader.buildPackage(self, pkgargs, prvargs, reqargs, upgargs, cnfargs, recargs)
name = pkgargs[1]
if hasattr(self, '_flagdict') and self._flagdict and name in self._flagdict:
if sysconf.getReadOnly():
diff --git a/smart/backends/rpm/metadata.py b/smart/backends/rpm/metadata.py
index 2c54f39..568fe06 100644
--- a/smart/backends/rpm/metadata.py
+++ b/smart/backends/rpm/metadata.py
@@ -165,6 +165,7 @@ class RPMMetaDataLoader(Loader):
distepoch = None
info = {}
reqdict = {}
+ recdict = {}
prvdict = {}
upgdict = {}
cnfdict = {}
@@ -287,12 +288,16 @@ class RPMMetaDataLoader(Loader):
lasttag = queue[-1].tag
if lasttag == REQUIRES:
- if elem.get("pre") == "1":
- reqdict[(RPMPreRequires,
- ename, erelation, eversion)] = True
+ if elem.get("missingok") == "1":
+ recdict[(RPMRequires,
+ ename, erelation, eversion)] = True
else:
- reqdict[(RPMRequires,
- ename, erelation, eversion)] = True
+ if elem.get("pre") == "1":
+ reqdict[(RPMPreRequires,
+ ename, erelation, eversion)] = True
+ else:
+ reqdict[(RPMRequires,
+ ename, erelation, eversion)] = True
elif lasttag == PROVIDES:
if ename[0] == "/":
@@ -328,6 +333,12 @@ class RPMMetaDataLoader(Loader):
(RPMProvides, x[1], x[3]) in prvdict or
system_provides.match(*x[:3]))]
reqargs = collapse_libc_requires(reqargs)
+
+ recargs = [x for x in recdict
+ if not ((x[2] is None or "=" in x[2]) and
+ (RPMProvides, x[1], x[3]) in prvdict or
+ system_provides.match(*x[:3]))]
+
prvargs = prvdict.keys()
cnfargs = cnfdict.keys()
upgargs = upgdict.keys()
@@ -339,7 +350,7 @@ class RPMMetaDataLoader(Loader):
versionarch = "%s@%s" % (distversion, arch)
pkg = self.buildPackage((RPMPackage, name, versionarch),
- prvargs, reqargs, upgargs, cnfargs)
+ prvargs, reqargs, upgargs, cnfargs, recargs)
pkg.loaders[self] = info
# Store the provided files for future usage.
@@ -362,6 +373,7 @@ class RPMMetaDataLoader(Loader):
distepoch = None
pkgid = None
reqdict.clear()
+ recdict.clear()
prvdict.clear()
upgdict.clear()
cnfdict.clear()
diff --git a/smart/cache.py b/smart/cache.py
index b829825..cec8bb3 100644
--- a/smart/cache.py
+++ b/smart/cache.py
@@ -32,7 +32,8 @@ class Package(object):
self.name = name
self.version = version
self.provides = ()
- self.requires = ()
+ self.requires = []
+ self.recommends = []
self.upgrades = ()
self.conflicts = ()
self.installed = False
@@ -55,7 +56,9 @@ class Package(object):
fk([x for x in self.provides if x.name[0] != "/"]) !=
fk([x for x in other.provides if x.name[0] != "/"]) or
fk([x for x in self.requires if x.name[0] != "/"]) !=
- fk([x for x in other.requires if x.name[0] != "/"])):
+ fk([x for x in other.requires if x.name[0] != "/"]) or
+ fk([x for x in self.recommends if x.name[0] != "/"]) !=
+ fk([x for x in other.recommends if x.name[0] != "/"])):
return False
return True
@@ -110,6 +113,7 @@ class Package(object):
self.version,
self.provides,
self.requires,
+ self.recommends,
self.upgrades,
self.conflicts,
self.installed,
@@ -122,6 +126,7 @@ class Package(object):
self.version,
self.provides,
self.requires,
+ self.recommends,
self.upgrades,
self.conflicts,
self.installed,
@@ -274,6 +279,7 @@ class Provides(object):
self.version = version
self.packages = []
self.requiredby = ()
+ self.recommendedby = ()
self.upgradedby = ()
self.conflictedby = ()
@@ -401,7 +407,7 @@ class Loader(object):
def loadFileProvides(self, fndict):
pass
- def buildPackage(self, pkgargs, prvargs, reqargs, upgargs, cnfargs):
+ def buildPackage(self, pkgargs, prvargs, reqargs, upgargs, cnfargs, recargs = None):
cache = self._cache
pkg = pkgargs[0](*pkgargs[1:])
relpkgs = []
@@ -427,6 +433,17 @@ class Loader(object):
relpkgs.append(req.packages)
pkg.requires.append(req)
+ if recargs:
+ pkg.recommends = []
+ for args in recargs:
+ rec = cache._objmap.get(args)
+ if not rec:
+ rec = args[0](*args[1:])
+ cache._objmap[args] = rec
+ cache._recommends.append(rec)
+ relpkgs.append(rec.packages)
+ pkg.recommends.append(rec)
+
if upgargs:
pkg.upgrades = []
for args in upgargs:
@@ -572,6 +589,7 @@ class Cache(object):
self._packages = []
self._provides = []
self._requires = []
+ self._recommends = []
self._upgrades = []
self._conflicts = []
self._objmap = {}
@@ -581,6 +599,8 @@ class Cache(object):
del prv.packages[:]
if prv.requiredby:
del prv.requiredby[:]
+ if prv.recommendedby:
+ del prv.recommendedby[:]
if prv.upgradedby:
del prv.upgradedby[:]
if prv.conflictedby:
@@ -589,6 +609,10 @@ class Cache(object):
del req.packages[:]
if req.providedby:
del req.providedby[:]
+ for rec in self._recommends:
+ del rec.packages[:]
+ if rec.providedby:
+ del rec.providedby[:]
for upg in self._upgrades:
del upg.packages[:]
if upg.providedby:
@@ -600,6 +624,7 @@ class Cache(object):
del self._packages[:]
del self._provides[:]
del self._requires[:]
+ del self._recommends[:]
del self._upgrades[:]
del self._conflicts[:]
self._objmap.clear()
@@ -621,6 +646,7 @@ class Cache(object):
packages = {}
provides = {}
requires = {}
+ recommends = {}
upgrades = {}
conflicts = {}
objmap = self._objmap
@@ -646,6 +672,11 @@ class Cache(object):
if req not in requires:
objmap[req.getInitArgs()] = req
requires[req] = True
+ for rec in pkg.recommends[:]:
+ rec.packages.append(pkg)
+ if rec not in recommends:
+ objmap[rec.getInitArgs()] = rec
+ recommends[rec] = True
for upg in pkg.upgrades:
upg.packages.append(pkg)
if upg not in upgrades:
@@ -659,6 +690,7 @@ class Cache(object):
self._packages[:] = packages.keys()
self._provides[:] = provides.keys()
self._requires[:] = requires.keys()
+ self._recommends[:] = recommends.keys()
self._upgrades[:] = upgrades.keys()
self._conflicts[:] = conflicts.keys()
@@ -710,6 +742,14 @@ class Cache(object):
lst.append(req)
else:
reqnames[name] = [req]
+ recnames = {}
+ for rec in self._recommends:
+ for name in rec.getMatchNames():
+ lst = recnames.get(name)
+ if lst:
+ lst.append(rec)
+ else:
+ recnames[name] = [rec]
upgnames = {}
for upg in self._upgrades:
for name in upg.getMatchNames():
@@ -739,6 +779,18 @@ class Cache(object):
prv.requiredby.append(req)
else:
prv.requiredby = [req]
+ lst = recnames.get(prv.name)
+ if lst:
+ for rec in lst:
+ if rec.matches(prv):
+ if rec.providedby:
+ rec.providedby.append(prv)
+ else:
+ rec.providedby = [prv]
+ if prv.recommendedby:
+ prv.recommendedby.append(rec)
+ else:
+ prv.recommendedby = [rec]
lst = upgnames.get(prv.name)
if lst:
for upg in lst:
@@ -782,6 +834,12 @@ class Cache(object):
else:
return [x for x in self._requires if x.name == name]
+ def getRecommends(self, name=None):
+ if not name:
+ return self._recommends
+ else:
+ return [x for x in self._recommends if x.name == name]
+
def getUpgrades(self, name=None):
if not name:
return self._upgrades
@@ -807,6 +865,12 @@ class Cache(object):
for req in self._requires:
if prvname in req.getMatchNames() and req.matches(prv):
searcher.addResult(req)
+ if searcher.recommends:
+ for prv in searcher.recommends:
+ prvname = prv.name
+ for req in self._recommends:
+ if prvname in req.getMatchNames() and req.matches(prv):
+ searcher.addResult(req)
if searcher.upgrades:
for prv in searcher.upgrades:
prvname = prv.name
@@ -839,6 +903,7 @@ class Cache(object):
self._packages = state["_packages"]
provides = {}
requires = {}
+ recommends = {}
upgrades = {}
conflicts = {}
for pkg in self._packages:
@@ -848,6 +913,9 @@ class Cache(object):
for req in pkg.requires:
req.packages.append(pkg)
requires[req] = True
+ for rec in pkg.recommends:
+ rec.packages.append(pkg)
+ recommends[rec] = True
for upg in pkg.upgrades:
upg.packages.append(pkg)
upgrades[upg] = True
@@ -856,6 +924,7 @@ class Cache(object):
conflicts[cnf] = True
self._provides = provides.keys()
self._requires = requires.keys()
+ self._recommends = recommends.keys()
self._upgrades = upgrades.keys()
self._conflicts = conflicts.keys()
self._objmap = {}
diff --git a/smart/ccache.c b/smart/ccache.c
index 7541e26..7193185 100644
--- a/smart/ccache.c
+++ b/smart/ccache.c
@@ -82,6 +82,7 @@ typedef struct {
PyObject *version;
PyObject *provides;
PyObject *requires;
+ PyObject *recommends;
PyObject *upgrades;
PyObject *conflicts;
PyObject *installed;
@@ -96,6 +97,7 @@ typedef struct {
PyObject *version;
PyObject *packages;
PyObject *requiredby;
+ PyObject *recommendedby;
PyObject *upgradedby;
PyObject *conflictedby;
} ProvidesObject;
@@ -123,6 +125,7 @@ typedef struct {
PyObject *_packages;
PyObject *_provides;
PyObject *_requires;
+ PyObject *_recommends;
PyObject *_upgrades;
PyObject *_conflicts;
PyObject *_objmap;
@@ -211,7 +214,8 @@ Package_init(PackageObject *self, PyObject *args)
Py_INCREF(self->name);
Py_INCREF(self->version);
self->provides = PyTuple_New(0);
- self->requires = PyTuple_New(0);
+ self->requires = PyList_New(0);
+ self->recommends = PyList_New(0);
self->upgrades = PyTuple_New(0);
self->conflicts = PyTuple_New(0);
Py_INCREF(Py_False);
@@ -228,6 +232,7 @@ Package_traverse(PackageObject *self, visitproc visit, void *arg)
{
Py_VISIT(self->provides);
Py_VISIT(self->requires);
+ Py_VISIT(self->recommends);
Py_VISIT(self->upgrades);
Py_VISIT(self->conflicts);
Py_VISIT(self->loaders);
@@ -239,6 +244,7 @@ Package_clear(PackageObject *self)
{
Py_CLEAR(self->provides);
Py_CLEAR(self->requires);
+ Py_CLEAR(self->recommends);
Py_CLEAR(self->upgrades);
Py_CLEAR(self->conflicts);
Py_CLEAR(self->loaders);
@@ -252,6 +258,7 @@ Package_dealloc(PackageObject *self)
Py_XDECREF(self->version);
Py_XDECREF(self->provides);
Py_XDECREF(self->requires);
+ Py_XDECREF(self->recommends);
Py_XDECREF(self->upgrades);
Py_XDECREF(self->conflicts);
Py_XDECREF(self->installed);
@@ -453,6 +460,46 @@ Package_equals(PackageObject *self, PackageObject *other)
}
}
+ ilen = 0;
+ jlen = 0;
+ for (i = 0; i != PyList_GET_SIZE(self->recommends); i++) {
+ PyObject *item = PyList_GET_ITEM(self->recommends, i);
+ if (!PyObject_IsInstance(item, (PyObject *)&Depends_Type)) {
+ PyErr_SetString(PyExc_TypeError, "Depends instance expected");
+ return NULL;
+ }
+ if (STR(((DependsObject *)item)->name)[0] != '/')
+ ilen += 1;
+ }
+ for (j = 0; j != PyList_GET_SIZE(other->recommends); j++) {
+ PyObject *item = PyList_GET_ITEM(other->recommends, j);
+ if (!PyObject_IsInstance(item, (PyObject *)&Depends_Type)) {
+ PyErr_SetString(PyExc_TypeError, "Depends instance expected");
+ return NULL;
+ }
+ if (STR(((DependsObject *)item)->name)[0] != '/')
+ jlen += 1;
+ }
+ if (ilen != jlen) {
+ ret = Py_False;
+ goto exit;
+ }
+
+ ilen = PyList_GET_SIZE(self->recommends);
+ jlen = PyList_GET_SIZE(other->recommends);
+ for (i = 0; i != ilen; i++) {
+ PyObject *item = PyList_GET_ITEM(self->recommends, i);
+ if (STR(((DependsObject *)item)->name)[0] != '/') {
+ for (j = 0; j != jlen; j++)
+ if (item == PyList_GET_ITEM(other->recommends, j))
+ break;
+ if (j == jlen) {
+ ret = Py_False;
+ goto exit;
+ }
+ }
+ }
+
exit:
Py_INCREF(ret);
return ret;
@@ -606,13 +653,14 @@ Package_getPriority(PackageObject *self, PyObject *args)
static PyObject *
Package__getstate__(PackageObject *self, PyObject *args)
{
- PyObject *state = PyTuple_New(10);
+ PyObject *state = PyTuple_New(11);
if (!state) return NULL;
Py_INCREF(self->name);
Py_INCREF(self->version);
Py_INCREF(self->provides);
Py_INCREF(self->requires);
+ Py_INCREF(self->recommends);
Py_INCREF(self->upgrades);
Py_INCREF(self->conflicts);
Py_INCREF(self->installed);
@@ -620,16 +668,17 @@ Package__getstate__(PackageObject *self, PyObject *args)
Py_INCREF(self->priority);
Py_INCREF(self->loaders);
- PyTuple_SET_ITEM(state, 0, self->name);
- PyTuple_SET_ITEM(state, 1, self->version);
- PyTuple_SET_ITEM(state, 2, self->provides);
- PyTuple_SET_ITEM(state, 3, self->requires);
- PyTuple_SET_ITEM(state, 4, self->upgrades);
- PyTuple_SET_ITEM(state, 5, self->conflicts);
- PyTuple_SET_ITEM(state, 6, self->installed);
- PyTuple_SET_ITEM(state, 7, self->essential);
- PyTuple_SET_ITEM(state, 8, self->priority);
- PyTuple_SET_ITEM(state, 9, self->loaders);
+ PyTuple_SET_ITEM(state, 0, self->name);
+ PyTuple_SET_ITEM(state, 1, self->version);
+ PyTuple_SET_ITEM(state, 2, self->provides);
+ PyTuple_SET_ITEM(state, 3, self->requires);
+ PyTuple_SET_ITEM(state, 4, self->recommends);
+ PyTuple_SET_ITEM(state, 5, self->upgrades);
+ PyTuple_SET_ITEM(state, 6, self->conflicts);
+ PyTuple_SET_ITEM(state, 7, self->installed);
+ PyTuple_SET_ITEM(state, 8, self->essential);
+ PyTuple_SET_ITEM(state, 9, self->priority);
+ PyTuple_SET_ITEM(state, 10, self->loaders);
return state;
}
@@ -637,7 +686,7 @@ Package__getstate__(PackageObject *self, PyObject *args)
static PyObject *
Package__setstate__(PackageObject *self, PyObject *state)
{
- if (!PyTuple_Check(state) || PyTuple_GET_SIZE(state) != 10) {
+ if (!PyTuple_Check(state) || PyTuple_GET_SIZE(state) != 11) {
PyErr_SetString(StateVersionError, "");
return NULL;
}
@@ -645,18 +694,20 @@ Package__setstate__(PackageObject *self, PyObject *state)
self->version = PyTuple_GET_ITEM(state, 1);
self->provides = PyTuple_GET_ITEM(state, 2);
self->requires = PyTuple_GET_ITEM(state, 3);
- self->upgrades = PyTuple_GET_ITEM(state, 4);
- self->conflicts = PyTuple_GET_ITEM(state, 5);
- self->installed = PyTuple_GET_ITEM(state, 6);
- self->essential = PyTuple_GET_ITEM(state, 7);
- self->priority = PyTuple_GET_ITEM(state, 8);
- self->loaders = PyTuple_GET_ITEM(state, 9);
+ self->recommends = PyTuple_GET_ITEM(state, 4);
+ self->upgrades = PyTuple_GET_ITEM(state, 5);
+ self->conflicts = PyTuple_GET_ITEM(state, 6);
+ self->installed = PyTuple_GET_ITEM(state, 7);
+ self->essential = PyTuple_GET_ITEM(state, 8);
+ self->priority = PyTuple_GET_ITEM(state, 9);
+ self->loaders = PyTuple_GET_ITEM(state, 10);
Py_INCREF(self->name);
Py_INCREF(self->version);
Py_INCREF(self->provides);
Py_INCREF(self->requires);
+ Py_INCREF(self->recommends);
Py_INCREF(self->upgrades);
Py_INCREF(self->conflicts);
Py_INCREF(self->installed);
@@ -686,6 +737,7 @@ static PyMemberDef Package_members[] = {
{"version", T_OBJECT, OFF(version), 0, 0},
{"provides", T_OBJECT, OFF(provides), 0, 0},
{"requires", T_OBJECT, OFF(requires), 0, 0},
+ {"recommends", T_OBJECT, OFF(recommends), 0, 0},
{"upgrades", T_OBJECT, OFF(upgrades), 0, 0},
{"conflicts", T_OBJECT, OFF(conflicts), 0, 0},
{"installed", T_OBJECT, OFF(installed), 0, 0},
@@ -750,6 +802,7 @@ Provides_init(ProvidesObject *self, PyObject *args)
Py_INCREF(self->version);
self->packages = PyList_New(0);
self->requiredby = PyTuple_New(0);
+ self->recommendedby = PyTuple_New(0);
self->upgradedby = PyTuple_New(0);
self->conflictedby = PyTuple_New(0);
return 0;
@@ -760,6 +813,7 @@ Provides_traverse(ProvidesObject *self, visitproc visit, void *arg)
{
Py_VISIT(self->packages);
Py_VISIT(self->requiredby);
+ Py_VISIT(self->recommendedby);
Py_VISIT(self->upgradedby);
Py_VISIT(self->conflictedby);
return 0;
@@ -770,6 +824,7 @@ Provides_clear(ProvidesObject *self)
{
Py_CLEAR(self->packages);
Py_CLEAR(self->requiredby);
+ Py_CLEAR(self->recommendedby);
Py_CLEAR(self->upgradedby);
Py_CLEAR(self->conflictedby);
return 0;
@@ -782,6 +837,7 @@ Provides_dealloc(ProvidesObject *self)
Py_XDECREF(self->version);
Py_XDECREF(self->packages);
Py_XDECREF(self->requiredby);
+ Py_XDECREF(self->recommendedby);
Py_XDECREF(self->upgradedby);
Py_XDECREF(self->conflictedby);
self->ob_type->tp_free((PyObject *)self);
@@ -960,6 +1016,7 @@ static PyMemberDef Provides_members[] = {
{"version", T_OBJECT, OFF(version), 0, 0},
{"packages", T_OBJECT, OFF(packages), 0, 0},
{"requiredby", T_OBJECT, OFF(requiredby), 0, 0},
+ {"recommendedby", T_OBJECT, OFF(recommendedby), 0, 0},
{"upgradedby", T_OBJECT, OFF(upgradedby), 0, 0},
{"conflictedby", T_OBJECT, OFF(conflictedby), 0, 0},
{NULL}
@@ -1555,6 +1612,7 @@ Loader_buildPackage(LoaderObject *self, PyObject *args)
PyObject *reqargs;
PyObject *upgargs;
PyObject *cnfargs;
+ PyObject *recargs = NULL;
PyObject *callargs;
PyObject *pkg;
@@ -1574,9 +1632,10 @@ Loader_buildPackage(LoaderObject *self, PyObject *args)
cache = (CacheObject *)self->_cache;
- if (!PyArg_ParseTuple(args, "O!O&O&O&O&", &PyTuple_Type, &pkgargs,
+ if (!PyArg_ParseTuple(args, "O!O&O&O&O&|O&", &PyTuple_Type, &pkgargs,
mylist, &prvargs, mylist, &reqargs,
- mylist, &upgargs, mylist, &cnfargs))
+ mylist, &upgargs, mylist, &cnfargs,
+ mylist, &recargs))
return NULL;
if (PyTuple_GET_SIZE(pkgargs) < 2) {
@@ -1701,6 +1760,59 @@ Loader_buildPackage(LoaderObject *self, PyObject *args)
}
}
+ /* if recargs: */
+ if (recargs) {
+ int i = 0;
+ int len = PyList_GET_SIZE(recargs);
+ /* pkg.recommends = [] */
+ Py_DECREF(pkgobj->recommends);
+ pkgobj->recommends = PyList_New(len);
+ /* for args in recargs: */
+ for (; i != len; i++) {
+ PyObject *args = PyList_GET_ITEM(recargs, i);
+ DependsObject *recobj;
+ PyObject *rec;
+
+ if (!PyTuple_Check(args)) {
+ PyErr_SetString(PyExc_TypeError,
+ "Item in recargs is not a tuple");
+ return NULL;
+ }
+
+ /* rec = cache._objmap.get(args) */
+ rec = PyDict_GetItem(cache->_objmap, args);
+ recobj = (DependsObject *)rec;
+
+ /* if not rec: */
+ if (!rec) {
+ if (!PyTuple_Check(args) || PyTuple_GET_SIZE(args) < 2) {
+ PyErr_SetString(PyExc_ValueError, "Invalid recargs tuple");
+ return NULL;
+ }
+ /* rec = args[0](*args[1:]) */
+ callargs = PyTuple_GetSlice(args, 1, PyTuple_GET_SIZE(args));
+ rec = PyObject_CallObject(PyTuple_GET_ITEM(args, 0), callargs);
+ Py_DECREF(callargs);
+ if (!rec) return NULL;
+ recobj = (DependsObject *)rec;
+
+ /* cache._objmap[args] = rec */
+ PyDict_SetItem(cache->_objmap, args, rec);
+ Py_DECREF(rec);
+
+ /* cache._recommends.append(rec) */
+ PyList_Append(cache->_recommends, rec);
+ }
+
+ /* relpkgs.append(rec.packages) */
+ PyList_Append(relpkgs, recobj->packages);
+
+ /* pkg.recommends.append(rec) */
+ Py_INCREF(rec);
+ PyList_SET_ITEM(pkgobj->recommends, i, rec);
+ }
+ }
+
/* if upgargs: */
if (upgargs) {
int i = 0;
@@ -2391,6 +2503,7 @@ Cache_init(CacheObject *self, PyObject *args)
self->_packages = PyList_New(0);
self->_provides = PyList_New(0);
self->_requires = PyList_New(0);
+ self->_recommends = PyList_New(0);
self->_upgrades = PyList_New(0);
self->_conflicts = PyList_New(0);
self->_objmap = PyDict_New();
@@ -2404,6 +2517,7 @@ Cache_traverse(CacheObject *self, visitproc visit, void *arg)
Py_VISIT(self->_packages);
Py_VISIT(self->_provides);
Py_VISIT(self->_requires);
+ Py_VISIT(self->_recommends);
Py_VISIT(self->_upgrades);
Py_VISIT(self->_conflicts);
Py_VISIT(self->_objmap);
@@ -2417,6 +2531,7 @@ Cache_clear(CacheObject *self)
Py_CLEAR(self->_packages);
Py_CLEAR(self->_provides);
Py_CLEAR(self->_requires);
+ Py_CLEAR(self->_recommends);
Py_CLEAR(self->_upgrades);
Py_CLEAR(self->_conflicts);
Py_CLEAR(self->_objmap);
@@ -2430,6 +2545,7 @@ Cache_dealloc(CacheObject *self)
Py_XDECREF(self->_packages);
Py_XDECREF(self->_provides);
Py_XDECREF(self->_requires);
+ Py_XDECREF(self->_recommends);
Py_XDECREF(self->_upgrades);
Py_XDECREF(self->_conflicts);
Py_XDECREF(self->_objmap);
@@ -2449,6 +2565,8 @@ Cache_reset(CacheObject *self, PyObject *args)
LIST_CLEAR(prvobj->packages);
if (PyList_Check(prvobj->requiredby))
LIST_CLEAR(prvobj->requiredby);
+ if (PyList_Check(prvobj->recommendedby))
+ LIST_CLEAR(prvobj->recommendedby);
if (PyList_Check(prvobj->upgradedby))
LIST_CLEAR(prvobj->upgradedby);
if (PyList_Check(prvobj->conflictedby))
@@ -2464,6 +2582,16 @@ Cache_reset(CacheObject *self, PyObject *args)
if (PyList_Check(reqobj->providedby))
LIST_CLEAR(reqobj->providedby);
}
+ len = PyList_GET_SIZE(self->_recommends);
+ for (i = 0; i != len; i++) {
+ DependsObject *reqobj;
+ PyObject *req;
+ req = PyList_GET_ITEM(self->_recommends, i);
+ reqobj = (DependsObject *)req;
+ LIST_CLEAR(reqobj->packages);
+ if (PyList_Check(reqobj->providedby))
+ LIST_CLEAR(reqobj->providedby);
+ }
len = PyList_GET_SIZE(self->_upgrades);
for (i = 0; i != len; i++) {
DependsObject *upgobj;
@@ -2487,6 +2615,7 @@ Cache_reset(CacheObject *self, PyObject *args)
LIST_CLEAR(self->_packages);
LIST_CLEAR(self->_provides);
LIST_CLEAR(self->_requires);
+ LIST_CLEAR(self->_recommends);
LIST_CLEAR(self->_upgrades);
LIST_CLEAR(self->_conflicts);
PyDict_Clear(self->_objmap);
@@ -2534,6 +2663,7 @@ Cache__reload(CacheObject *self, PyObject *args)
packages = {}
provides = {}
requires = {}
+ recommends = {}
upgrades = {}
conflicts = {}
objmap = self._objmap
@@ -2541,11 +2671,12 @@ Cache__reload(CacheObject *self, PyObject *args)
PyObject *packages = PyDict_New();
PyObject *provides = PyDict_New();
PyObject *requires = PyDict_New();
+ PyObject *recommends = PyDict_New();
PyObject *upgrades = PyDict_New();
PyObject *conflicts = PyDict_New();
PyObject *objmap = self->_objmap;
int i, ilen;
- if (!packages || !provides || !requires || !conflicts)
+ if (!packages || !provides || !requires || !recommends || !conflicts )
return NULL;
/* for loader in loaders: */
@@ -2679,6 +2810,30 @@ Cache__reload(CacheObject *self, PyObject *args)
}
/*
+ for rec in pkg.recommends:
+ rec.packages.append(pkg)
+ if rec not in recommends:
+ recommends[rec] = True
+ objmap[rec.getInitArgs()] = rec
+ */
+ if (PyList_Check(pkg->recommends)) {
+ klen = PyList_GET_SIZE(pkg->recommends);
+ for (k = 0; k != klen; k++) {
+ PyObject *rec = PyList_GET_ITEM(pkg->recommends, k);
+ PyList_Append(((DependsObject *)rec)->packages,
+ (PyObject *)pkg);
+ if (!PyDict_GetItem(recommends, rec)) {
+ PyDict_SetItem(recommends, rec, Py_True);
+ args = PyObject_CallMethod(rec, "getInitArgs",
+ NULL);
+ if (!args) return NULL;
+ PyDict_SetItem(objmap, args, rec);
+ Py_DECREF(args);
+ }
+ }
+ }
+
+ /*
for upg in pkg.upgrades:
upg.packages.append(pkg)
if upg not in upgrades:
@@ -2747,6 +2902,11 @@ Cache__reload(CacheObject *self, PyObject *args)
self->_requires = PyDict_Keys(requires);
Py_DECREF(requires);
+ /* self._recommends[:] = recommends.keys() */
+ Py_DECREF(self->_recommends);
+ self->_recommends = PyDict_Keys(recommends);
+ Py_DECREF(recommends);
+
/* self._upgrades[:] = upgrades.keys() */
Py_DECREF(self->_upgrades);
self->_upgrades = PyDict_Keys(upgrades);
@@ -2852,7 +3012,7 @@ PyObject *
Cache_linkDeps(CacheObject *self, PyObject *args)
{
int i, j, len;
- PyObject *reqnames, *upgnames, *cnfnames;
+ PyObject *reqnames, *recnames, *upgnames, *cnfnames;
PyObject *lst;
/* reqnames = {} */
@@ -2896,6 +3056,47 @@ Cache_linkDeps(CacheObject *self, PyObject *args)
Py_DECREF(seq);
}
+ /* recnames = {} */
+ recnames = PyDict_New();
+ /* for rec in self._recommends: */
+ len = PyList_GET_SIZE(self->_recommends);
+ for (i = 0; i != len; i++) {
+ PyObject *rec = PyList_GET_ITEM(self->_recommends, i);
+
+ /* for name in rec.getMatchNames(): */
+ PyObject *names = PyObject_CallMethod(rec, "getMatchNames", NULL);
+ PyObject *seq = PySequence_Fast(names, "getMatchNames() returned "
+ "non-sequence object");
+ int nameslen;
+ if (!seq) return NULL;
+ nameslen = PySequence_Fast_GET_SIZE(seq);
+ for (j = 0; j != nameslen; j++) {
+ PyObject *name = PySequence_Fast_GET_ITEM(seq, j);
+
+ /* lst = recnames.get(name) */
+ lst = PyDict_GetItem(recnames, name);
+
+ /*
+ if lst:
+ lst.append(rec)
+ else:
+ recnames[name] = [rec]
+ */
+ if (lst) {
+ PyList_Append(lst, rec);
+ } else {
+ lst = PyList_New(1);
+ Py_INCREF(rec);
+ PyList_SET_ITEM(lst, 0, rec);
+ PyDict_SetItem(recnames, name, lst);
+ Py_DECREF(lst);
+ }
+ }
+
+ Py_DECREF(names);
+ Py_DECREF(seq);
+ }
+
/* upgnames = {} */
upgnames = PyDict_New();
/* for upg in self._upgrades: */
@@ -3035,6 +3236,56 @@ Cache_linkDeps(CacheObject *self, PyObject *args)
}
}
+ /* lst = recnames.get(prv.name) */
+ lst = PyDict_GetItem(recnames, prv->name);
+
+ /* if lst: */
+ if (lst) {
+ /* for rec in lst: */
+ int reclen = PyList_GET_SIZE(lst);
+ for (j = 0; j != reclen; j++) {
+ DependsObject *rec = (DependsObject *)PyList_GET_ITEM(lst, j);
+ /* if rec.matches(prv): */
+ PyObject *ret = PyObject_CallMethod((PyObject *)rec, "matches",
+ "O", (PyObject *)prv);
+ if (!ret) return NULL;
+ if (PyObject_IsTrue(ret)) {
+ /*
+ if rec.providedby:
+ rec.providedby.append(prv)
+ else:
+ rec.providedby = [prv]
+ */
+ if (PyList_Check(rec->providedby)) {
+ PyList_Append(rec->providedby, (PyObject *)prv);
+ } else {
+ PyObject *_lst = PyList_New(1);
+ Py_INCREF(prv);
+ PyList_SET_ITEM(_lst, 0, (PyObject *)prv);
+ Py_DECREF(rec->providedby);
+ rec->providedby = _lst;
+ }
+
+ /*
+ if prv.recommendedby:
+ prv.recommendedby.append(prv)
+ else:
+ prv.recommendedby = [prv]
+ */
+ if (PyList_Check(prv->recommendedby)) {
+ PyList_Append(prv->recommendedby, (PyObject *)rec);
+ } else {
+ PyObject *_lst = PyList_New(1);
+ Py_INCREF(rec);
+ PyList_SET_ITEM(_lst, 0, (PyObject *)rec);
+ Py_DECREF(prv->recommendedby);
+ prv->recommendedby = _lst;
+ }
+ }
+ Py_DECREF(ret);
+ }
+ }
+
/* lst = upgnames.get(prv.name) */
lst = PyDict_GetItem(upgnames, prv->name);
@@ -3139,6 +3390,7 @@ Cache_linkDeps(CacheObject *self, PyObject *args)
}
Py_DECREF(reqnames);
+ Py_DECREF(recnames);
Py_DECREF(upgnames);
Py_DECREF(cnfnames);
@@ -3215,6 +3467,29 @@ Cache_getRequires(CacheObject *self, PyObject *args)
}
PyObject *
+Cache_getRecommends(CacheObject *self, PyObject *args)
+{
+ const char *name = NULL;
+ PyObject *lst;
+ int i, len;
+ if (!PyArg_ParseTuple(args, "|s", &name))
+ return NULL;
+ if (!name) {
+ Py_INCREF(self->_recommends);
+ return self->_recommends;
+ }
+ lst = PyList_New(0);
+ len = PyList_GET_SIZE(self->_recommends);
+ for (i = 0; i != len; i++) {
+ DependsObject *rec =
+ (DependsObject*)PyList_GET_ITEM(self->_recommends, i);
+ if (strcmp(STR(rec->name), name) == 0)
+ PyList_Append(lst, (PyObject *)rec);
+ }
+ return lst;
+}
+
+PyObject *
Cache_getUpgrades(CacheObject *self, PyObject *args)
{
const char *name = NULL;
@@ -3324,6 +3599,38 @@ Cache_search(CacheObject *self, PyObject *searcher)
}
Py_DECREF(lst);
+ lst = PyObject_GetAttrString(searcher, "recommends");
+ if (lst == NULL || !PyList_Check(lst)) {
+ PyErr_SetString(PyExc_TypeError, "Invalid recommends attribute");
+ return NULL;
+ }
+ for (i = 0; i != PyList_GET_SIZE(lst); i++) {
+ ProvidesObject *prv = (ProvidesObject *)PyList_GET_ITEM(lst, i);
+ for (j = 0; j != PyList_GET_SIZE(self->_recommends); j++) {
+ PyObject *rec = PyList_GET_ITEM(self->_recommends, j);
+ PyObject *names = PyObject_CallMethod(rec, "getMatchNames", NULL);
+ PyObject *seq = PySequence_Fast(names, "getMatchNames() returned "
+ "non-sequence object");
+ if (seq == NULL) return NULL;
+ for (k = 0; k != PySequence_Fast_GET_SIZE(seq); k++) {
+ if (strcmp(PyString_AS_STRING(PySequence_Fast_GET_ITEM(seq, k)),
+ PyString_AS_STRING(prv->name)) == 0) {
+ res = PyObject_CallMethod(rec, "matches", "O", prv);
+ if (res == NULL)
+ return NULL;
+ if (PyObject_IsTrue(res))
+ CALLMETHOD(searcher, "addResult", "O", rec);
+ Py_DECREF(res);
+ break;
+ }
+ }
+
+ Py_DECREF(names);
+ Py_DECREF(seq);
+ }
+ }
+ Py_DECREF(lst);
+
lst = PyObject_GetAttrString(searcher, "upgrades");
if (lst == NULL || !PyList_Check(lst)) {
PyErr_SetString(PyExc_TypeError, "Invalid upgrades attribute");
@@ -3420,7 +3727,7 @@ Cache__getstate__(CacheObject *self, PyObject *args)
static PyObject *
Cache__setstate__(CacheObject *self, PyObject *state)
{
- PyObject *provides, *requires, *upgrades, *conflicts;
+ PyObject *provides, *requires, *recommends, *upgrades, *conflicts;
int i, ilen;
int j, jlen;
@@ -3452,11 +3759,13 @@ Cache__setstate__(CacheObject *self, PyObject *state)
/*
provides = {}
requires = {}
+ recommends = {}
upgrades = {}
conflicts = {}
*/
provides = PyDict_New();
requires = PyDict_New();
+ recommends = PyDict_New();
upgrades = PyDict_New();
conflicts = PyDict_New();
@@ -3497,6 +3806,21 @@ Cache__setstate__(CacheObject *self, PyObject *state)
}
/*
+ for rec in pkg.recommends:
+ rec.packages.append(pkg)
+ recommends[rec] = True
+ */
+ if (PyList_Check(pkgobj->recommends)) {
+ jlen = PyList_GET_SIZE(pkgobj->recommends);
+ for (j = 0; j != jlen; j++) {
+ PyObject *rec = PyList_GET_ITEM(pkgobj->recommends, j);
+ DependsObject *recobj = (DependsObject *)rec;
+ PyList_Append(recobj->packages, pkg);
+ PyDict_SetItem(recommends, rec, Py_True);
+ }
+ }
+
+ /*
for upg in pkg.upgrades:
upg.packages.append(pkg)
upgrades[upg] = True
@@ -3525,6 +3849,7 @@ Cache__setstate__(CacheObject *self, PyObject *state)
PyDict_SetItem(conflicts, cnf, Py_True);
}
}
+
}
/* self._provides = provides.keys() */
@@ -3535,6 +3860,10 @@ Cache__setstate__(CacheObject *self, PyObject *state)
self->_requires = PyDict_Keys(requires);
Py_DECREF(requires);
+ /* self._recommends = recommends.keys() */
+ self->_recommends = PyDict_Keys(recommends);
+ Py_DECREF(recommends);
+
/* self._upgrades = upgrades.keys() */
self->_upgrades = PyDict_Keys(upgrades);
Py_DECREF(upgrades);
@@ -3562,6 +3891,7 @@ static PyMethodDef Cache_methods[] = {
{"getPackages", (PyCFunction)Cache_getPackages, METH_VARARGS, NULL},
{"getProvides", (PyCFunction)Cache_getProvides, METH_VARARGS, NULL},
{"getRequires", (PyCFunction)Cache_getRequires, METH_VARARGS, NULL},
+ {"getRecommends", (PyCFunction)Cache_getRecommends, METH_VARARGS, NULL},
{"getUpgrades", (PyCFunction)Cache_getUpgrades, METH_VARARGS, NULL},
{"getConflicts", (PyCFunction)Cache_getConflicts, METH_VARARGS, NULL},
{"search", (PyCFunction)Cache_search, METH_O, NULL},
@@ -3576,6 +3906,7 @@ static PyMemberDef Cache_members[] = {
{"_packages", T_OBJECT, OFF(_packages), RO, 0},
{"_provides", T_OBJECT, OFF(_provides), RO, 0},
{"_requires", T_OBJECT, OFF(_requires), RO, 0},
+ {"_recommends", T_OBJECT, OFF(_recommends), RO, 0},
{"_upgrades", T_OBJECT, OFF(_upgrades), RO, 0},
{"_conflicts", T_OBJECT, OFF(_conflicts), RO, 0},
{"_objmap", T_OBJECT, OFF(_objmap), RO, 0},
diff --git a/smart/commands/query.py b/smart/commands/query.py
index 808e53a..9265cd9 100644
--- a/smart/commands/query.py
+++ b/smart/commands/query.py
@@ -107,6 +107,8 @@ def option_parser(**kwargs):
help=_("show requires for the given packages"))
parser.add_option("--show-prerequires", action="store_true",
help=_("show requires selecting only pre-dependencies"))
+ parser.add_option("--show-recommends", action="store_true",
+ help=_("show recommends for the given packages"))
parser.add_option("--show-upgrades", action="store_true",
help=_("show upgrades for the given packages"))
parser.add_option("--show-conflicts", action="store_true",
@@ -488,6 +490,19 @@ def main(ctrl, opts, reloadchannels=True):
continue
output.showRequiresProvidedBy(pkg, req,
prv, prvpkg)
+ if pkg.recommends and (opts.show_recommends):
+ pkg.recommends.sort()
+ first = True
+ for req in pkg.recommends:
+ output.showRecommends(pkg, req)
+ if opts.show_providedby and req.providedby:
+ for prv in req.providedby:
+ prv.packages.sort()
+ for prvpkg in prv.packages:
+ if opts.installed and not prvpkg.installed:
+ continue
+ output.showRecommendsProvidedBy(pkg, req,
+ prv, prvpkg)
if pkg.upgrades and (opts.show_upgrades or whoupgrades):
pkg.upgrades.sort()
first = True
@@ -594,6 +609,12 @@ class NullOutput(object):
def showRequiresProvidedBy(self, pkg, req, prv, prvpkg):
pass
+ def showRecommends(self, pkg, req):
+ pass
+
+ def showRecommendsProvidedBy(self, pkg, req, prv, prvpkg):
+ pass
+
def showUpgrades(self, pkg, upg):
pass
@@ -619,6 +640,8 @@ class TextOutput(NullOutput):
self._firstconflictedby = True
self._firstrequires = True
self._firstrequiresprovidedby = True
+ self._firstrecommends = True
+ self._firstrecommendsprovidedby = True
self._firstupgrades = True
self._firstupgradesprovidedby = True
self._firstconflicts = True
@@ -711,6 +734,22 @@ class TextOutput(NullOutput):
name = str(prvpkg)
print " ", "%s (%s)" % (name, prv)
+ def showRecommends(self, pkg, rec):
+ if self._firstrecommends:
+ self._firstrecommends = False
+ print " ", _("Recommends:")
+ print " ", rec
+
+ def showRecommendsProvidedBy(self, pkg, req, prv, prvpkg):
+ if self._firstrecommendsprovidedby:
+ self._firstrecommendsprovidedby = False
+ print " ", _("Provided By:")
+ if self.opts.hide_version:
+ name = prvpkg.name
+ else:
+ name = str(prvpkg)
+ print " ", "%s (%s)" % (name, prv)
+
def showUpgrades(self, pkg, upg):
if self._firstupgrades:
self._firstupgrades = False
@@ -797,6 +836,18 @@ class GraphVizOutput(NullOutput):
self._shown[req, prv] = True
print ' "Requires: %s" -> "Provides: %s";' % (req, prv)
+ def showRecommends(self, pkg, req):
+ if (pkg, req) not in self._shown:
+ self._shown[pkg, req] = True
+ print ' "%s" -> "Recommends: %s";' % (pkg, req)
+
+ def showRecommendsProvidedBy(self, pkg, req, prv, prvpkg):
+ self.showPackage(prvpkg)
+ self.showProvides(prvpkg, prv)
+ if (req, prv) not in self._shown:
+ self._shown[req, prv] = True
+ print ' "Recommends: %s" -> "Provides: %s";' % (req, prv)
+
def showUpgrades(self, pkg, upg):
if (pkg, upg) not in self._shown:
self._shown[pkg, upg] = True
diff --git a/smart/control.py b/smart/control.py
index fd7083a..d44abe7 100644
--- a/smart/control.py
+++ b/smart/control.py
@@ -447,7 +447,7 @@ class Control(object):
queue = marked.keys()
while queue:
pkg = queue.pop(0)
- for req in pkg.requires:
+ for req in pkg.requires + pkg.recommends:
for prv in req.providedby:
for prvpkg in prv.packages:
if (prvpkg.installed and
@@ -794,7 +794,7 @@ class Control(object):
pkglst = []
for pkg in changeset:
n = 0
- for req in pkg.requires:
+ for req in pkg.requires + pkg.recommends:
for prv in req.providedby:
for prvpkg in prv.packages:
if changeset.get(prvpkg) is INSTALL:
diff --git a/smart/searcher.py b/smart/searcher.py
index 216f4ce..32eb825 100644
--- a/smart/searcher.py
+++ b/smart/searcher.py
@@ -45,9 +45,9 @@ class Searcher(object):
- provides is matched in Provides.search(), for the same reason.
- - requires, upgrades, and conflicts don't have special searching
- methods. Instead, their usual match() method is given an instance
- of the Provides type.
+ - requires, recommends, upgrades, and conflicts don't have special
+ searching methods. Instead, their usual match() method is given
+ an instance of the Provides type.
- group, path, url, and other information which is found by
PackageInfo, is searched by the Loader.search() method and
@@ -62,6 +62,7 @@ class Searcher(object):
self.nameversion = []
self.provides = []
self.requires = []
+ self.recommends = []
self.upgrades = []
self.conflicts = []
self.path = []
@@ -76,6 +77,7 @@ class Searcher(object):
del self.nameversion[:]
del self.provides[:]
del self.requires[:]
+ del self.recommends[:]
del self.upgrades[:]
del self.conflicts[:]
del self.path[:]
@@ -122,6 +124,8 @@ class Searcher(object):
self.addProvides(s[9:], cutoff)
elif s.startswith("requires:"):
self.addRequires(s[9:])
+ elif s.startswith("recommends:"):
+ self.addRecommends(s[11:])
elif s.startswith("upgrades:"):
self.addUpgrades(s[9:])
elif s.startswith("conflicts:"):
@@ -151,6 +155,7 @@ class Searcher(object):
return s and (
s.startswith("provides:") or
s.startswith("requires:") or
+ s.startswith("recommends:") or
s.startswith("upgrades:") or
s.startswith("conflicts:") or
s.startswith("url:") or
@@ -182,6 +187,9 @@ class Searcher(object):
def addRequires(self, s):
self.requires.append(self._buildProvides(s))
+ def addRecommends(self, s):
+ self.recommends.append(self._buildProvides(s))
+
def addUpgrades(self, s):
self.upgrades.append(self._buildProvides(s))
diff --git a/smart/transaction.py b/smart/transaction.py
index eb320d2..300b9cc 100644
--- a/smart/transaction.py
+++ b/smart/transaction.py
@@ -573,7 +573,7 @@ class Transaction(object):
self._remove(namepkg, changeset, locked, pending, depth)
# Install packages required by this one.
- for req in pkg.requires:
+ for req in pkg.requires + pkg.recommends:
# Check if someone is already providing it.
prvpkgs = {}
@@ -596,8 +596,12 @@ class Transaction(object):
if not prvpkgs:
# No packages provide it at all. Give up.
- raise Failed, _("Can't install %s: no package provides %s") % \
- (pkg, req)
+ if req in pkg.requires:
+ raise Failed, _("Can't install %s: no package provides %s") % \
+ (pkg, req)
+ else:
+ # It's only a recommend, skip
+ continue
if len(prvpkgs) == 1:
# Don't check locked here. prvpkgs was
@@ -1359,7 +1363,7 @@ class ChangeSetSplitter(object):
set = self._changeset
# Check all dependencies needed by this package.
- for req in pkg.requires:
+ for req in pkg.requires + pkg.recommends:
# Check if any already installed or to be installed
# package will solve the problem.
@@ -1424,8 +1428,9 @@ class ChangeSetSplitter(object):
# There are no solutions for the problem.
# Should we really care about it?
- if (self._forcerequires or
- isinstance(req, PreRequires)):
+ if ((self._forcerequires or
+ isinstance(req, PreRequires))
+ and req in pkg.requires):
raise Error, _("No providers for '%s', "
"required by '%s'") % (req, pkg)
@@ -1625,7 +1630,7 @@ def recursiveInternalRequires(pkgmap, pkg, numrel, done=None):
return n
def forwardRequires(pkg, map):
- for req in pkg.requires:
+ for req in pkg.requires + pkg.recommends:
if req not in map:
map[req] = True
for prv in req.providedby:
@@ -1794,6 +1799,15 @@ def checkPackages(cache, checkset, relateset, report=False):
iface.info(_("Unsatisfied dependency: %s requires %s") %
(pkg, req))
+ for req in pkg.recommends:
+ for prv in req.providedby:
+ for prvpkg in prv.packages:
+ if prvpkg in relateset:
+ break
+ else:
+ continue
+ break
+
if not pkg.installed:
continue
--
1.7.9.5