blob: d607fc4752bd9fd7b141b794fe49db33b5e7c02c [file] [log] [blame]
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001Handle recommended packages in core and rpm backends
2
3Identify and store recommended packages in the cache, add a query option
4to read them and ignore them if they are not present when installing.
5
6Initial identification code from Mark Hatle <mark.hatle@windriver.com>.
7
8Upstream-Status: Pending
9
10Signed-off-by: Paul Eggleton <paul.eggleton@linux.intel.com>
11
12diff --git a/smart/backends/rpm/base.py b/smart/backends/rpm/base.py
13index 9332ea0..4fcfbee 100644
14--- a/smart/backends/rpm/base.py
15+++ b/smart/backends/rpm/base.py
16@@ -225,6 +225,52 @@ class RPMPackage(Package):
17 break
18 else:
19 return False
20+ srecs = fk(self.recommends)
21+ orecs = fk(other.recommends)
22+ if srecs != orecs:
23+ for srec in srecs:
24+ if srec.name[0] == "/" or srec in orecs:
25+ continue
26+ for orec in orecs:
27+ if (srec.name == orec.name and
28+ srec.relation == orec.relation and
29+ checkver(srec.version, orec.version)):
30+ break
31+ else:
32+ return False
33+ for orec in orecs:
34+ if orec.name[0] == "/" or orec in srecs:
35+ continue
36+ for srec in srecs:
37+ if (srec.name == orec.name and
38+ srec.relation == orec.relation and
39+ checkver(srec.version, orec.version)):
40+ break
41+ else:
42+ return False
43+ srecs = fk(self.recommends)
44+ orecs = fk(other.recommends)
45+ if srecs != orecs:
46+ for srec in srecs:
47+ if srec.name[0] == "/" or srec in orecs:
48+ continue
49+ for orec in orecs:
50+ if (srec.name == orec.name and
51+ srec.relation == orec.relation and
52+ checkver(srec.version, orec.version)):
53+ break
54+ else:
55+ return False
56+ for orec in orecs:
57+ if orec.name[0] == "/" or orec in srecs:
58+ continue
59+ for srec in srecs:
60+ if (srec.name == orec.name and
61+ srec.relation == orec.relation and
62+ checkver(srec.version, orec.version)):
63+ break
64+ else:
65+ return False
66 return True
67
68 def coexists(self, other):
69diff --git a/smart/ccache.c b/smart/ccache.c
70index 7193185..8b66515 100644
71--- a/smart/ccache.c
72+++ b/smart/ccache.c
73@@ -500,6 +500,46 @@ Package_equals(PackageObject *self, PackageObject *other)
74 }
75 }
76
77+ ilen = 0;
78+ jlen = 0;
79+ for (i = 0; i != PyList_GET_SIZE(self->recommends); i++) {
80+ PyObject *item = PyList_GET_ITEM(self->recommends, i);
81+ if (!PyObject_IsInstance(item, (PyObject *)&Depends_Type)) {
82+ PyErr_SetString(PyExc_TypeError, "Depends instance expected");
83+ return NULL;
84+ }
85+ if (STR(((DependsObject *)item)->name)[0] != '/')
86+ ilen += 1;
87+ }
88+ for (j = 0; j != PyList_GET_SIZE(other->recommends); j++) {
89+ PyObject *item = PyList_GET_ITEM(other->recommends, j);
90+ if (!PyObject_IsInstance(item, (PyObject *)&Depends_Type)) {
91+ PyErr_SetString(PyExc_TypeError, "Depends instance expected");
92+ return NULL;
93+ }
94+ if (STR(((DependsObject *)item)->name)[0] != '/')
95+ jlen += 1;
96+ }
97+ if (ilen != jlen) {
98+ ret = Py_False;
99+ goto exit;
100+ }
101+
102+ ilen = PyList_GET_SIZE(self->recommends);
103+ jlen = PyList_GET_SIZE(other->recommends);
104+ for (i = 0; i != ilen; i++) {
105+ PyObject *item = PyList_GET_ITEM(self->recommends, i);
106+ if (STR(((DependsObject *)item)->name)[0] != '/') {
107+ for (j = 0; j != jlen; j++)
108+ if (item == PyList_GET_ITEM(other->recommends, j))
109+ break;
110+ if (j == jlen) {
111+ ret = Py_False;
112+ goto exit;
113+ }
114+ }
115+ }
116+
117 exit:
118 Py_INCREF(ret);
119 return ret;
120@@ -1813,6 +1853,59 @@ Loader_buildPackage(LoaderObject *self, PyObject *args)
121 }
122 }
123
124+ /* if recargs: */
125+ if (recargs) {
126+ int i = 0;
127+ int len = PyList_GET_SIZE(recargs);
128+ /* pkg.recommends = [] */
129+ Py_DECREF(pkgobj->recommends);
130+ pkgobj->recommends = PyList_New(len);
131+ /* for args in recargs: */
132+ for (; i != len; i++) {
133+ PyObject *args = PyList_GET_ITEM(recargs, i);
134+ DependsObject *recobj;
135+ PyObject *rec;
136+
137+ if (!PyTuple_Check(args)) {
138+ PyErr_SetString(PyExc_TypeError,
139+ "Item in recargs is not a tuple");
140+ return NULL;
141+ }
142+
143+ /* rec = cache._objmap.get(args) */
144+ rec = PyDict_GetItem(cache->_objmap, args);
145+ recobj = (DependsObject *)rec;
146+
147+ /* if not rec: */
148+ if (!rec) {
149+ if (!PyTuple_Check(args) || PyTuple_GET_SIZE(args) < 2) {
150+ PyErr_SetString(PyExc_ValueError, "Invalid recargs tuple");
151+ return NULL;
152+ }
153+ /* rec = args[0](*args[1:]) */
154+ callargs = PyTuple_GetSlice(args, 1, PyTuple_GET_SIZE(args));
155+ rec = PyObject_CallObject(PyTuple_GET_ITEM(args, 0), callargs);
156+ Py_DECREF(callargs);
157+ if (!rec) return NULL;
158+ recobj = (DependsObject *)rec;
159+
160+ /* cache._objmap[args] = rec */
161+ PyDict_SetItem(cache->_objmap, args, rec);
162+ Py_DECREF(rec);
163+
164+ /* cache._recommends.append(rec) */
165+ PyList_Append(cache->_recommends, rec);
166+ }
167+
168+ /* relpkgs.append(rec.packages) */
169+ PyList_Append(relpkgs, recobj->packages);
170+
171+ /* pkg.recommends.append(rec) */
172+ Py_INCREF(rec);
173+ PyList_SET_ITEM(pkgobj->recommends, i, rec);
174+ }
175+ }
176+
177 /* if upgargs: */
178 if (upgargs) {
179 int i = 0;
180@@ -2592,6 +2685,16 @@ Cache_reset(CacheObject *self, PyObject *args)
181 if (PyList_Check(reqobj->providedby))
182 LIST_CLEAR(reqobj->providedby);
183 }
184+ len = PyList_GET_SIZE(self->_recommends);
185+ for (i = 0; i != len; i++) {
186+ DependsObject *reqobj;
187+ PyObject *req;
188+ req = PyList_GET_ITEM(self->_recommends, i);
189+ reqobj = (DependsObject *)req;
190+ LIST_CLEAR(reqobj->packages);
191+ if (PyList_Check(reqobj->providedby))
192+ LIST_CLEAR(reqobj->providedby);
193+ }
194 len = PyList_GET_SIZE(self->_upgrades);
195 for (i = 0; i != len; i++) {
196 DependsObject *upgobj;
197@@ -2834,6 +2937,30 @@ Cache__reload(CacheObject *self, PyObject *args)
198 }
199
200 /*
201+ for rec in pkg.recommends:
202+ rec.packages.append(pkg)
203+ if rec not in recommends:
204+ recommends[rec] = True
205+ objmap[rec.getInitArgs()] = rec
206+ */
207+ if (PyList_Check(pkg->recommends)) {
208+ klen = PyList_GET_SIZE(pkg->recommends);
209+ for (k = 0; k != klen; k++) {
210+ PyObject *rec = PyList_GET_ITEM(pkg->recommends, k);
211+ PyList_Append(((DependsObject *)rec)->packages,
212+ (PyObject *)pkg);
213+ if (!PyDict_GetItem(recommends, rec)) {
214+ PyDict_SetItem(recommends, rec, Py_True);
215+ args = PyObject_CallMethod(rec, "getInitArgs",
216+ NULL);
217+ if (!args) return NULL;
218+ PyDict_SetItem(objmap, args, rec);
219+ Py_DECREF(args);
220+ }
221+ }
222+ }
223+
224+ /*
225 for upg in pkg.upgrades:
226 upg.packages.append(pkg)
227 if upg not in upgrades:
228@@ -3097,6 +3224,47 @@ Cache_linkDeps(CacheObject *self, PyObject *args)
229 Py_DECREF(seq);
230 }
231
232+ /* recnames = {} */
233+ recnames = PyDict_New();
234+ /* for rec in self._recommends: */
235+ len = PyList_GET_SIZE(self->_recommends);
236+ for (i = 0; i != len; i++) {
237+ PyObject *rec = PyList_GET_ITEM(self->_recommends, i);
238+
239+ /* for name in rec.getMatchNames(): */
240+ PyObject *names = PyObject_CallMethod(rec, "getMatchNames", NULL);
241+ PyObject *seq = PySequence_Fast(names, "getMatchNames() returned "
242+ "non-sequence object");
243+ int nameslen;
244+ if (!seq) return NULL;
245+ nameslen = PySequence_Fast_GET_SIZE(seq);
246+ for (j = 0; j != nameslen; j++) {
247+ PyObject *name = PySequence_Fast_GET_ITEM(seq, j);
248+
249+ /* lst = recnames.get(name) */
250+ lst = PyDict_GetItem(recnames, name);
251+
252+ /*
253+ if lst:
254+ lst.append(rec)
255+ else:
256+ recnames[name] = [rec]
257+ */
258+ if (lst) {
259+ PyList_Append(lst, rec);
260+ } else {
261+ lst = PyList_New(1);
262+ Py_INCREF(rec);
263+ PyList_SET_ITEM(lst, 0, rec);
264+ PyDict_SetItem(recnames, name, lst);
265+ Py_DECREF(lst);
266+ }
267+ }
268+
269+ Py_DECREF(names);
270+ Py_DECREF(seq);
271+ }
272+
273 /* upgnames = {} */
274 upgnames = PyDict_New();
275 /* for upg in self._upgrades: */
276@@ -3286,6 +3454,56 @@ Cache_linkDeps(CacheObject *self, PyObject *args)
277 }
278 }
279
280+ /* lst = recnames.get(prv.name) */
281+ lst = PyDict_GetItem(recnames, prv->name);
282+
283+ /* if lst: */
284+ if (lst) {
285+ /* for rec in lst: */
286+ int reclen = PyList_GET_SIZE(lst);
287+ for (j = 0; j != reclen; j++) {
288+ DependsObject *rec = (DependsObject *)PyList_GET_ITEM(lst, j);
289+ /* if rec.matches(prv): */
290+ PyObject *ret = PyObject_CallMethod((PyObject *)rec, "matches",
291+ "O", (PyObject *)prv);
292+ if (!ret) return NULL;
293+ if (PyObject_IsTrue(ret)) {
294+ /*
295+ if rec.providedby:
296+ rec.providedby.append(prv)
297+ else:
298+ rec.providedby = [prv]
299+ */
300+ if (PyList_Check(rec->providedby)) {
301+ PyList_Append(rec->providedby, (PyObject *)prv);
302+ } else {
303+ PyObject *_lst = PyList_New(1);
304+ Py_INCREF(prv);
305+ PyList_SET_ITEM(_lst, 0, (PyObject *)prv);
306+ Py_DECREF(rec->providedby);
307+ rec->providedby = _lst;
308+ }
309+
310+ /*
311+ if prv.recommendedby:
312+ prv.recommendedby.append(prv)
313+ else:
314+ prv.recommendedby = [prv]
315+ */
316+ if (PyList_Check(prv->recommendedby)) {
317+ PyList_Append(prv->recommendedby, (PyObject *)rec);
318+ } else {
319+ PyObject *_lst = PyList_New(1);
320+ Py_INCREF(rec);
321+ PyList_SET_ITEM(_lst, 0, (PyObject *)rec);
322+ Py_DECREF(prv->recommendedby);
323+ prv->recommendedby = _lst;
324+ }
325+ }
326+ Py_DECREF(ret);
327+ }
328+ }
329+
330 /* lst = upgnames.get(prv.name) */
331 lst = PyDict_GetItem(upgnames, prv->name);
332
333@@ -3821,6 +4094,21 @@ Cache__setstate__(CacheObject *self, PyObject *state)
334 }
335
336 /*
337+ for rec in pkg.recommends:
338+ rec.packages.append(pkg)
339+ recommends[rec] = True
340+ */
341+ if (PyList_Check(pkgobj->recommends)) {
342+ jlen = PyList_GET_SIZE(pkgobj->recommends);
343+ for (j = 0; j != jlen; j++) {
344+ PyObject *rec = PyList_GET_ITEM(pkgobj->recommends, j);
345+ DependsObject *recobj = (DependsObject *)rec;
346+ PyList_Append(recobj->packages, pkg);
347+ PyDict_SetItem(recommends, rec, Py_True);
348+ }
349+ }
350+
351+ /*
352 for upg in pkg.upgrades:
353 upg.packages.append(pkg)
354 upgrades[upg] = True
355diff --git a/smart/commands/query.py b/smart/commands/query.py
356index 9265cd9..b6f5697 100644
357--- a/smart/commands/query.py
358+++ b/smart/commands/query.py
359@@ -750,6 +750,22 @@ class TextOutput(NullOutput):
360 name = str(prvpkg)
361 print " ", "%s (%s)" % (name, prv)
362
363+ def showRecommends(self, pkg, rec):
364+ if self._firstrecommends:
365+ self._firstrecommends = False
366+ print " ", _("Recommends:")
367+ print " ", rec
368+
369+ def showRecommendsProvidedBy(self, pkg, req, prv, prvpkg):
370+ if self._firstrecommendsprovidedby:
371+ self._firstrecommendsprovidedby = False
372+ print " ", _("Provided By:")
373+ if self.opts.hide_version:
374+ name = prvpkg.name
375+ else:
376+ name = str(prvpkg)
377+ print " ", "%s (%s)" % (name, prv)
378+
379 def showUpgrades(self, pkg, upg):
380 if self._firstupgrades:
381 self._firstupgrades = False