1 /*
2  * Copyright (C) 2012-2013 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 <glib.h>
23 #include <structmember.h>
24 #include <stddef.h>
25 #include <solv/util.h>
26 
27 #include "dnf-types.h"
28 #include "dnf-goal.h"
29 
30 #include "exception-py.hpp"
31 #include "goal-py.hpp"
32 #include "hy-goal-private.hpp"
33 #include "iutil-py.hpp"
34 #include "package-py.hpp"
35 #include "selector-py.hpp"
36 #include "sack-py.hpp"
37 #include "query-py.hpp"
38 #include "pycomp.hpp"
39 #include "goal/Goal.hpp"
40 #include "sack/query.hpp"
41 #include "sack/packageset.hpp"
42 
43 #define BLOCK_SIZE 15
44 
45 typedef struct {
46     PyObject_HEAD
47     HyGoal goal;
48     PyObject *sack;
49 } _GoalObject;
50 
51 static int
args_pkg_sltr_check(DnfPackage * pkg,HySelector sltr)52 args_pkg_sltr_check(DnfPackage *pkg, HySelector sltr)
53 {
54     if (!(pkg || sltr)) {
55         PyErr_SetString(PyExc_ValueError,
56                         "Requires a Package or a Selector argument.");
57         return 0;
58     }
59     if (pkg && sltr) {
60         PyErr_SetString(PyExc_ValueError,
61                         "Does not accept both Package and Selector arguments.");
62         return 0;
63     }
64     return 1;
65 }
66 
67 static int
args_pkg_sltr_parse(PyObject * args,PyObject * kwds,DnfPackage ** pkg,HySelector * sltr,int * flags,int flag_mask)68 args_pkg_sltr_parse(PyObject *args, PyObject *kwds,
69                      DnfPackage **pkg, HySelector *sltr, int *flags, int flag_mask)
70 {
71     const char *kwlist[] = {"package", "select", "clean_deps", "check_installed",
72                       "optional", NULL};
73     int clean_deps = 0, check_installed = 0, optional = 0;
74     if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O&O&iii", (char**) kwlist,
75                                      package_converter, pkg,
76                                      selector_converter, sltr,
77                                      &clean_deps, &check_installed,
78                                      &optional))
79         return 0;
80     if (!args_pkg_sltr_check(*pkg, *sltr))
81         return 0;
82     if (clean_deps) {
83         if (!(flag_mask & HY_CLEAN_DEPS)) {
84             PyErr_SetString(PyExc_ValueError,
85                             "Does not accept clean_deps keyword") ;
86             return 0;
87         }
88         *flags |= HY_CLEAN_DEPS;
89     }
90     if (check_installed) {
91         if  (!(flag_mask & HY_CHECK_INSTALLED)) {
92             PyErr_SetString(PyExc_ValueError,
93                             "Does not accept check_installed keyword") ;
94             return 0;
95         }
96         *flags |= HY_CHECK_INSTALLED;
97     }
98     if (optional) {
99         if  (!(flag_mask & HY_WEAK_SOLV)) {
100             PyErr_SetString(PyExc_ValueError,
101                             "Does not accept optional keyword");
102             return 0;
103         }
104         *flags |= HY_WEAK_SOLV;
105     }
106     return 1;
107 }
108 
109 static int
args_run_parse(PyObject * args,PyObject * kwds,int * flags,PyObject ** callback_p)110 args_run_parse(PyObject *args, PyObject *kwds, int *flags, PyObject **callback_p)
111 {
112     const char *kwlist[] = {"callback", "allow_uninstall", "force_best", "verify",
113         "ignore_weak_deps", "ignore_weak", NULL};
114     int ignore_weak = 0;
115     int ignore_weak_deps = 0;
116     int allow_uninstall = 0;
117     int force_best = 0;
118     int verify = 0;
119     PyObject *callback = NULL;
120 
121     if (!PyArg_ParseTupleAndKeywords(args, kwds, "|Oiiiii", (char**) kwlist,
122                                      &callback, &allow_uninstall, &force_best,
123                                      &verify, &ignore_weak_deps, &ignore_weak))
124         return 0;
125 
126     if (callback) {
127         if (!callback_p) {
128             PyErr_SetString(PyExc_ValueError,
129                             "Does not accept a callback argument.");
130             return 0;
131         }
132         if (!PyCallable_Check(callback)) {
133             PyErr_SetString(PyExc_ValueError, "Must be a callable object.");
134             return 0;
135         }
136         *callback_p = callback;
137     } else if (callback_p) {
138         PyErr_SetString(PyExc_ValueError, "Expected a callback argument.");
139         return 0;
140     }
141 
142     if (allow_uninstall)
143         *flags |= DNF_ALLOW_UNINSTALL;
144     if (force_best)
145         *flags |= DNF_FORCE_BEST;
146     if (verify)
147         *flags |= DNF_VERIFY;
148     if (ignore_weak_deps)
149         *flags |= DNF_IGNORE_WEAK_DEPS;
150     if (ignore_weak)
151         *flags |= DNF_IGNORE_WEAK;
152     return 1;
153 }
154 
155 static PyObject *
op_ret2exc(int ret)156 op_ret2exc(int ret)
157 {
158     if (!ret)
159         Py_RETURN_NONE;
160 
161     switch (ret) {
162     case DNF_ERROR_BAD_SELECTOR:
163         PyErr_SetString(HyExc_Value,
164                         "Ill-formed Selector used for the operation.");
165         return NULL;
166     case DNF_ERROR_INVALID_ARCHITECTURE:
167         PyErr_SetString(HyExc_Arch, "Used arch is unknown.");
168         return NULL;
169     case DNF_ERROR_PACKAGE_NOT_FOUND:
170         PyErr_SetString(HyExc_Validation, "The validation check has failed.");
171         return NULL;
172     default:
173         PyErr_SetString(HyExc_Exception, "Goal operation failed.");
174         return NULL;
175     }
176 }
177 
178 /* functions on the type */
179 
180 static PyObject *
goal_new(PyTypeObject * type,PyObject * args,PyObject * kwds)181 goal_new(PyTypeObject *type, PyObject *args, PyObject *kwds) try
182 {
183     _GoalObject *self = (_GoalObject*)type->tp_alloc(type, 0);
184     if (self) {
185         self->goal = NULL;
186         self->sack = NULL;
187     }
188     return (PyObject*)self;
189 } CATCH_TO_PYTHON
190 
191 static void
goal_dealloc(_GoalObject * self)192 goal_dealloc(_GoalObject *self)
193 {
194     if (self->goal)
195         hy_goal_free(self->goal);
196 
197     Py_XDECREF(self->sack);
198     Py_TYPE(self)->tp_free(self);
199 }
200 
201 static int
goal_init(_GoalObject * self,PyObject * args,PyObject * kwds)202 goal_init(_GoalObject *self, PyObject *args, PyObject *kwds) try
203 {
204     PyObject *sack;
205     DnfSack *csack;
206 
207     if (!PyArg_ParseTuple(args, "O!", &sack_Type, &sack))
208         return -1;
209     csack = sackFromPyObject(sack);
210     if (csack == NULL)
211         return -1;
212     self->sack = sack;
213     Py_INCREF(self->sack); // sack has to kept around until we are
214     self->goal = hy_goal_create(csack);
215     return 0;
216 } CATCH_TO_PYTHON_INT
217 
218 /* object methods */
219 
220 static PyObject *
distupgrade_all(_GoalObject * self,PyObject * unused)221 distupgrade_all(_GoalObject *self, PyObject *unused) try
222 {
223     int ret = hy_goal_distupgrade_all(self->goal);
224     return op_ret2exc(ret);
225 } CATCH_TO_PYTHON
226 
227 static PyObject *
distupgrade(_GoalObject * self,PyObject * args,PyObject * kwds)228 distupgrade(_GoalObject *self, PyObject *args, PyObject *kwds) try
229 {
230     DnfPackage *pkg = NULL;
231     HySelector sltr = NULL;
232     if (!args_pkg_sltr_parse(args, kwds, &pkg, &sltr, NULL, 0))
233         return NULL;
234 
235     int ret = pkg ? hy_goal_distupgrade(self->goal, pkg) :
236         hy_goal_distupgrade_selector(self->goal, sltr);
237     return op_ret2exc(ret);
238 } CATCH_TO_PYTHON
239 
240 static PyObject *
get_protect_running_kernel(_GoalObject * self,void * unused)241 get_protect_running_kernel(_GoalObject *self, void * unused) try
242 {
243     return PyBool_FromLong(self->goal->get_protect_running_kernel());
244 } CATCH_TO_PYTHON
245 
246 static int
set_protect_running_kernel(_GoalObject * self,PyObject * value,void * closure)247 set_protect_running_kernel(_GoalObject *self, PyObject * value, void * closure) try
248 {
249     if(!PyBool_Check(value)) {
250         PyErr_SetString(PyExc_TypeError, "Only Bool Type accepted");
251         return -1;
252     }
253     int c_value = PyObject_IsTrue(value);
254     self->goal->set_protect_running_kernel(c_value);
255     return 0;
256 } CATCH_TO_PYTHON_INT
257 
258 static PyObject *
erase(_GoalObject * self,PyObject * args,PyObject * kwds)259 erase(_GoalObject *self, PyObject *args, PyObject *kwds) try
260 {
261     DnfPackage *pkg = NULL;
262     HySelector sltr = NULL;
263     int flags = 0;
264     if (!args_pkg_sltr_parse(args, kwds, &pkg, &sltr, &flags, HY_CLEAN_DEPS))
265         return NULL;
266 
267     int ret = pkg ? hy_goal_erase_flags(self->goal, pkg, flags) :
268         hy_goal_erase_selector_flags(self->goal, sltr, flags);
269     return op_ret2exc(ret);
270 } CATCH_TO_PYTHON
271 
272 static PyObject *
install(_GoalObject * self,PyObject * args,PyObject * kwds)273 install(_GoalObject *self, PyObject *args, PyObject *kwds) try
274 {
275     DnfPackage *pkg = NULL;
276     HySelector sltr = NULL;
277     int flags = 0;
278     g_autoptr(GError) error = NULL;
279     if (!args_pkg_sltr_parse(args, kwds, &pkg, &sltr, &flags, HY_WEAK_SOLV))
280         return NULL;
281 
282     if (flags & HY_WEAK_SOLV) {
283         if (pkg) {
284             hy_goal_install_optional(self->goal, pkg);
285         } else {
286             hy_goal_install_selector_optional(self->goal, sltr, &error);
287         }
288     } else {
289         if (pkg) {
290             hy_goal_install(self->goal, pkg);
291         } else {
292             hy_goal_install_selector(self->goal, sltr, &error);
293         }
294     }
295     return op_error2exc(error);
296 } CATCH_TO_PYTHON
297 
298 static PyObject *
upgrade(_GoalObject * self,PyObject * args,PyObject * kwds)299 upgrade(_GoalObject *self, PyObject *args, PyObject *kwds) try
300 {
301     DnfPackage *pkg = NULL;
302     HySelector sltr = NULL;
303 
304     if (!args_pkg_sltr_parse(args, kwds, &pkg, &sltr, NULL, 0))
305         return NULL;
306     if (pkg) {
307         int ret = hy_goal_upgrade_to(self->goal, pkg);
308         return op_ret2exc(ret);
309     }
310     int ret = hy_goal_upgrade_selector(self->goal, sltr);
311     return op_ret2exc(ret);
312 } CATCH_TO_PYTHON
313 
314 static PyObject *
upgrade_all(_GoalObject * self,PyObject * unused)315 upgrade_all(_GoalObject *self, PyObject *unused) try
316 {
317     int ret = hy_goal_upgrade_all(self->goal);
318     return op_ret2exc(ret);
319 } CATCH_TO_PYTHON
320 
321 static PyObject *
userinstalled(_GoalObject * self,PyObject * obj)322 userinstalled(_GoalObject *self, PyObject *obj) try
323 {
324     if (queryObject_Check(obj)) {
325         HyQuery query = queryFromPyObject(obj);
326         if (query == NULL)
327             return NULL;
328         self->goal->userInstalled(*query->getResultPset());
329         Py_RETURN_FALSE;
330     }
331     DnfPackage *cpkg = packageFromPyObject(obj);
332     int ret;
333 
334     if (cpkg == NULL)
335         return NULL;
336     ret = hy_goal_userinstalled(self->goal, cpkg);
337     if (!ret)
338         Py_RETURN_TRUE;
339     Py_RETURN_FALSE;
340 } CATCH_TO_PYTHON
341 
342 static PyObject *
get_actions(_GoalObject * self,void * unused)343 get_actions(_GoalObject *self, void *unused) try
344 {
345     HyGoal goal = self->goal;
346     return PyLong_FromLong(goal->getActions());
347 } CATCH_TO_PYTHON
348 
349 static PyObject *
req_has_distupgrade_all(_GoalObject * self,PyObject * unused)350 req_has_distupgrade_all(_GoalObject *self, PyObject *unused) try
351 {
352     return PyBool_FromLong(hy_goal_has_actions(self->goal, DNF_DISTUPGRADE_ALL));
353 } CATCH_TO_PYTHON
354 
355 static PyObject *
req_has_erase(_GoalObject * self,PyObject * unused)356 req_has_erase(_GoalObject *self, PyObject *unused) try
357 {
358     return PyBool_FromLong(hy_goal_has_actions(self->goal, DNF_ERASE));
359 } CATCH_TO_PYTHON
360 
361 static PyObject *
req_length(_GoalObject * self,PyObject * unused)362 req_length(_GoalObject *self, PyObject *unused) try
363 {
364     return PyLong_FromLong(hy_goal_req_length(self->goal));
365 } CATCH_TO_PYTHON
366 
367 static PyObject *
add_protected(_GoalObject * self,PyObject * seq)368 add_protected(_GoalObject *self, PyObject *seq) try
369 {
370     HyGoal goal = self->goal;
371     auto pset = pyseq_to_packageset(seq, hy_goal_get_sack(goal));
372     if (!pset)
373         return NULL;
374     dnf_goal_add_protected(goal, pset.get());
375     Py_RETURN_NONE;
376 } CATCH_TO_PYTHON
377 
378 static PyObject *
run(_GoalObject * self,PyObject * args,PyObject * kwds)379 run(_GoalObject *self, PyObject *args, PyObject *kwds) try
380 {
381     int flags = 0;
382     if (!args_run_parse(args, kwds, &flags, NULL))
383         return NULL;
384 
385     int ret = hy_goal_run_flags(self->goal, static_cast<DnfGoalActions>(flags));
386     if (!ret)
387         Py_RETURN_TRUE;
388     Py_RETURN_FALSE;
389 } CATCH_TO_PYTHON
390 
391 static PyObject *
count_problems(_GoalObject * self,PyObject * unused)392 count_problems(_GoalObject *self, PyObject *unused) try
393 {
394     return PyLong_FromLong(hy_goal_count_problems(self->goal));
395 } CATCH_TO_PYTHON
396 
397 /**
398  * Reports problems described in strings.
399  *
400  * Returns Python list with Python list of strings for each problem or empty Python list if no
401  * problem or NULL in case of error.
402  */
403 static PyObject *
problem_rules(_GoalObject * self,PyObject * unused)404 problem_rules(_GoalObject *self, PyObject *unused) try
405 {
406     auto allProblems = self->goal->describeAllProblemRules(true);
407     return problemRulesPyConverter(allProblems);
408 } CATCH_TO_PYTHON
409 
410 /**
411  * Reports packages that has a conflict
412  *
413  * Returns Python list with package objects that have a conflict.
414  */
415 static PyObject *
problem_conflicts(_GoalObject * self,PyObject * args,PyObject * kwds)416 problem_conflicts(_GoalObject *self, PyObject *args, PyObject *kwds) try
417 {
418     const char *kwlist[] = {"available", NULL};
419     int available = 0;
420 
421     if (!PyArg_ParseTupleAndKeywords(args, kwds, "|i", (char**) kwlist, &available))
422         return 0;
423 
424     DnfPackageState pkg_type = DNF_PACKAGE_STATE_ALL;
425     if (available)
426         pkg_type = DNF_PACKAGE_STATE_AVAILABLE;
427     auto pset = self->goal->listConflictPkgs(pkg_type);
428     return packageset_to_pylist(pset.get(), self->sack);
429 } CATCH_TO_PYTHON
430 
431 /**
432  * Reports packages that has a conflict
433  *
434  * Returns Python list with package objects that have a conflict.
435  */
436 static PyObject *
problem_broken_dependency(_GoalObject * self,PyObject * args,PyObject * kwds)437 problem_broken_dependency(_GoalObject *self, PyObject *args, PyObject *kwds) try
438 {
439     const char *kwlist[] = {"available", NULL};
440     int available = 0;
441 
442     if (!PyArg_ParseTupleAndKeywords(args, kwds, "|i", (char**) kwlist, &available))
443         return 0;
444 
445     DnfPackageState pkg_type = DNF_PACKAGE_STATE_ALL;
446 
447     if (available)
448         pkg_type = DNF_PACKAGE_STATE_AVAILABLE;
449     auto pset = self->goal->listBrokenDependencyPkgs(pkg_type);
450 
451     return packageset_to_pylist(pset.get(), self->sack);
452 } CATCH_TO_PYTHON
453 
454 static PyObject *
log_decisions(_GoalObject * self,PyObject * unused)455 log_decisions(_GoalObject *self, PyObject *unused) try
456 {
457     if (hy_goal_log_decisions(self->goal))
458         PyErr_SetString(PyExc_ValueError, "log_decisions() failed.");
459     Py_RETURN_NONE;
460 } CATCH_TO_PYTHON
461 
462 static PyObject *
write_debugdata(_GoalObject * self,PyObject * dir_str)463 write_debugdata(_GoalObject *self, PyObject *dir_str) try
464 {
465     g_autoptr(GError) error = NULL;
466     PycompString dir(dir_str);
467 
468     if (!dir.getCString())
469         return NULL;
470 
471     gboolean ret = hy_goal_write_debugdata(self->goal, dir.getCString(), &error);
472     if (!ret) {
473         op_error2exc(error);
474         return NULL;
475     }
476     Py_RETURN_NONE;
477 } CATCH_TO_PYTHON
478 
479 static PyObject *
list_generic(_GoalObject * self,GPtrArray * (* func)(HyGoal,GError **))480 list_generic(_GoalObject *self, GPtrArray *(*func)(HyGoal, GError **))
481 {
482     g_autoptr(GError) error = NULL;
483     GPtrArray *plist = func(self->goal, &error);
484     PyObject *list;
485 
486     if (!plist) {
487         switch (error->code) {
488         case DNF_ERROR_INTERNAL_ERROR:
489             PyErr_SetString(HyExc_Value, "Goal has not been run yet.");
490             break;
491         case DNF_ERROR_NO_SOLUTION:
492             PyErr_SetString(HyExc_Runtime, "Goal could not find a solution.");
493             break;
494         default:
495             assert(0);
496         }
497         return NULL;
498     }
499     list = packagelist_to_pylist(plist, self->sack);
500     g_ptr_array_unref(plist);
501     return list;
502 }
503 
504 static PyObject *
list_erasures(_GoalObject * self,PyObject * unused)505 list_erasures(_GoalObject *self, PyObject *unused) try
506 {
507     return list_generic(self, hy_goal_list_erasures);
508 } CATCH_TO_PYTHON
509 
510 static PyObject *
list_installs(_GoalObject * self,PyObject * unused)511 list_installs(_GoalObject *self, PyObject *unused) try
512 {
513     return list_generic(self, hy_goal_list_installs);
514 } CATCH_TO_PYTHON
515 
516 static PyObject *
list_obsoleted(_GoalObject * self,PyObject * unused)517 list_obsoleted(_GoalObject *self, PyObject *unused) try
518 {
519     return list_generic(self, hy_goal_list_obsoleted);
520 } CATCH_TO_PYTHON
521 
522 static PyObject *
list_reinstalls(_GoalObject * self,PyObject * unused)523 list_reinstalls(_GoalObject *self, PyObject *unused) try
524 {
525     return list_generic(self, hy_goal_list_reinstalls);
526 } CATCH_TO_PYTHON
527 
528 static PyObject *
list_unneeded(_GoalObject * self,PyObject * unused)529 list_unneeded(_GoalObject *self, PyObject *unused) try
530 {
531     return list_generic(self, hy_goal_list_unneeded);
532 } CATCH_TO_PYTHON
533 
534 static PyObject *
list_suggested(_GoalObject * self,PyObject * unused)535 list_suggested(_GoalObject *self, PyObject *unused) try
536 {
537     return list_generic(self, hy_goal_list_suggested);
538 } CATCH_TO_PYTHON
539 
540 static PyObject *
list_downgrades(_GoalObject * self,PyObject * unused)541 list_downgrades(_GoalObject *self, PyObject *unused) try
542 {
543     return list_generic(self, hy_goal_list_downgrades);
544 } CATCH_TO_PYTHON
545 
546 static PyObject *
list_upgrades(_GoalObject * self,PyObject * unused)547 list_upgrades(_GoalObject *self, PyObject *unused) try
548 {
549     return list_generic(self, hy_goal_list_upgrades);
550 } CATCH_TO_PYTHON
551 
552 static PyObject *
obsoleted_by_package(_GoalObject * self,PyObject * pkg)553 obsoleted_by_package(_GoalObject *self, PyObject *pkg) try
554 {
555     DnfPackage *cpkg = packageFromPyObject(pkg);
556 
557     if (cpkg == NULL)
558         return NULL;
559     GPtrArray *plist = hy_goal_list_obsoleted_by_package(self->goal, cpkg);
560     PyObject *list = packagelist_to_pylist(plist, self->sack);
561     g_ptr_array_unref(plist);
562     return list;
563 } CATCH_TO_PYTHON
564 
565 static PyObject *
get_reason(_GoalObject * self,PyObject * pkg)566 get_reason(_GoalObject *self, PyObject *pkg) try
567 {
568     DnfPackage *cpkg = packageFromPyObject(pkg);
569 
570     if (cpkg == NULL)
571         return NULL;
572     int reason = hy_goal_get_reason(self->goal, cpkg);
573     return PyLong_FromLong(reason);
574 } CATCH_TO_PYTHON
575 
576 static PyObject *
goalToPyObject(HyGoal goal,PyObject * sack)577 goalToPyObject(HyGoal goal, PyObject *sack)
578 {
579     _GoalObject *self = (_GoalObject *)goal_Type.tp_alloc(&goal_Type, 0);
580     if (self) {
581         self->goal = goal;
582         self->sack = sack;
583         Py_INCREF(sack);
584     }
585     return (PyObject *)self;
586 }
587 
588 static PyObject *
deepcopy(_GoalObject * self,PyObject * args,PyObject * kwds)589 deepcopy(_GoalObject *self, PyObject *args, PyObject *kwds) try
590 {
591     HyGoal goal = hy_goal_clone(self->goal);
592     return goalToPyObject(goal, self->sack);
593 } CATCH_TO_PYTHON
594 
595 static struct PyMethodDef goal_methods[] = {
596     {"__deepcopy__", (PyCFunction)deepcopy, METH_KEYWORDS|METH_VARARGS,
597      NULL},
598     {"add_protected", (PyCFunction)add_protected, METH_O,
599      NULL},
600     {"distupgrade_all",        (PyCFunction)distupgrade_all,        METH_NOARGS,        NULL},
601     {"distupgrade",                (PyCFunction)distupgrade,
602      METH_VARARGS | METH_KEYWORDS, NULL},
603     {"erase",                (PyCFunction)erase,
604      METH_VARARGS | METH_KEYWORDS, NULL},
605     {"install",                (PyCFunction)install,
606      METH_VARARGS | METH_KEYWORDS, NULL},
607     {"upgrade",                (PyCFunction)upgrade,
608      METH_VARARGS | METH_KEYWORDS, NULL},
609     {"upgrade_all",        (PyCFunction)upgrade_all,        METH_NOARGS,        NULL},
610     {"userinstalled",        (PyCFunction)userinstalled,        METH_O,                NULL},
611     // deprecated in 0.5.9, will be removed in 1.0.0
612     // use goal.actions & hawkey.DISTUPGRADE_ALL instead
613     {"req_has_distupgrade_all",        (PyCFunction)req_has_distupgrade_all,
614      METH_NOARGS,        NULL},
615     // deprecated in 0.5.9, will be removed in 1.0.0
616     // use goal.actions | hawkey.ERASE instead
617     {"req_has_erase",        (PyCFunction)req_has_erase,        METH_NOARGS,        NULL},
618     {"req_length",        (PyCFunction)req_length,        METH_NOARGS,        NULL},
619     {"run",                (PyCFunction)run,
620      METH_VARARGS | METH_KEYWORDS, NULL},
621     {"count_problems",        (PyCFunction)count_problems,        METH_NOARGS,        NULL},
622     {"problem_conflicts",(PyCFunction)problem_conflicts,        METH_VARARGS | METH_KEYWORDS,                NULL},
623     {"problem_broken_dependency",(PyCFunction)problem_broken_dependency,        METH_VARARGS | METH_KEYWORDS,                NULL},
624     {"problem_rules", (PyCFunction)problem_rules,        METH_NOARGS,                NULL},
625     {"log_decisions",   (PyCFunction)log_decisions,        METH_NOARGS,        NULL},
626     {"write_debugdata", (PyCFunction)write_debugdata,        METH_O,                NULL},
627     {"list_erasures",        (PyCFunction)list_erasures,        METH_NOARGS,        NULL},
628     {"list_installs",        (PyCFunction)list_installs,        METH_NOARGS,        NULL},
629     {"list_obsoleted",        (PyCFunction)list_obsoleted,        METH_NOARGS,        NULL},
630     {"list_reinstalls",        (PyCFunction)list_reinstalls,        METH_NOARGS,        NULL},
631     {"list_unneeded",        (PyCFunction)list_unneeded,        METH_NOARGS,        NULL},
632     {"list_suggested",       (PyCFunction)list_suggested,       METH_NOARGS,        NULL},
633     {"list_downgrades",        (PyCFunction)list_downgrades,        METH_NOARGS,        NULL},
634     {"list_upgrades",        (PyCFunction)list_upgrades,        METH_NOARGS,        NULL},
635     {"obsoleted_by_package",(PyCFunction)obsoleted_by_package,
636      METH_O, NULL},
637     {"get_reason",        (PyCFunction)get_reason,        METH_O,                NULL},
638     {NULL}                      /* sentinel */
639 };
640 
641 static struct PyMemberDef goal_members[] = {
642     {(char*)"sack", T_OBJECT, offsetof(_GoalObject, sack), READONLY, NULL},
643     {NULL}
644 };
645 
646 static PyGetSetDef goal_getsetters[] = {
647     {(char*)"actions",        (getter)get_actions, NULL, NULL, NULL},
648     {(char*)"protect_running_kernel", (getter)get_protect_running_kernel,
649         (setter)set_protect_running_kernel, NULL, NULL},
650     {NULL}                /* sentinel */
651 };
652 
653 PyTypeObject goal_Type = {
654     PyVarObject_HEAD_INIT(NULL, 0)
655     "_hawkey.Goal",                /*tp_name*/
656     sizeof(_GoalObject),        /*tp_basicsize*/
657     0,                                /*tp_itemsize*/
658     (destructor) goal_dealloc,  /*tp_dealloc*/
659     0,                                /*tp_print*/
660     0,                                /*tp_getattr*/
661     0,                                /*tp_setattr*/
662     0,                                /*tp_compare*/
663     0,                                /*tp_repr*/
664     0,                                /*tp_as_number*/
665     0,                                /*tp_as_sequence*/
666     0,                                /*tp_as_mapping*/
667     0,                                /*tp_hash */
668     0,                                /*tp_call*/
669     0,                                /*tp_str*/
670     PyObject_GenericGetAttr,        /*tp_getattro*/
671     0,                                /*tp_setattro*/
672     0,                                /*tp_as_buffer*/
673     Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE,        /*tp_flags*/
674     "Goal object",                /* tp_doc */
675     0,                                /* tp_traverse */
676     0,                                /* tp_clear */
677     0,                                /* tp_richcompare */
678     0,                                /* tp_weaklistoffset */
679     PyObject_SelfIter,                /* tp_iter */
680     0,                                 /* tp_iternext */
681     goal_methods,                /* tp_methods */
682     goal_members,                /* tp_members */
683     goal_getsetters,                                /* tp_getset */
684     0,                                /* tp_base */
685     0,                                /* tp_dict */
686     0,                                /* tp_descr_get */
687     0,                                /* tp_descr_set */
688     0,                                /* tp_dictoffset */
689     (initproc)goal_init,        /* tp_init */
690     0,                                /* tp_alloc */
691     goal_new,                        /* tp_new */
692     0,                                /* tp_free */
693     0,                                /* tp_is_gc */
694 };
695