/* * Copyright (C) 2012-2013 Red Hat, Inc. * * Licensed under the GNU Lesser General Public License Version 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include #include #include "dnf-types.h" #include "dnf-goal.h" #include "exception-py.hpp" #include "goal-py.hpp" #include "hy-goal-private.hpp" #include "iutil-py.hpp" #include "package-py.hpp" #include "selector-py.hpp" #include "sack-py.hpp" #include "query-py.hpp" #include "pycomp.hpp" #include "goal/Goal.hpp" #include "sack/query.hpp" #include "sack/packageset.hpp" #define BLOCK_SIZE 15 typedef struct { PyObject_HEAD HyGoal goal; PyObject *sack; } _GoalObject; static int args_pkg_sltr_check(DnfPackage *pkg, HySelector sltr) { if (!(pkg || sltr)) { PyErr_SetString(PyExc_ValueError, "Requires a Package or a Selector argument."); return 0; } if (pkg && sltr) { PyErr_SetString(PyExc_ValueError, "Does not accept both Package and Selector arguments."); return 0; } return 1; } static int args_pkg_sltr_parse(PyObject *args, PyObject *kwds, DnfPackage **pkg, HySelector *sltr, int *flags, int flag_mask) { const char *kwlist[] = {"package", "select", "clean_deps", "check_installed", "optional", NULL}; int clean_deps = 0, check_installed = 0, optional = 0; if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O&O&iii", (char**) kwlist, package_converter, pkg, selector_converter, sltr, &clean_deps, &check_installed, &optional)) return 0; if (!args_pkg_sltr_check(*pkg, *sltr)) return 0; if (clean_deps) { if (!(flag_mask & HY_CLEAN_DEPS)) { PyErr_SetString(PyExc_ValueError, "Does not accept clean_deps keyword") ; return 0; } *flags |= HY_CLEAN_DEPS; } if (check_installed) { if (!(flag_mask & HY_CHECK_INSTALLED)) { PyErr_SetString(PyExc_ValueError, "Does not accept check_installed keyword") ; return 0; } *flags |= HY_CHECK_INSTALLED; } if (optional) { if (!(flag_mask & HY_WEAK_SOLV)) { PyErr_SetString(PyExc_ValueError, "Does not accept optional keyword"); return 0; } *flags |= HY_WEAK_SOLV; } return 1; } static int args_run_parse(PyObject *args, PyObject *kwds, int *flags, PyObject **callback_p) { const char *kwlist[] = {"callback", "allow_uninstall", "force_best", "verify", "ignore_weak_deps", "ignore_weak", NULL}; int ignore_weak = 0; int ignore_weak_deps = 0; int allow_uninstall = 0; int force_best = 0; int verify = 0; PyObject *callback = NULL; if (!PyArg_ParseTupleAndKeywords(args, kwds, "|Oiiiii", (char**) kwlist, &callback, &allow_uninstall, &force_best, &verify, &ignore_weak_deps, &ignore_weak)) return 0; if (callback) { if (!callback_p) { PyErr_SetString(PyExc_ValueError, "Does not accept a callback argument."); return 0; } if (!PyCallable_Check(callback)) { PyErr_SetString(PyExc_ValueError, "Must be a callable object."); return 0; } *callback_p = callback; } else if (callback_p) { PyErr_SetString(PyExc_ValueError, "Expected a callback argument."); return 0; } if (allow_uninstall) *flags |= DNF_ALLOW_UNINSTALL; if (force_best) *flags |= DNF_FORCE_BEST; if (verify) *flags |= DNF_VERIFY; if (ignore_weak_deps) *flags |= DNF_IGNORE_WEAK_DEPS; if (ignore_weak) *flags |= DNF_IGNORE_WEAK; return 1; } static PyObject * op_ret2exc(int ret) { if (!ret) Py_RETURN_NONE; switch (ret) { case DNF_ERROR_BAD_SELECTOR: PyErr_SetString(HyExc_Value, "Ill-formed Selector used for the operation."); return NULL; case DNF_ERROR_INVALID_ARCHITECTURE: PyErr_SetString(HyExc_Arch, "Used arch is unknown."); return NULL; case DNF_ERROR_PACKAGE_NOT_FOUND: PyErr_SetString(HyExc_Validation, "The validation check has failed."); return NULL; default: PyErr_SetString(HyExc_Exception, "Goal operation failed."); return NULL; } } /* functions on the type */ static PyObject * goal_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { _GoalObject *self = (_GoalObject*)type->tp_alloc(type, 0); if (self) { self->goal = NULL; self->sack = NULL; } return (PyObject*)self; } static void goal_dealloc(_GoalObject *self) { if (self->goal) hy_goal_free(self->goal); Py_XDECREF(self->sack); Py_TYPE(self)->tp_free(self); } static int goal_init(_GoalObject *self, PyObject *args, PyObject *kwds) { PyObject *sack; DnfSack *csack; if (!PyArg_ParseTuple(args, "O!", &sack_Type, &sack)) return -1; csack = sackFromPyObject(sack); if (csack == NULL) return -1; self->sack = sack; Py_INCREF(self->sack); // sack has to kept around until we are self->goal = hy_goal_create(csack); return 0; } /* object methods */ static PyObject * distupgrade_all(_GoalObject *self, PyObject *unused) { int ret = hy_goal_distupgrade_all(self->goal); return op_ret2exc(ret); } static PyObject * distupgrade(_GoalObject *self, PyObject *args, PyObject *kwds) { DnfPackage *pkg = NULL; HySelector sltr = NULL; if (!args_pkg_sltr_parse(args, kwds, &pkg, &sltr, NULL, 0)) return NULL; int ret = pkg ? hy_goal_distupgrade(self->goal, pkg) : hy_goal_distupgrade_selector(self->goal, sltr); return op_ret2exc(ret); } static PyObject * erase(_GoalObject *self, PyObject *args, PyObject *kwds) { DnfPackage *pkg = NULL; HySelector sltr = NULL; int flags = 0; if (!args_pkg_sltr_parse(args, kwds, &pkg, &sltr, &flags, HY_CLEAN_DEPS)) return NULL; int ret = pkg ? hy_goal_erase_flags(self->goal, pkg, flags) : hy_goal_erase_selector_flags(self->goal, sltr, flags); return op_ret2exc(ret); } static PyObject * install(_GoalObject *self, PyObject *args, PyObject *kwds) { DnfPackage *pkg = NULL; HySelector sltr = NULL; int flags = 0; g_autoptr(GError) error = NULL; if (!args_pkg_sltr_parse(args, kwds, &pkg, &sltr, &flags, HY_WEAK_SOLV)) return NULL; if (flags & HY_WEAK_SOLV) { if (pkg) { hy_goal_install_optional(self->goal, pkg); } else { hy_goal_install_selector_optional(self->goal, sltr, &error); } } else { if (pkg) { hy_goal_install(self->goal, pkg); } else { hy_goal_install_selector(self->goal, sltr, &error); } } return op_error2exc(error); } static PyObject * upgrade(_GoalObject *self, PyObject *args, PyObject *kwds) { DnfPackage *pkg = NULL; HySelector sltr = NULL; if (!args_pkg_sltr_parse(args, kwds, &pkg, &sltr, NULL, 0)) return NULL; if (pkg) { int ret = hy_goal_upgrade_to(self->goal, pkg); return op_ret2exc(ret); } int ret = hy_goal_upgrade_selector(self->goal, sltr); return op_ret2exc(ret); } static PyObject * upgrade_all(_GoalObject *self, PyObject *unused) { int ret = hy_goal_upgrade_all(self->goal); return op_ret2exc(ret); } static PyObject * userinstalled(_GoalObject *self, PyObject *obj) { if (queryObject_Check(obj)) { HyQuery query = queryFromPyObject(obj); if (query == NULL) return NULL; self->goal->userInstalled(*query->getResultPset()); Py_RETURN_FALSE; } DnfPackage *cpkg = packageFromPyObject(obj); int ret; if (cpkg == NULL) return NULL; ret = hy_goal_userinstalled(self->goal, cpkg); if (!ret) Py_RETURN_TRUE; Py_RETURN_FALSE; } static PyObject * get_actions(_GoalObject *self, void *unused) { HyGoal goal = self->goal; return PyLong_FromLong(goal->getActions()); } static PyObject * req_has_distupgrade_all(_GoalObject *self, PyObject *unused) { return PyBool_FromLong(hy_goal_has_actions(self->goal, DNF_DISTUPGRADE_ALL)); } static PyObject * req_has_erase(_GoalObject *self, PyObject *unused) { return PyBool_FromLong(hy_goal_has_actions(self->goal, DNF_ERASE)); } static PyObject * req_length(_GoalObject *self, PyObject *unused) { return PyLong_FromLong(hy_goal_req_length(self->goal)); } static PyObject * add_protected(_GoalObject *self, PyObject *seq) { HyGoal goal = self->goal; auto pset = pyseq_to_packageset(seq, hy_goal_get_sack(goal)); if (!pset) return NULL; dnf_goal_add_protected(goal, pset.get()); Py_RETURN_NONE; } static PyObject * run(_GoalObject *self, PyObject *args, PyObject *kwds) { int flags = 0; if (!args_run_parse(args, kwds, &flags, NULL)) return NULL; int ret = hy_goal_run_flags(self->goal, static_cast(flags)); if (!ret) Py_RETURN_TRUE; Py_RETURN_FALSE; } static PyObject * count_problems(_GoalObject *self, PyObject *unused) { return PyLong_FromLong(hy_goal_count_problems(self->goal)); } /** * Reports problems described in strings. * * Returns Python list with Python list of strings for each problem or empty Python list if no * problem or NULL in case of error. */ static PyObject * problem_rules(_GoalObject *self, PyObject *unused) { auto allProblems = self->goal->describeAllProblemRules(true); return problemRulesPyConverter(allProblems); } /** * Reports packages that has a conflict * * Returns Python list with package objects that have a conflict. */ static PyObject * problem_conflicts(_GoalObject *self, PyObject *args, PyObject *kwds) { const char *kwlist[] = {"available", NULL}; int available = 0; if (!PyArg_ParseTupleAndKeywords(args, kwds, "|i", (char**) kwlist, &available)) return 0; DnfPackageState pkg_type = DNF_PACKAGE_STATE_ALL; if (available) pkg_type = DNF_PACKAGE_STATE_AVAILABLE; auto pset = self->goal->listConflictPkgs(pkg_type); return packageset_to_pylist(pset.get(), self->sack); } /** * Reports packages that has a conflict * * Returns Python list with package objects that have a conflict. */ static PyObject * problem_broken_dependency(_GoalObject *self, PyObject *args, PyObject *kwds) { const char *kwlist[] = {"available", NULL}; int available = 0; if (!PyArg_ParseTupleAndKeywords(args, kwds, "|i", (char**) kwlist, &available)) return 0; DnfPackageState pkg_type = DNF_PACKAGE_STATE_ALL; if (available) pkg_type = DNF_PACKAGE_STATE_AVAILABLE; auto pset = self->goal->listBrokenDependencyPkgs(pkg_type); return packageset_to_pylist(pset.get(), self->sack); } static PyObject * log_decisions(_GoalObject *self, PyObject *unused) { if (hy_goal_log_decisions(self->goal)) PyErr_SetString(PyExc_ValueError, "log_decisions() failed."); Py_RETURN_NONE; } static PyObject * write_debugdata(_GoalObject *self, PyObject *dir_str) { g_autoptr(GError) error = NULL; PycompString dir(dir_str); if (!dir.getCString()) return NULL; gboolean ret = hy_goal_write_debugdata(self->goal, dir.getCString(), &error); if (!ret) { op_error2exc(error); return NULL; } Py_RETURN_NONE; } static PyObject * list_generic(_GoalObject *self, GPtrArray *(*func)(HyGoal, GError **)) { g_autoptr(GError) error = NULL; GPtrArray *plist = func(self->goal, &error); PyObject *list; if (!plist) { switch (error->code) { case DNF_ERROR_INTERNAL_ERROR: PyErr_SetString(HyExc_Value, "Goal has not been run yet."); break; case DNF_ERROR_NO_SOLUTION: PyErr_SetString(HyExc_Runtime, "Goal could not find a solution."); break; default: assert(0); } return NULL; } list = packagelist_to_pylist(plist, self->sack); g_ptr_array_unref(plist); return list; } static PyObject * list_erasures(_GoalObject *self, PyObject *unused) { return list_generic(self, hy_goal_list_erasures); } static PyObject * list_installs(_GoalObject *self, PyObject *unused) { return list_generic(self, hy_goal_list_installs); } static PyObject * list_obsoleted(_GoalObject *self, PyObject *unused) { return list_generic(self, hy_goal_list_obsoleted); } static PyObject * list_reinstalls(_GoalObject *self, PyObject *unused) { return list_generic(self, hy_goal_list_reinstalls); } static PyObject * list_unneeded(_GoalObject *self, PyObject *unused) { return list_generic(self, hy_goal_list_unneeded); } static PyObject * list_suggested(_GoalObject *self, PyObject *unused) { return list_generic(self, hy_goal_list_suggested); } static PyObject * list_downgrades(_GoalObject *self, PyObject *unused) { return list_generic(self, hy_goal_list_downgrades); } static PyObject * list_upgrades(_GoalObject *self, PyObject *unused) { return list_generic(self, hy_goal_list_upgrades); } static PyObject * obsoleted_by_package(_GoalObject *self, PyObject *pkg) { DnfPackage *cpkg = packageFromPyObject(pkg); if (cpkg == NULL) return NULL; GPtrArray *plist = hy_goal_list_obsoleted_by_package(self->goal, cpkg); PyObject *list = packagelist_to_pylist(plist, self->sack); g_ptr_array_unref(plist); return list; } static PyObject * get_reason(_GoalObject *self, PyObject *pkg) { DnfPackage *cpkg = packageFromPyObject(pkg); if (cpkg == NULL) return NULL; int reason = hy_goal_get_reason(self->goal, cpkg); return PyLong_FromLong(reason); } static PyObject * goalToPyObject(HyGoal goal, PyObject *sack) { _GoalObject *self = (_GoalObject *)goal_Type.tp_alloc(&goal_Type, 0); if (self) { self->goal = goal; self->sack = sack; Py_INCREF(sack); } return (PyObject *)self; } static PyObject * deepcopy(_GoalObject *self, PyObject *args, PyObject *kwds) { HyGoal goal = hy_goal_clone(self->goal); return goalToPyObject(goal, self->sack); } static struct PyMethodDef goal_methods[] = { {"__deepcopy__", (PyCFunction)deepcopy, METH_KEYWORDS|METH_VARARGS, NULL}, {"add_protected", (PyCFunction)add_protected, METH_O, NULL}, {"distupgrade_all", (PyCFunction)distupgrade_all, METH_NOARGS, NULL}, {"distupgrade", (PyCFunction)distupgrade, METH_VARARGS | METH_KEYWORDS, NULL}, {"erase", (PyCFunction)erase, METH_VARARGS | METH_KEYWORDS, NULL}, {"install", (PyCFunction)install, METH_VARARGS | METH_KEYWORDS, NULL}, {"upgrade", (PyCFunction)upgrade, METH_VARARGS | METH_KEYWORDS, NULL}, {"upgrade_all", (PyCFunction)upgrade_all, METH_NOARGS, NULL}, {"userinstalled", (PyCFunction)userinstalled, METH_O, NULL}, // deprecated in 0.5.9, will be removed in 1.0.0 // use goal.actions & hawkey.DISTUPGRADE_ALL instead {"req_has_distupgrade_all", (PyCFunction)req_has_distupgrade_all, METH_NOARGS, NULL}, // deprecated in 0.5.9, will be removed in 1.0.0 // use goal.actions | hawkey.ERASE instead {"req_has_erase", (PyCFunction)req_has_erase, METH_NOARGS, NULL}, {"req_length", (PyCFunction)req_length, METH_NOARGS, NULL}, {"run", (PyCFunction)run, METH_VARARGS | METH_KEYWORDS, NULL}, {"count_problems", (PyCFunction)count_problems, METH_NOARGS, NULL}, {"problem_conflicts",(PyCFunction)problem_conflicts, METH_VARARGS | METH_KEYWORDS, NULL}, {"problem_broken_dependency",(PyCFunction)problem_broken_dependency, METH_VARARGS | METH_KEYWORDS, NULL}, {"problem_rules", (PyCFunction)problem_rules, METH_NOARGS, NULL}, {"log_decisions", (PyCFunction)log_decisions, METH_NOARGS, NULL}, {"write_debugdata", (PyCFunction)write_debugdata, METH_O, NULL}, {"list_erasures", (PyCFunction)list_erasures, METH_NOARGS, NULL}, {"list_installs", (PyCFunction)list_installs, METH_NOARGS, NULL}, {"list_obsoleted", (PyCFunction)list_obsoleted, METH_NOARGS, NULL}, {"list_reinstalls", (PyCFunction)list_reinstalls, METH_NOARGS, NULL}, {"list_unneeded", (PyCFunction)list_unneeded, METH_NOARGS, NULL}, {"list_suggested", (PyCFunction)list_suggested, METH_NOARGS, NULL}, {"list_downgrades", (PyCFunction)list_downgrades, METH_NOARGS, NULL}, {"list_upgrades", (PyCFunction)list_upgrades, METH_NOARGS, NULL}, {"obsoleted_by_package",(PyCFunction)obsoleted_by_package, METH_O, NULL}, {"get_reason", (PyCFunction)get_reason, METH_O, NULL}, {NULL} /* sentinel */ }; static struct PyMemberDef goal_members[] = { {(char*)"sack", T_OBJECT, offsetof(_GoalObject, sack), READONLY, NULL}, {NULL} }; static PyGetSetDef goal_getsetters[] = { {(char*)"actions", (getter)get_actions, NULL, NULL, NULL}, {NULL} /* sentinel */ }; PyTypeObject goal_Type = { PyVarObject_HEAD_INIT(NULL, 0) "_hawkey.Goal", /*tp_name*/ sizeof(_GoalObject), /*tp_basicsize*/ 0, /*tp_itemsize*/ (destructor) goal_dealloc, /*tp_dealloc*/ 0, /*tp_print*/ 0, /*tp_getattr*/ 0, /*tp_setattr*/ 0, /*tp_compare*/ 0, /*tp_repr*/ 0, /*tp_as_number*/ 0, /*tp_as_sequence*/ 0, /*tp_as_mapping*/ 0, /*tp_hash */ 0, /*tp_call*/ 0, /*tp_str*/ PyObject_GenericGetAttr, /*tp_getattro*/ 0, /*tp_setattro*/ 0, /*tp_as_buffer*/ Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, /*tp_flags*/ "Goal object", /* tp_doc */ 0, /* tp_traverse */ 0, /* tp_clear */ 0, /* tp_richcompare */ 0, /* tp_weaklistoffset */ PyObject_SelfIter, /* tp_iter */ 0, /* tp_iternext */ goal_methods, /* tp_methods */ goal_members, /* tp_members */ goal_getsetters, /* tp_getset */ 0, /* tp_base */ 0, /* tp_dict */ 0, /* tp_descr_get */ 0, /* tp_descr_set */ 0, /* tp_dictoffset */ (initproc)goal_init, /* tp_init */ 0, /* tp_alloc */ goal_new, /* tp_new */ 0, /* tp_free */ 0, /* tp_is_gc */ };