blob: d607fc4752bd9fd7b141b794fe49db33b5e7c02c [file] [log] [blame]
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