1 /*
2 * Copyright (C) 2012-2014 Red Hat, Inc.
3 *
4 * Licensed under the GNU Lesser General Public License Version 2.1
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21 #include <Python.h>
22 #include <solv/poolid.h>
23 #include <solv/solver.h>
24 #include <solv/util.h>
25 #include <time.h>
26
27 #include "error.hpp"
28 #include "nevra.hpp"
29 #include "hy-query-private.hpp"
30 #include "hy-selector.h"
31 #include "hy-subject.h"
32 #include "dnf-reldep.h"
33 #include "dnf-reldep-list.h"
34 #include "repo/solvable/DependencyContainer.hpp"
35 #include "transaction/Swdb.hpp"
36
37 #include "exception-py.hpp"
38 #include "hawkey-pysys.hpp"
39 #include "iutil-py.hpp"
40 #include "package-py.hpp"
41 #include "query-py.hpp"
42 #include "reldep-py.hpp"
43 #include "sack-py.hpp"
44 #include "pycomp.hpp"
45 #include "sack/advisorypkg.hpp"
46 #include "sack/packageset.hpp"
47 #include "sack/selector.hpp"
48
49 #include <algorithm>
50 #include <functional>
51
52 typedef struct {
53 PyObject_HEAD
54 HyQuery query;
55 PyObject *sack;
56 } _QueryObject;
57
58 static const int keyname_int_matches[] = {
59 HY_PKG,
60 HY_PKG_ADVISORY,
61 HY_PKG_ADVISORY_BUG,
62 HY_PKG_ADVISORY_CVE,
63 HY_PKG_ADVISORY_SEVERITY,
64 HY_PKG_ADVISORY_TYPE,
65 HY_PKG_ARCH,
66 HY_PKG_CONFLICTS,
67 HY_PKG_DESCRIPTION,
68 HY_PKG_DOWNGRADABLE,
69 HY_PKG_DOWNGRADES,
70 HY_PKG_EMPTY,
71 HY_PKG_ENHANCES,
72 HY_PKG_EPOCH,
73 HY_PKG_EVR,
74 HY_PKG_FILE,
75 HY_PKG_LATEST,
76 HY_PKG_LATEST_PER_ARCH,
77 HY_PKG_LATEST_PER_ARCH_BY_PRIORITY,
78 HY_PKG_LOCATION,
79 HY_PKG_NAME,
80 HY_PKG_NEVRA,
81 HY_PKG_NEVRA_STRICT,
82 HY_PKG_OBSOLETES,
83 HY_PKG_OBSOLETES_BY_PRIORITY,
84 HY_PKG_PROVIDES,
85 HY_PKG_RECOMMENDS,
86 HY_PKG_RELEASE,
87 HY_PKG_REPONAME,
88 HY_PKG_REQUIRES,
89 HY_PKG_SOURCERPM,
90 HY_PKG_SUGGESTS,
91 HY_PKG_SUMMARY,
92 HY_PKG_SUPPLEMENTS,
93 HY_PKG_UPGRADABLE,
94 HY_PKG_UPGRADES,
95 HY_PKG_UPGRADES_BY_PRIORITY,
96 HY_PKG_URL,
97 HY_PKG_VERSION
98 };
99
100 static const char * const keyname_char_matches[] = {
101 "pkg",
102 "advisory",
103 "advisory_bug",
104 "advisory_cve",
105 "advisory_severity",
106 "advisory_type",
107 "arch",
108 "conflicts",
109 "description",
110 "downgradable",
111 "downgrades",
112 "empty",
113 "enhances",
114 "epoch",
115 "evr",
116 "file",
117 "latest",
118 "latest_per_arch",
119 "latest_per_arch_by_priority",
120 "location",
121 "name",
122 "nevra",
123 "nevra_strict",
124 "obsoletes",
125 "obsoletes_by_priority",
126 "provides",
127 "recommends",
128 "release",
129 "reponame",
130 "requires",
131 "sourcerpm",
132 "suggests",
133 "summary",
134 "supplements",
135 "upgradable",
136 "upgrades",
137 "upgrades_by_priority",
138 "url",
139 "version",
140 NULL
141 };
142
143 static const char * const query_cmp_map_char[] = {
144 "eq",
145 "gt",
146 "lt",
147 "neq",
148 "not",
149 "gte",
150 "lte",
151 "substr",
152 "glob",
153 "eqg",
154 "upgrade",
155 NULL
156 };
157
158 static const int query_cmp_map_int[] = {
159 HY_EQ,
160 HY_GT,
161 HY_LT,
162 HY_NEQ,
163 HY_NOT,
164 HY_EQ | HY_GT,
165 HY_EQ | HY_LT,
166 HY_SUBSTR,
167 HY_GLOB,
168 HY_EQG,
169 HY_UPGRADE
170 };
171
172 HyQuery
queryFromPyObject(PyObject * o)173 queryFromPyObject(PyObject *o)
174 {
175 if (!PyType_IsSubtype(o->ob_type, &query_Type)) {
176 PyErr_SetString(PyExc_TypeError, "Expected a Query object.");
177 return NULL;
178 }
179 return ((_QueryObject *)o)->query;
180 }
181
182 PyObject *
queryToPyObject(HyQuery query,PyObject * sack,PyTypeObject * custom_object_type)183 queryToPyObject(HyQuery query, PyObject *sack, PyTypeObject *custom_object_type)
184 {
185 _QueryObject *self = (_QueryObject *)custom_object_type->tp_alloc(custom_object_type, 0);
186 if (self) {
187 self->query = query;
188 self->sack = sack;
189 Py_INCREF(sack);
190 }
191 return (PyObject *) self;
192 }
193
194 int
query_converter(PyObject * o,HyQuery * query_ptr)195 query_converter(PyObject *o, HyQuery *query_ptr)
196 {
197 HyQuery query = queryFromPyObject(o);
198 if (query == NULL)
199 return 0;
200 *query_ptr = query;
201 return 1;
202 }
203
204 /* functions on the type */
205
206 static PyObject *
query_new(PyTypeObject * type,PyObject * args,PyObject * kwds)207 query_new(PyTypeObject *type, PyObject *args, PyObject *kwds) try
208 {
209 _QueryObject *self = (_QueryObject *)type->tp_alloc(type, 0);
210 if (self) {
211 self->query = NULL;
212 self->sack = NULL;
213 }
214 return (PyObject *)self;
215 } CATCH_TO_PYTHON
216
217 static void
query_dealloc(_QueryObject * self)218 query_dealloc(_QueryObject *self)
219 {
220 if (self->query)
221 delete self->query;
222 Py_XDECREF(self->sack);
223 Py_TYPE(self)->tp_free(self);
224 }
225
226 static int
query_init(_QueryObject * self,PyObject * args,PyObject * kwds)227 query_init(_QueryObject * self, PyObject *args, PyObject *kwds) try
228 {
229 const char *kwlist[] = {"sack", "flags", "query", NULL};
230 PyObject *sack = NULL;
231 PyObject *query = NULL;
232 int flags = 0;
233
234 if (!PyArg_ParseTupleAndKeywords(args, kwds, "|OiO", (char**) kwlist, &sack, &flags, &query))
235 return -1;
236
237 if (query && (!sack || sack == Py_None) && queryObject_Check(query)) {
238 _QueryObject *query_obj = (_QueryObject*)query;
239 self->sack = query_obj->sack;
240 self->query = new libdnf::Query(*query_obj->query);
241 } else if (sack && (!query || query == Py_None) && sackObject_Check(sack)) {
242 DnfSack *csack = sackFromPyObject(sack);
243 assert(csack);
244 self->sack = sack;
245 self->query = new libdnf::Query(csack, static_cast<libdnf::Query::ExcludeFlags>(flags));
246 } else {
247 const char *msg = "Expected a _hawkey.Sack or a _hawkey.Query object.";
248 PyErr_SetString(PyExc_TypeError, msg);
249 return -1;
250 }
251 Py_INCREF(self->sack);
252 return 0;
253 } CATCH_TO_PYTHON_INT
254
255 /* object attributes */
256
257 static PyObject *
get_evaluated(_QueryObject * self,void * unused)258 get_evaluated(_QueryObject *self, void *unused) try
259 {
260 HyQuery q = self->query;
261 return PyBool_FromLong((long) q->getApplied());
262 } CATCH_TO_PYTHON
263
264 static PyObject *
clear(_QueryObject * self,PyObject * unused)265 clear(_QueryObject *self, PyObject *unused) try
266 {
267 self->query->clear();
268 Py_RETURN_NONE;
269 } CATCH_TO_PYTHON
270
271 static int
raise_bad_filter(void)272 raise_bad_filter(void)
273 {
274 PyErr_SetString(HyExc_Query, "Invalid filter key or match type.");
275 return 0;
276 }
277
278 static int
filter_add(HyQuery query,key_t keyname,int cmp_type,PyObject * match)279 filter_add(HyQuery query, key_t keyname, int cmp_type, PyObject *match)
280 {
281 if (keyname == HY_PKG_DOWNGRADABLE ||
282 keyname == HY_PKG_DOWNGRADES ||
283 keyname == HY_PKG_EMPTY ||
284 keyname == HY_PKG_LATEST_PER_ARCH ||
285 keyname == HY_PKG_LATEST_PER_ARCH_BY_PRIORITY ||
286 keyname == HY_PKG_LATEST ||
287 keyname == HY_PKG_UPGRADABLE ||
288 keyname == HY_PKG_UPGRADES ||
289 keyname == HY_PKG_UPGRADES_BY_PRIORITY) {
290 int val;
291
292 if (!PyInt_Check(match) || cmp_type != HY_EQ) {
293 PyErr_SetString(HyExc_Value, "Invalid boolean filter query.");
294 return 0;
295 }
296 long val_long = PyLong_AsLong(match);
297 if (val_long < INT_MIN) {
298 val = INT_MIN;
299 } else if (val_long > INT_MAX) {
300 val = INT_MAX;
301 } else {
302 val = val_long;
303 }
304 if (keyname == HY_PKG_EMPTY) {
305 if (!val) {
306 PyErr_SetString(HyExc_Value, "Invalid boolean filter query.");
307 return 0;
308 }
309 query->addFilter(HY_PKG_EMPTY, HY_EQ, 1);
310 } else {
311 query->addFilter(keyname, HY_EQ, val);
312 }
313 return 1;
314 }
315 if (PyUnicode_Check(match) || PyString_Check(match)) {
316 PycompString cmatch(match);
317 if (!cmatch.getCString())
318 return 0;
319 int query_filter_ret = query->addFilter(keyname, cmp_type, cmatch.getCString());
320
321 if (query_filter_ret)
322 return raise_bad_filter();
323 return 1;
324 }
325 if (PyInt_Check(match)) {
326 long val = PyLong_AsLong(match);
327 if (cmp_type == HY_GLOB) // Workaround: Python can send integer with HY_GLOB
328 cmp_type = HY_EQ;
329 if (val > INT_MAX || val < INT_MIN) {
330 PyErr_SetString(HyExc_Value, "Numeric argument out of range.");
331 return 0;
332 }
333 if (query->addFilter(keyname, cmp_type, val))
334 return raise_bad_filter();
335 return 1;
336 }
337 if (queryObject_Check(match)) {
338 HyQuery target = queryFromPyObject(match);
339 const DnfPackageSet * pset = target->runSet();
340 int ret = query->addFilter(keyname, cmp_type, pset);
341
342 if (ret)
343 return raise_bad_filter();
344 return 1;
345 }
346 if (reldepObject_Check(match)) {
347 DnfReldep *reldep = reldepFromPyObject(match);
348 if (cmp_type != HY_EQ || query->addFilter(keyname, reldep))
349 return raise_bad_filter();
350 return 1;
351 }
352 // match is a sequence now:
353 switch (keyname) {
354 case HY_PKG:
355 case HY_PKG_OBSOLETES:
356 case HY_PKG_OBSOLETES_BY_PRIORITY:
357 case HY_PKG_CONFLICTS:
358 case HY_PKG_REQUIRES:
359 case HY_PKG_ENHANCES:
360 case HY_PKG_RECOMMENDS:
361 case HY_PKG_SUGGESTS:
362 case HY_PKG_SUPPLEMENTS: {
363 // It could be a sequence of packages or reldep/strings. Lets try packages first.
364 auto pset = pyseq_to_packageset(match, query->getSack());
365 if (!pset) {
366 if (auto PyError = PyErr_Occurred()) {
367 // It was not a sequence of packages.
368 if (PyErr_GivenExceptionMatches(PyError, PyExc_TypeError)) {
369 PyErr_Clear();
370 auto reldeplist = pyseq_to_reldeplist(match, query->getSack(), cmp_type);
371 if (reldeplist == NULL)
372 return 1;
373
374 int ret = query->addFilter(keyname, reldeplist.get());
375 if (ret) {
376 return raise_bad_filter();
377 }
378 break;
379 }
380 }
381 return 1;
382 }
383 int ret = query->addFilter(keyname, cmp_type, pset.get());
384 if (ret)
385 return raise_bad_filter();
386
387 break;
388 }
389 case HY_PKG_PROVIDES: {
390 auto reldeplist = pyseq_to_reldeplist(match, query->getSack(), cmp_type);
391 if (reldeplist == NULL)
392 return 1;
393
394 int ret = query->addFilter(keyname, reldeplist.get());
395 if (ret)
396 return raise_bad_filter();
397 break;
398 }
399 default: {
400 std::vector<std::string> matches;
401 try {
402 matches = pySequenceConverter(match);
403 } catch (std::runtime_error &) {
404 return 0;
405 }
406 std::vector<const char *> matchesCString(matches.size() + 1);
407 std::transform(matches.begin(), matches.end(), matchesCString.begin(),
408 std::mem_fn(&std::string::c_str));
409 int filter_in_ret = query->addFilter(keyname, cmp_type, matchesCString.data());
410 if (filter_in_ret)
411 return raise_bad_filter();
412 break;
413 }
414 }
415 return 1;
416 }
417
418 static char *
filter_key_splitter(char ** key)419 filter_key_splitter(char** key)
420 {
421 char *sbegin = *key;
422 char *end;
423
424 if (sbegin == NULL)
425 return NULL;
426 int index;
427
428 for (index = 0; sbegin[index] != '\0'; ++index) {
429 if ((sbegin[index] == '_') && (sbegin[index + 1] == '_')) {
430 end = sbegin + index;
431 *end++ = '\0';
432 *key = ++end;
433 return sbegin;
434 }
435 }
436 *key = NULL;
437 return sbegin;
438 }
439
440 gboolean
filter_internal(HyQuery query,HySelector sltr,PyObject * sack,PyObject * args,PyObject * kwds)441 filter_internal(HyQuery query, HySelector sltr, PyObject *sack, PyObject *args, PyObject *kwds)
442 {
443 PyObject *key, *value;
444 Py_ssize_t pos = 0;
445 key_t keyname;
446 int cmp_type;
447 PyObject *tuple_item;
448 int argument_number, presence_cmp_type;
449 int cmp_type_flag = 0;
450
451 if (args != NULL) {
452 Py_ssize_t tuple_size = PyTuple_Size(args);
453 for (int x = 0; x < tuple_size; ++x) {
454 tuple_item = PyTuple_GetItem(args, x);
455 if (PyInt_Check(tuple_item)) {
456 long c_int = PyLong_AsLong(tuple_item);
457 if (c_int == HY_ICASE) {
458 cmp_type_flag = HY_ICASE;
459 } else {
460 PyErr_SetString(HyExc_Value, "Invalid flag. Only HY_ICASE allowed");
461 return FALSE;
462 }
463 }
464 }
465 }
466
467 if (kwds != NULL) {
468 while (PyDict_Next(kwds, &pos, &key, &value)) {
469 keyname = -1;
470 argument_number = 0;
471 PycompString cmatch(key);
472 if (!cmatch.getCString())
473 return FALSE;
474 auto parsed_string = cmatch.getString();
475 char *tmp_string = &parsed_string.front();
476 cmp_type = 0;
477 char *parcial_string;
478 while ((parcial_string = filter_key_splitter(&tmp_string)) != NULL) {
479 if (!argument_number) {
480 for (unsigned int i = 0; keyname_char_matches[i] != NULL; ++i) {
481 if (strcmp(keyname_char_matches[i], parcial_string) == 0) {
482 keyname = keyname_int_matches[i];
483 argument_number = 1;
484 break;
485 }
486 }
487 if (!argument_number) {
488 PyErr_SetString(HyExc_Value, g_strdup_printf(
489 "Unrecognized key name: %s", parcial_string));
490 return FALSE;
491 }
492 } else {
493 presence_cmp_type = FALSE;
494 for (unsigned int i = 0; query_cmp_map_char[i] != NULL; ++i) {
495 if (strcmp(query_cmp_map_char[i], parcial_string) == 0) {
496 cmp_type |= query_cmp_map_int[i];
497 presence_cmp_type = TRUE;
498 break;
499 }
500 }
501 if (!presence_cmp_type) {
502 PyErr_SetString(HyExc_Value, g_strdup_printf(
503 "Unrecognized filter type: %s", parcial_string));
504 return FALSE;
505 }
506 }
507 }
508 if (cmp_type == 0) {
509 cmp_type = HY_EQ;
510 }
511 if (keyname != -1) {
512 if (query != NULL) {
513 if (filter_add(query, keyname, cmp_type|cmp_type_flag, value) == 0) {
514 return FALSE;
515 }
516 } else {
517 if (keyname == HY_PKG) {
518 DnfSack *c_sack = sackFromPyObject(sack);
519 assert(c_sack);
520 auto pset = pyseq_to_packageset(value, c_sack);
521 if (!pset) {
522 ret2e(DNF_ERROR_BAD_SELECTOR, "Invalid value type: Only List and Query supported");
523 return FALSE;
524 }
525 if (!sltr) {
526 PyErr_SetString(HyExc_Value, "Selector is nulptr");
527 return FALSE;
528 }
529 if (ret2e(sltr->set(pset.get()),
530 "Invalid Selector spec." )) {
531 return FALSE;
532 }
533 } else {
534 PycompString c_sltr_match(value);
535 if (!c_sltr_match.getCString())
536 return FALSE;
537 if (ret2e(hy_selector_set(sltr, keyname, cmp_type, c_sltr_match.getCString()),
538 "Invalid Selector spec." )) {
539 return FALSE;
540 }
541 }
542 }
543 }
544 }
545 }
546 return TRUE;
547 }
548
549 static PyObject *
filter(_QueryObject * self,PyObject * args,PyObject * kwds)550 filter(_QueryObject *self, PyObject *args, PyObject *kwds) try {
551 auto query = std::unique_ptr<libdnf::Query>(new libdnf::Query(*self->query));
552 gboolean ret = filter_internal(query.get(), NULL, self->sack, args, kwds);
553 if (!ret)
554 return NULL;
555 PyObject *final_query = queryToPyObject(query.release(), self->sack, Py_TYPE(self));
556 return final_query;
557 } CATCH_TO_PYTHON
558
559 static _QueryObject *
filterm(_QueryObject * self,PyObject * args,PyObject * kwds)560 filterm(_QueryObject *self, PyObject *args, PyObject *kwds) try {
561 gboolean ret = filter_internal(self->query, NULL, self->sack, args, kwds);
562 if (!ret)
563 return NULL;
564 Py_INCREF(self);
565 return self;
566 } CATCH_TO_PYTHON
567
568 static PyObject *
add_available_filter(_QueryObject * self,PyObject * unused)569 add_available_filter(_QueryObject *self, PyObject *unused) try
570 {
571 HyQuery query = new libdnf::Query(*self->query);
572 query->available();
573 PyObject *final_query = queryToPyObject(query, self->sack, Py_TYPE(self));
574 return final_query;
575 } CATCH_TO_PYTHON
576
577 static PyObject *
add_downgrades_filter(_QueryObject * self,PyObject * unused)578 add_downgrades_filter(_QueryObject *self, PyObject *unused) try
579 {
580 HyQuery query = new libdnf::Query(*self->query);
581 query->addFilter(HY_PKG_DOWNGRADES, HY_EQ, 1);
582 PyObject *final_query = queryToPyObject(query, self->sack, Py_TYPE(self));
583 return final_query;
584 } CATCH_TO_PYTHON
585
586 static PyObject *
duplicated_filter(_QueryObject * self,PyObject * unused)587 duplicated_filter(_QueryObject *self, PyObject *unused) try
588 {
589 HyQuery self_query_copy = new libdnf::Query(*self->query);
590 self_query_copy->filterDuplicated();
591 PyObject *final_query = queryToPyObject(self_query_copy, self->sack, Py_TYPE(self));
592 return final_query;
593 } CATCH_TO_PYTHON
594
595 static PyObject *
add_filter_extras(_QueryObject * self,PyObject * unused)596 add_filter_extras(_QueryObject *self, PyObject *unused) try
597 {
598 HyQuery self_query_copy = new libdnf::Query(*self->query);
599 self_query_copy->filterExtras();
600 PyObject *final_query = queryToPyObject(self_query_copy, self->sack, Py_TYPE(self));
601 return final_query;
602 } CATCH_TO_PYTHON
603
604 static PyObject *
add_installed_filter(_QueryObject * self,PyObject * unused)605 add_installed_filter(_QueryObject *self, PyObject *unused) try
606 {
607 HyQuery query = new libdnf::Query(*self->query);
608 query->installed();
609 PyObject *final_query = queryToPyObject(query, self->sack, Py_TYPE(self));
610 return final_query;
611 } CATCH_TO_PYTHON
612
613 static PyObject *
add_filter_latest(_QueryObject * self,PyObject * args)614 add_filter_latest(_QueryObject *self, PyObject *args) try
615 {
616 int value = 1;
617
618 if (!PyArg_ParseTuple(args, "|i", &value))
619 return NULL;
620
621 HyQuery query = new libdnf::Query(*self->query);
622 query->addFilter(HY_PKG_LATEST_PER_ARCH, HY_EQ, value);
623 PyObject *final_query = queryToPyObject(query, self->sack, Py_TYPE(self));
624 return final_query;
625 } CATCH_TO_PYTHON
626
627 static PyObject *
add_upgrades_filter(_QueryObject * self,PyObject * unused)628 add_upgrades_filter(_QueryObject *self, PyObject *unused) try
629 {
630 HyQuery query = new libdnf::Query(*self->query);
631 query->addFilter(HY_PKG_UPGRADES, HY_EQ, 1);
632 PyObject *final_query = queryToPyObject(query, self->sack, Py_TYPE(self));
633 return final_query;
634 } CATCH_TO_PYTHON
635
636
637 static PyObject *
run(_QueryObject * self,PyObject * unused)638 run(_QueryObject *self, PyObject *unused) try
639 {
640 PyObject *list;
641
642 const DnfPackageSet * pset = self->query->runSet();
643 list = packageset_to_pylist(pset, self->sack);
644 return list;
645 } CATCH_TO_PYTHON
646
647 static PyObject *
apply(PyObject * self,PyObject * unused)648 apply(PyObject *self, PyObject *unused) try
649 {
650 ((_QueryObject *) self)->query->apply();
651 Py_INCREF(self);
652 return self;
653 } CATCH_TO_PYTHON
654
655 static PyObject *
q_union(PyObject * self,PyObject * args)656 q_union(PyObject *self, PyObject *args) try
657 {
658 PyObject *other;
659 if (!PyArg_ParseTuple(args, "O!", &query_Type, &other))
660 return NULL;
661
662 HyQuery self_query_copy = new libdnf::Query(*((_QueryObject *) self)->query);
663 HyQuery other_q = ((_QueryObject *) other)->query;
664 self_query_copy->queryUnion(*other_q);
665 PyObject *final_query = queryToPyObject(self_query_copy, ((_QueryObject *) self)->sack,
666 Py_TYPE(self));
667 return final_query;
668 } CATCH_TO_PYTHON
669
670 static PyObject *
q_intersection(PyObject * self,PyObject * args)671 q_intersection(PyObject *self, PyObject *args) try
672 {
673 PyObject *other;
674 if (!PyArg_ParseTuple(args, "O!", &query_Type, &other))
675 return NULL;
676
677 HyQuery self_query_copy = new libdnf::Query(*((_QueryObject *) self)->query);
678 HyQuery other_q = ((_QueryObject *) other)->query;
679 self_query_copy->queryIntersection(*other_q);
680 PyObject *final_query = queryToPyObject(self_query_copy, ((_QueryObject *) self)->sack,
681 Py_TYPE(self));
682 return final_query;
683 } CATCH_TO_PYTHON
684
685 static PyObject *
q_difference(PyObject * self,PyObject * args)686 q_difference(PyObject *self, PyObject *args) try
687 {
688 PyObject *other;
689 if (!PyArg_ParseTuple(args, "O!", &query_Type, &other))
690 return NULL;
691
692 HyQuery self_query_copy = new libdnf::Query(*((_QueryObject *) self)->query);
693 HyQuery other_q = ((_QueryObject *) other)->query;
694 self_query_copy->queryDifference(*other_q);
695 PyObject *final_query = queryToPyObject(self_query_copy, ((_QueryObject *) self)->sack,
696 Py_TYPE(self));
697 return final_query;
698 } CATCH_TO_PYTHON
699
700 typedef struct {
701 PyObject_HEAD
702 libdnf::Swdb *ptr;
703 void *ty;
704 int own;
705 PyObject *next;
706 } SwdbSwigPyObject;
707
708 static PyObject *
get_advisory_pkgs(_QueryObject * self,PyObject * args)709 get_advisory_pkgs(_QueryObject *self, PyObject *args) try
710 {
711 int cmpType;
712
713 if (!PyArg_ParseTuple(args, "i", &cmpType))
714 return NULL;
715
716 std::vector<libdnf::AdvisoryPkg> advisoryPkgs;
717
718 self->query->getAdvisoryPkgs(cmpType, advisoryPkgs);
719 return advisoryPkgVectorToPylist(advisoryPkgs);
720 } CATCH_TO_PYTHON
721
722 static PyObject *
filter_userinstalled(PyObject * self,PyObject * args,PyObject * kwds)723 filter_userinstalled(PyObject *self, PyObject *args, PyObject *kwds) try
724 {
725 const char *kwlist[] = {"swdb", NULL};
726 PyObject *pySwdb;
727
728 if (!PyArg_ParseTupleAndKeywords(args, kwds, "O", (char **)kwlist, &pySwdb)) {
729 return NULL;
730 }
731
732 UniquePtrPyObject thisPySwdb(PyObject_GetAttrString(pySwdb, "this"));
733 auto swigSwdb = reinterpret_cast< SwdbSwigPyObject * >(thisPySwdb.get());
734
735 if (swigSwdb == nullptr) {
736 PyErr_SetString(PyExc_SystemError, "Unable to parse SwigPyObject");
737 return NULL;
738 }
739
740 libdnf::Swdb * swdb = swigSwdb->ptr;
741
742 if (swdb == NULL) {
743 PyErr_SetString(PyExc_SystemError, "Unable to parse swig object");
744 return NULL;
745 }
746 HyQuery self_query_copy = new libdnf::Query(*((_QueryObject *) self)->query);
747 self_query_copy->filterUserInstalled(*swdb);
748
749 PyObject *final_query = queryToPyObject(self_query_copy, ((_QueryObject *) self)->sack,
750 Py_TYPE(self));
751 return final_query;
752 } CATCH_TO_PYTHON
753
754 static PyObject *
filter_unneeded_or_safe_to_remove(PyObject * self,PyObject * args,PyObject * kwds,bool SafeToRemove)755 filter_unneeded_or_safe_to_remove(PyObject *self, PyObject *args, PyObject *kwds, bool SafeToRemove)
756 {
757 const char *kwlist[] = {"swdb", "debug_solver", NULL};
758 PyObject *pySwdb;
759 PyObject *debug_solver = NULL;
760
761 if (!PyArg_ParseTupleAndKeywords(
762 args, kwds, "O|O!", (char **)kwlist, &pySwdb, &PyBool_Type, &debug_solver)) {
763 return NULL;
764 }
765
766 UniquePtrPyObject thisPySwdb(PyObject_GetAttrString(pySwdb, "this"));
767 auto swigSwdb = reinterpret_cast< SwdbSwigPyObject * >(thisPySwdb.get());
768
769 if (swigSwdb == nullptr) {
770 PyErr_SetString(PyExc_SystemError, "Unable to parse SwigPyObject");
771 return NULL;
772 }
773
774 libdnf::Swdb *swdb = swigSwdb->ptr;
775
776 if (swdb == NULL) {
777 PyErr_SetString(PyExc_SystemError, "Unable to parse swig object");
778 return NULL;
779 }
780 std::unique_ptr<libdnf::Query> self_query_copy(new libdnf::Query(*((_QueryObject *) self)->query));
781 gboolean c_debug_solver = debug_solver != NULL && PyObject_IsTrue(debug_solver);
782
783 int ret;
784 if (SafeToRemove) {
785 ret = self_query_copy->filterSafeToRemove(*swdb, c_debug_solver);
786 } else {
787 ret = self_query_copy->filterUnneeded(*swdb, c_debug_solver);
788 }
789 if (ret == -1) {
790 PyErr_SetString(PyExc_SystemError, "Unable to provide query with unneded filter");
791 return NULL;
792 }
793
794 PyObject *final_query = queryToPyObject(self_query_copy.release(), ((_QueryObject *) self)->sack,
795 Py_TYPE(self));
796 return final_query;
797 }
798
799 static PyObject *
filter_safe_to_remove(PyObject * self,PyObject * args,PyObject * kwds)800 filter_safe_to_remove(PyObject *self, PyObject *args, PyObject *kwds) try
801 {
802 return filter_unneeded_or_safe_to_remove(self, args, kwds, true);
803 } CATCH_TO_PYTHON
804
805
806 static PyObject *
filter_unneeded(PyObject * self,PyObject * args,PyObject * kwds)807 filter_unneeded(PyObject *self, PyObject *args, PyObject *kwds) try
808 {
809 return filter_unneeded_or_safe_to_remove(self, args, kwds, false);
810 } CATCH_TO_PYTHON
811
812 static PyObject *
q_add(_QueryObject * self,PyObject * list)813 q_add(_QueryObject *self, PyObject *list) try
814 {
815 if (!PyList_Check(list)) {
816 PyErr_SetString(PyExc_TypeError, "Only a list can be concatenated to a Query");
817 return NULL;
818 }
819 PyObject *unused = NULL;
820 PyObject *query_list = run(self, unused);
821
822 int list_count = PyList_Size(list);
823 for (int index = 0; index < list_count; ++index)
824 PyList_Append(query_list, PyList_GetItem(list, index));
825 return query_list;
826 } CATCH_TO_PYTHON
827
828 static int
query_contains(PyObject * self,PyObject * pypkg)829 query_contains(PyObject *self, PyObject *pypkg) try
830 {
831 HyQuery q = ((_QueryObject *) self)->query;
832 DnfPackage *pkg = packageFromPyObject(pypkg);
833
834 if (pkg) {
835 Id id = dnf_package_get_id(pkg);
836 q->apply();
837 if (MAPTST(q->getResult(), id))
838 return 1;
839 }
840 return 0;
841 } CATCH_TO_PYTHON_INT
842
843 static size_t
query_len(PyObject * self)844 query_len(PyObject *self) try
845 {
846 HyQuery q = ((_QueryObject *) self)->query;
847 return q->size();
848 } CATCH_TO_PYTHON_INT
849
850 static PyObject *
q_length(PyObject * self,PyObject * unused)851 q_length(PyObject *self, PyObject *unused) try
852 {
853 return PyLong_FromLong(query_len(self));
854 } CATCH_TO_PYTHON
855
856 static PyObject *
query_get_item(PyObject * self,int index)857 query_get_item(PyObject *self, int index) try
858 {
859 HyQuery query = ((_QueryObject *) self)->query;
860 Id id = query->getIndexItem(index);
861 if (id == -1) {
862 PyErr_SetString(PyExc_IndexError, "list index out of range");
863 return NULL;
864 }
865 PyObject *package = new_package(((_QueryObject *) self)->sack, id);
866 return package;
867 } CATCH_TO_PYTHON
868
869 static PyObject *
query_iter(PyObject * self)870 query_iter(PyObject *self) try
871 {
872 const DnfPackageSet * pset = ((_QueryObject *) self)->query->runSet();
873 UniquePtrPyObject list(packageset_to_pylist(pset, ((_QueryObject *) self)->sack));
874 if (!list)
875 return NULL;
876 PyObject *iter = PyObject_GetIter(list.get());
877 return iter;
878 } CATCH_TO_PYTHON
879
880 static PyObject *
query_to_name_dict(_QueryObject * self,PyObject * unused)881 query_to_name_dict(_QueryObject *self, PyObject *unused) try
882 {
883 HyQuery query = ((_QueryObject *) self)->query;
884 Pool *pool = dnf_sack_get_pool(query->getSack());
885
886 libdnf::IdQueue samename;
887 hy_query_to_name_ordered_queue(query, &samename);
888
889 Solvable *considered;
890 Id name = 0;
891 UniquePtrPyObject list(PyList_New(0));
892 UniquePtrPyObject ret_dict(PyDict_New());
893
894 for (int i = 0; i < samename.size(); ++i) {
895 Id package_id = samename[i];
896 considered = pool->solvables + package_id;
897 if (name == 0) {
898 name = considered->name;
899 } else if (name != considered->name) {
900 PyDict_SetItemString(ret_dict.get(), pool_id2str(pool, name), list.get());
901 list.reset(PyList_New(0));
902 name = considered->name;
903 }
904 UniquePtrPyObject package(new_package(self->sack, package_id));
905 if (!package)
906 goto fail;
907
908 int rc = PyList_Append(list.get(), package.get());
909 if (rc == -1)
910 goto fail;
911 }
912 if (name)
913 PyDict_SetItemString(ret_dict.get(), pool_id2str(pool, name), list.get());
914 return ret_dict.release();
915
916 fail:
917 PyErr_SetString(PyExc_SystemError, "Unable to create name_dict");
918 return NULL;
919 } CATCH_TO_PYTHON
920
921 static PyObject *
query_to_name_arch_dict(_QueryObject * self,PyObject * unused)922 query_to_name_arch_dict(_QueryObject *self, PyObject *unused) try
923 {
924 HyQuery query = ((_QueryObject *) self)->query;
925 Pool *pool = dnf_sack_get_pool(query->getSack());
926
927 libdnf::IdQueue samename;
928
929 hy_query_to_name_arch_ordered_queue(query, &samename);
930
931 Solvable *considered;
932 Id name = 0;
933 Id arch = 0;
934 UniquePtrPyObject key(PyTuple_New(2));
935 UniquePtrPyObject list(PyList_New(0));
936 UniquePtrPyObject ret_dict(PyDict_New());
937
938 for (int i = 0; i < samename.size(); ++i) {
939 Id package_id = samename[i];
940 considered = pool->solvables + package_id;
941 if (name == 0) {
942 name = considered->name;
943 arch = considered->arch;
944 } else if ((name != considered->name) || (arch != considered->arch)) {
945 if (PyTuple_SetItem(key.get(), 0, PyString_FromString(pool_id2str(pool, name))))
946 goto fail;
947 if (PyTuple_SetItem(key.get(), 1, PyString_FromString(pool_id2str(pool, arch))))
948 goto fail;
949 PyDict_SetItem(ret_dict.get(), key.get(), list.get());
950 key.reset(PyTuple_New(2));
951 list.reset(PyList_New(0));
952 name = considered->name;
953 arch = considered->arch;
954 }
955 UniquePtrPyObject package(new_package(self->sack, package_id));
956 if (!package)
957 goto fail;
958
959 int rc = PyList_Append(list.get(), package.get());
960 if (rc == -1)
961 goto fail;
962 }
963 if (name) {
964 if (PyTuple_SetItem(key.get(), 0, PyString_FromString(pool_id2str(pool, name))))
965 goto fail;
966 if (PyTuple_SetItem(key.get(), 1, PyString_FromString(pool_id2str(pool, arch))))
967 goto fail;
968 PyDict_SetItem(ret_dict.get(), key.get(), list.get());
969 }
970
971 return ret_dict.release();
972
973 fail:
974 PyErr_SetString(PyExc_SystemError, "Unable to create name_arch_dict");
975 return NULL;
976 } CATCH_TO_PYTHON
977
978 static PyObject *
add_nevra_or_other_filter(_QueryObject * self,PyObject * args)979 add_nevra_or_other_filter(_QueryObject *self, PyObject *args) try
980 {
981 auto self_query_copy = std::unique_ptr<libdnf::Query>(new libdnf::Query(*self->query));
982
983 int arguments_count = PyTuple_Size(args);
984 if (arguments_count == 1) {
985 const char *name;
986 if (!PyArg_ParseTuple(args, "s", &name))
987 return NULL;
988 libdnf::Nevra nevra;
989 if (nevra.parse(name, HY_FORM_NEVRA))
990 self_query_copy->addFilter(&nevra, false);
991 else
992 self_query_copy->addFilter(HY_PKG_EMPTY, HY_EQ, 1);
993 } else if (arguments_count == 3) {
994 const char *name;
995 const char *evr;
996 const char *arch;
997
998 if (!PyArg_ParseTuple(args, "sss", &name, &evr, &arch))
999 return NULL;
1000 self_query_copy->addFilter(HY_PKG_NAME, HY_EQ, name);
1001 self_query_copy->addFilter(HY_PKG_EVR, HY_EQ, evr);
1002 self_query_copy->addFilter(HY_PKG_ARCH, HY_EQ, arch);
1003 } else {
1004 PyErr_SetString(PyExc_TypeError,
1005 "nevra() takes 1 (NEVRA), or 3 (name, evr, arch) str params");
1006 return NULL;
1007 }
1008 PyObject *final_query = queryToPyObject(self_query_copy.release(), self->sack, Py_TYPE(self));
1009 return final_query;
1010 } CATCH_TO_PYTHON
1011
1012 static PyObject *
add_filter_recent(_QueryObject * self,PyObject * args)1013 add_filter_recent(_QueryObject *self, PyObject *args) try
1014 {
1015 long recent;
1016 if (!PyArg_ParseTuple(args, "l", &recent))
1017 return NULL;
1018
1019 self->query->apply();
1020 HyQuery self_query_copy = new libdnf::Query(*self->query);
1021 time_t now = time(NULL);
1022 time_t recent_limit = now - (recent*86400);
1023 self_query_copy->filterRecent((recent_limit < 0) ? 0 : recent_limit);
1024 PyObject *final_query = queryToPyObject(self_query_copy, self->sack, Py_TYPE(self));
1025 return final_query;
1026 } CATCH_TO_PYTHON
1027
1028 static PyGetSetDef query_getsetters[] = {
1029 {(char*)"evaluated", (getter)get_evaluated, NULL, NULL, NULL},
1030 {NULL} /* sentinel */
1031 };
1032
1033 PySequenceMethods query_sequence = {
1034 (lenfunc)query_len, /* sq_length */
1035 (binaryfunc)q_add, /* sq_concat */
1036 0, /* sq_repeat */
1037 (ssizeargfunc) query_get_item, /* sq_item */
1038 0, /* sq_slice */
1039 0, /* sq_ass_item */
1040 0, /* sq_ass_slice */
1041 (objobjproc)query_contains, /* sq_contains */
1042 };
1043
1044 static struct PyMethodDef query_methods[] = {
1045 {"clear", (PyCFunction)clear, METH_NOARGS,
1046 NULL},
1047 {"filter", (PyCFunction)filter, METH_KEYWORDS|METH_VARARGS,
1048 NULL},
1049 {"filterm", (PyCFunction)filterm, METH_KEYWORDS|METH_VARARGS,
1050 NULL},
1051 {"run", (PyCFunction)run, METH_NOARGS,
1052 NULL},
1053 {"apply", (PyCFunction)apply, METH_NOARGS,
1054 NULL},
1055 {"available", (PyCFunction)add_available_filter, METH_NOARGS, NULL},
1056 {"downgrades", (PyCFunction)add_downgrades_filter, METH_NOARGS, NULL},
1057 {"duplicated", (PyCFunction)duplicated_filter, METH_NOARGS, NULL},
1058 {"extras", (PyCFunction)add_filter_extras, METH_NOARGS, NULL},
1059 {"installed", (PyCFunction)add_installed_filter, METH_NOARGS, NULL},
1060 {"latest", (PyCFunction)add_filter_latest, METH_VARARGS, NULL},
1061 {"union", (PyCFunction)q_union, METH_VARARGS, NULL},
1062 {"upgrades", (PyCFunction)add_upgrades_filter, METH_NOARGS, NULL},
1063 {"intersection", (PyCFunction)q_intersection, METH_VARARGS, NULL},
1064 {"difference", (PyCFunction)q_difference, METH_VARARGS, NULL},
1065 {"count", (PyCFunction)q_length, METH_NOARGS,
1066 NULL},
1067 {"get_advisory_pkgs", (PyCFunction)get_advisory_pkgs, METH_VARARGS, NULL},
1068 {"userinstalled", (PyCFunction)filter_userinstalled, METH_KEYWORDS|METH_VARARGS, NULL},
1069 {"_na_dict", (PyCFunction)query_to_name_arch_dict, METH_NOARGS, NULL},
1070 {"_name_dict", (PyCFunction)query_to_name_dict, METH_NOARGS, NULL},
1071 {"_nevra", (PyCFunction)add_nevra_or_other_filter, METH_VARARGS, NULL},
1072 {"_recent", (PyCFunction)add_filter_recent, METH_VARARGS, NULL},
1073 {"_unneeded", (PyCFunction)filter_unneeded, METH_KEYWORDS|METH_VARARGS, NULL},
1074 {"_safe_to_remove", (PyCFunction)filter_safe_to_remove, METH_KEYWORDS|METH_VARARGS, NULL},
1075 {NULL} /* sentinel */
1076 };
1077
1078 PyTypeObject query_Type = {
1079 PyVarObject_HEAD_INIT(NULL, 0)
1080 "_hawkey.Query", /*tp_name*/
1081 sizeof(_QueryObject), /*tp_basicsize*/
1082 0, /*tp_itemsize*/
1083 (destructor) query_dealloc, /*tp_dealloc*/
1084 0, /*tp_print*/
1085 0, /*tp_getattr*/
1086 0, /*tp_setattr*/
1087 0, /*tp_compare*/
1088 0, /*tp_repr*/
1089 0, /*tp_as_number*/
1090 &query_sequence, /*tp_as_sequence*/
1091 0, /*tp_as_mapping*/
1092 0, /*tp_hash */
1093 0, /*tp_call*/
1094 0, /*tp_str*/
1095 0, /*tp_getattro*/
1096 0, /*tp_setattro*/
1097 0, /*tp_as_buffer*/
1098 Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, /*tp_flags*/
1099 "Query object", /* tp_doc */
1100 0, /* tp_traverse */
1101 0, /* tp_clear */
1102 0, /* tp_richcompare */
1103 0, /* tp_weaklistoffset */
1104 query_iter, /* tp_iter */
1105 0, /* tp_iternext */
1106 query_methods, /* tp_methods */
1107 0, /* tp_members */
1108 query_getsetters, /* tp_getset */
1109 0, /* tp_base */
1110 0, /* tp_dict */
1111 0, /* tp_descr_get */
1112 0, /* tp_descr_set */
1113 0, /* tp_dictoffset */
1114 (initproc)query_init, /* tp_init */
1115 0, /* tp_alloc */
1116 query_new, /* tp_new */
1117 0, /* tp_free */
1118 0, /* tp_is_gc */
1119 };
1120