| 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 9332ea0..4fcfbee 100644 |
| --- a/smart/backends/rpm/base.py |
| +++ b/smart/backends/rpm/base.py |
| @@ -225,6 +225,52 @@ 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 |
| + 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/ccache.c b/smart/ccache.c |
| index 7193185..8b66515 100644 |
| --- a/smart/ccache.c |
| +++ b/smart/ccache.c |
| @@ -500,6 +500,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; |
| @@ -1813,6 +1853,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; |
| @@ -2592,6 +2685,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; |
| @@ -2834,6 +2937,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: |
| @@ -3097,6 +3224,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: */ |
| @@ -3286,6 +3454,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); |
| |
| @@ -3821,6 +4094,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 |
| diff --git a/smart/commands/query.py b/smart/commands/query.py |
| index 9265cd9..b6f5697 100644 |
| --- a/smart/commands/query.py |
| +++ b/smart/commands/query.py |
| @@ -750,6 +750,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 |