1 /*
2  * Copyright (C) 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 
23 // libsolv
24 #include <solv/util.h>
25 
26 // hawkey
27 #include "hy-query.h"
28 #include "dnf-sack.h"
29 
30 // pyhawkey
31 #include "exception-py.hpp"
32 #include "iutil-py.hpp"
33 #include "nevra-py.hpp"
34 #include "pycomp.hpp"
35 #include "query-py.hpp"
36 #include "sack-py.hpp"
37 
38 typedef struct {
39     PyObject_HEAD
40     libdnf::Nevra *nevra;
41 } _NevraObject;
42 
43 libdnf::Nevra *
nevraFromPyObject(PyObject * o)44 nevraFromPyObject(PyObject *o)
45 {
46     if (!PyObject_TypeCheck(o, &nevra_Type)) {
47         PyErr_SetString(PyExc_TypeError, "Expected a _hawkey.NEVRA object.");
48         return NULL;
49     }
50     return ((_NevraObject *)o)->nevra;
51 }
52 
53 PyObject *
nevraToPyObject(libdnf::Nevra * nevra)54 nevraToPyObject(libdnf::Nevra *nevra)
55 {
56     _NevraObject *self = (_NevraObject *)nevra_Type.tp_alloc(&nevra_Type, 0);
57     if (self)
58         self->nevra = nevra;
59     return (PyObject *)self;
60 }
61 
62 // getsetters
63 static int
set_epoch(_NevraObject * self,PyObject * value,void * closure)64 set_epoch(_NevraObject *self, PyObject *value, void *closure) try
65 {
66     if (value == NULL)
67         self->nevra->setEpoch(libdnf::Nevra::EPOCH_NOT_SET);
68     else if (PyInt_Check(value))
69         self->nevra->setEpoch(PyLong_AsLong(value));
70     else if (value == Py_None)
71         self->nevra->setEpoch(libdnf::Nevra::EPOCH_NOT_SET);
72     else
73         return -1;
74     return 0;
75 } CATCH_TO_PYTHON_INT
76 
77 static PyObject *
get_epoch(_NevraObject * self,void * closure)78 get_epoch(_NevraObject *self, void *closure) try
79 {
80     if (self->nevra->getEpoch() == libdnf::Nevra::EPOCH_NOT_SET)
81         Py_RETURN_NONE;
82 #if PY_MAJOR_VERSION >= 3
83     return PyLong_FromLong(self->nevra->getEpoch());
84 #else
85     return PyInt_FromLong(self->nevra->getEpoch());
86 #endif
87 } CATCH_TO_PYTHON
88 
89 template<const std::string & (libdnf::Nevra::*getMethod)() const>
90 static PyObject *
get_attr(_NevraObject * self,void * closure)91 get_attr(_NevraObject *self, void *closure) try
92 {
93     auto str = (self->nevra->*getMethod)();
94     if (str.empty())
95         Py_RETURN_NONE;
96     else
97         return PyString_FromString(str.c_str());
98 } CATCH_TO_PYTHON
99 
100 template<void (libdnf::Nevra::*setMethod)(std::string &&)>
101 static int
set_attr(_NevraObject * self,PyObject * value,void * closure)102 set_attr(_NevraObject *self, PyObject *value, void *closure) try
103 {
104     PycompString str_value(value);
105     if (!str_value.getCString())
106         return -1;
107     (self->nevra->*setMethod)(str_value.getCString());
108     return 0;
109 } CATCH_TO_PYTHON_INT
110 
111 static PyGetSetDef nevra_getsetters[] = {
112     {(char*)"name", (getter)get_attr<&libdnf::Nevra::getName>,
113         (setter)set_attr<&libdnf::Nevra::setName>, NULL, NULL},
114     {(char*)"epoch", (getter)get_epoch, (setter)set_epoch,
115         NULL, NULL},
116     {(char*)"version", (getter)get_attr<&libdnf::Nevra::getVersion>,
117         (setter)set_attr<&libdnf::Nevra::setVersion>, NULL, NULL},
118     {(char*)"release", (getter)get_attr<&libdnf::Nevra::getRelease>,
119         (setter)set_attr<&libdnf::Nevra::setRelease>, NULL, NULL},
120     {(char*)"arch", (getter)get_attr<&libdnf::Nevra::getArch>,
121         (setter)set_attr<&libdnf::Nevra::setArch>, NULL, NULL},
122     {NULL}          /* sentinel */
123 };
124 
125 static PyObject *
nevra_new(PyTypeObject * type,PyObject * args,PyObject * kwds)126 nevra_new(PyTypeObject *type, PyObject *args, PyObject *kwds) try
127 {
128     _NevraObject *self = (_NevraObject*)type->tp_alloc(type, 0);
129     if (self)
130         self->nevra = new libdnf::Nevra;
131     return (PyObject*)self;
132 } CATCH_TO_PYTHON
133 
134 static void
nevra_dealloc(_NevraObject * self)135 nevra_dealloc(_NevraObject *self)
136 {
137     delete self->nevra;
138     Py_TYPE(self)->tp_free(self);
139 }
140 
141 static int
nevra_init(_NevraObject * self,PyObject * args,PyObject * kwds)142 nevra_init(_NevraObject *self, PyObject *args, PyObject *kwds) try
143 {
144     char *name = NULL, *version = NULL, *release = NULL, *arch = NULL;
145     PyObject *epoch_o = NULL;
146     libdnf::Nevra * cnevra = NULL;
147 
148     const char *kwlist[] = {"name", "epoch", "version", "release", "arch",
149         "nevra", NULL};
150 
151     if (!PyArg_ParseTupleAndKeywords(args, kwds, "|zOzzzO&", (char**) kwlist,
152         &name, &epoch_o, &version, &release, &arch, nevra_converter, &cnevra))
153         return -1;
154     if (!name && !cnevra) {
155         PyErr_SetString(PyExc_ValueError,
156             "Name is required parameter.");
157         return -1;
158     }
159     if (cnevra) {
160         *self->nevra = *cnevra;
161         return 0;
162     }
163     if (set_epoch(self, epoch_o, NULL) == -1) {
164         PyErr_SetString(PyExc_TypeError,
165             "An integer value or None expected for epoch.");
166         return -1;
167     }
168     if (name)
169         self->nevra->setName(name);
170     if (version)
171         self->nevra->setVersion(version);
172     if (release)
173         self->nevra->setRelease(release);
174     if (arch)
175         self->nevra->setArch(arch);
176     return 0;
177 } CATCH_TO_PYTHON_INT
178 
179 /* object methods */
180 
181 static PyObject *
evr(_NevraObject * self,PyObject * unused)182 evr(_NevraObject *self, PyObject *unused) try
183 {
184     return PyString_FromString(self->nevra->getEvr().c_str());;
185 } CATCH_TO_PYTHON
186 
187 int
nevra_converter(PyObject * o,libdnf::Nevra ** nevra_ptr)188 nevra_converter(PyObject *o, libdnf::Nevra **nevra_ptr)
189 {
190     auto nevra = nevraFromPyObject(o);
191     if (nevra == NULL)
192         return 0;
193     *nevra_ptr = nevra;
194     return 1;
195 }
196 
197 static PyObject *
evr_cmp(_NevraObject * self,PyObject * args)198 evr_cmp(_NevraObject *self, PyObject *args) try
199 {
200     DnfSack *sack;
201     libdnf::Nevra *nevra;
202     if (!PyArg_ParseTuple(args, "O&O&", nevra_converter, &nevra, sack_converter, &sack)) {
203         return NULL;
204     }
205     if (sack == NULL || nevra == NULL)
206         return NULL;
207     int cmp = self->nevra->compareEvr(*nevra, sack);
208     return PyLong_FromLong(cmp);
209 } CATCH_TO_PYTHON
210 
211 static PyObject *
has_just_name(_NevraObject * self,PyObject * unused)212 has_just_name(_NevraObject *self, PyObject *unused) try
213 {
214     return PyBool_FromLong(self->nevra->hasJustName());
215 } CATCH_TO_PYTHON
216 
217 static PyObject *
to_query(_NevraObject * self,PyObject * args,PyObject * kwds)218 to_query(_NevraObject *self, PyObject *args, PyObject *kwds) try
219 {
220     PyObject *sack;
221     DnfSack *csack;
222     const char *kwlist[] = {"sack", "icase", NULL};
223     PyObject *icase = NULL;
224 
225     if (!PyArg_ParseTupleAndKeywords(args, kwds, "O!|O!", (char**) kwlist, &sack_Type, &sack,
226         &PyBool_Type, &icase)) {
227         return NULL;
228     }
229     gboolean c_icase = icase!=NULL && PyObject_IsTrue(icase);
230     csack = sackFromPyObject(sack);
231     HyQuery query = hy_query_from_nevra(self->nevra, csack, c_icase);
232     PyObject *q = queryToPyObject(query, sack, &query_Type);
233     return q;
234 } CATCH_TO_PYTHON
235 
236 static struct PyMethodDef nevra_methods[] = {
237     {"evr_cmp",     (PyCFunction) evr_cmp, METH_VARARGS, NULL},
238     {"evr", (PyCFunction) evr, METH_NOARGS,   NULL},
239     {"has_just_name",     (PyCFunction) has_just_name, METH_NOARGS, NULL},
240     {"to_query",     (PyCFunction) to_query, METH_VARARGS | METH_KEYWORDS, NULL},
241 
242     {NULL}                      /* sentinel */
243 };
244 
245 static PyObject *
nevra_richcompare(PyObject * self,PyObject * other,int op)246 nevra_richcompare(PyObject *self, PyObject *other, int op) try
247 {
248     PyObject *v;
249     libdnf::Nevra *other_nevra, *self_nevra;
250     other_nevra = nevraFromPyObject(other);
251     self_nevra = nevraFromPyObject(self);
252 
253     if (!other_nevra) {
254         if(PyErr_Occurred() && PyErr_ExceptionMatches(PyExc_TypeError))
255             PyErr_Clear();
256         Py_INCREF(Py_NotImplemented);
257         return Py_NotImplemented;
258     }
259 
260     long result = self_nevra->compare(*other_nevra);
261 
262     switch (op) {
263     case Py_EQ:
264         v = TEST_COND(result == 0);
265         break;
266     case Py_NE:
267         v = TEST_COND(result != 0);
268         break;
269     case Py_LE:
270         v = TEST_COND(result <= 0);
271         break;
272     case Py_GE:
273         v = TEST_COND(result >= 0);
274         break;
275     case Py_LT:
276         v = TEST_COND(result < 0);
277         break;
278     case Py_GT:
279         v = TEST_COND(result > 0);
280         break;
281     default:
282         PyErr_BadArgument();
283         return NULL;
284     }
285     Py_INCREF(v);
286     return v;
287 } CATCH_TO_PYTHON
288 
289 PyTypeObject nevra_Type = {
290     PyVarObject_HEAD_INIT(NULL, 0)
291     "_hawkey.NEVRA",        /*tp_name*/
292     sizeof(_NevraObject),   /*tp_basicsize*/
293     0,              /*tp_itemsize*/
294     (destructor) nevra_dealloc,  /*tp_dealloc*/
295     0,              /*tp_print*/
296     0,              /*tp_getattr*/
297     0,              /*tp_setattr*/
298     0,              /*tp_compare*/
299     0,              /*tp_repr*/
300     0,              /*tp_as_number*/
301     0,              /*tp_as_sequence*/
302     0,              /*tp_as_mapping*/
303     0,              /*tp_hash */
304     0,              /*tp_call*/
305     0,              /*tp_str*/
306     0,              /*tp_getattro*/
307     0,              /*tp_setattro*/
308     0,              /*tp_as_buffer*/
309     Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE,     /*tp_flags*/
310     "NEVRA object",     /* tp_doc */
311     0,              /* tp_traverse */
312     0,              /* tp_clear */
313     nevra_richcompare,              /* tp_richcompare */
314     0,              /* tp_weaklistoffset */
315     0,              /* tp_iter */
316     0,                          /* tp_iternext */
317     nevra_methods,      /* tp_methods */
318     0,              /* tp_members */
319     nevra_getsetters,       /* tp_getset */
320     0,              /* tp_base */
321     0,              /* tp_dict */
322     0,              /* tp_descr_get */
323     0,              /* tp_descr_set */
324     0,              /* tp_dictoffset */
325     (initproc)nevra_init,   /* tp_init */
326     0,              /* tp_alloc */
327     nevra_new,          /* tp_new */
328     0,              /* tp_free */
329     0,              /* tp_is_gc */
330 };
331