382 lines
14 KiB
Diff
382 lines
14 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 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
|