1363 lines
51 KiB
Diff
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
|
|
|