9eae9a2286b7ddf0a1a7e70187a55f764611e899
[tools/librpm-tizen.git] / python / rpmds-py.c
1 #include "rpmsystem-py.h"
2
3 #include <rpm/rpmtypes.h>
4 #include <rpm/rpmstring.h>
5 #include <rpm/rpmlib.h>         /* rpmvercmp */
6
7 #include "header-py.h"
8 #include "rpmds-py.h"
9 #include "rpmstrpool-py.h"
10
11 struct rpmdsObject_s {
12     PyObject_HEAD
13     PyObject *md_dict;          /*!< to look like PyModuleObject */
14     int         active;
15     rpmds       ds;
16 };
17
18 static PyObject *
19 rpmds_Count(rpmdsObject * s)
20 {
21     DEPRECATED_METHOD("use len(ds) instead");
22     return Py_BuildValue("i", PyMapping_Size((PyObject *)s));
23 }
24
25 static PyObject *
26 rpmds_Ix(rpmdsObject * s)
27 {
28     return Py_BuildValue("i", rpmdsIx(s->ds));
29 }
30
31 static PyObject *
32 rpmds_DNEVR(rpmdsObject * s)
33 {
34     return Py_BuildValue("s", rpmdsDNEVR(s->ds));
35 }
36
37 static PyObject *
38 rpmds_N(rpmdsObject * s)
39 {
40     return Py_BuildValue("s", rpmdsN(s->ds));
41 }
42
43 static PyObject *
44 rpmds_EVR(rpmdsObject * s)
45 {
46     return Py_BuildValue("s", rpmdsEVR(s->ds));
47 }
48
49 static PyObject *
50 rpmds_Flags(rpmdsObject * s)
51 {
52     return Py_BuildValue("i", rpmdsFlags(s->ds));
53 }
54
55 static PyObject *
56 rpmds_TagN(rpmdsObject * s)
57 {
58     return Py_BuildValue("i", rpmdsTagN(s->ds));
59 }
60
61 static PyObject *
62 rpmds_Color(rpmdsObject * s)
63 {
64     return Py_BuildValue("i", rpmdsColor(s->ds));
65 }
66
67 static PyObject *
68 rpmds_iternext(rpmdsObject * s)
69 {
70     PyObject * result = NULL;
71
72     /* Reset loop indices on 1st entry. */
73     if (!s->active) {
74         s->ds = rpmdsInit(s->ds);
75         s->active = 1;
76     }
77
78     /* If more to do, return a (N, EVR, Flags) tuple. */
79     if (rpmdsNext(s->ds) >= 0) {
80         result = rpmds_Wrap(Py_TYPE(s), rpmdsCurrent(s->ds));
81     } else
82         s->active = 0;
83
84     return result;
85 }
86
87 static PyObject *
88 rpmds_SetNoPromote(rpmdsObject * s, PyObject * args, PyObject * kwds)
89 {
90     int nopromote;
91     char * kwlist[] = {"noPromote", NULL};
92
93     if (!PyArg_ParseTupleAndKeywords(args, kwds, "i:SetNoPromote", kwlist,
94             &nopromote))
95         return NULL;
96
97     return Py_BuildValue("i", rpmdsSetNoPromote(s->ds, nopromote));
98 }
99
100 /* XXX rpmdsFind uses bsearch on s->ds, so a sort is needed. */
101 static PyObject *
102 rpmds_Sort(rpmdsObject * s)
103 {
104     /* XXX sort on (N,EVR,F) here. */
105     Py_RETURN_NONE;
106 }
107
108 static PyObject *
109 rpmds_Find(rpmdsObject * s, PyObject * arg)
110 {
111     rpmdsObject * o;
112
113     if (!PyArg_Parse(arg, "O!:Find", &rpmds_Type, &o))
114         return NULL;
115
116     /* XXX make sure ods index is valid, real fix in lib/rpmds.c. */
117     if (rpmdsIx(o->ds) == -1)   rpmdsSetIx(o->ds, 0);
118
119     return Py_BuildValue("i", rpmdsFind(s->ds, o->ds));
120 }
121
122 static PyObject *
123 rpmds_Merge(rpmdsObject * s, PyObject * arg)
124 {
125     rpmdsObject * o;
126
127     if (!PyArg_Parse(arg, "O!:Merge", &rpmds_Type, &o))
128         return NULL;
129
130     return Py_BuildValue("i", rpmdsMerge(&s->ds, o->ds));
131 }
132 static PyObject *
133 rpmds_Search(rpmdsObject * s, PyObject * arg)
134 {
135     rpmdsObject * o;
136
137     if (!PyArg_Parse(arg, "O!:Merge", &rpmds_Type, &o))
138         return NULL;
139
140     return Py_BuildValue("i", rpmdsSearch(s->ds, o->ds));
141 }
142
143 static PyObject *rpmds_Compare(rpmdsObject * s, PyObject * o)
144 {
145     rpmdsObject * ods;
146
147     if (!PyArg_Parse(o, "O!:Compare", &rpmds_Type, &ods))
148         return NULL;
149
150     return PyBool_FromLong(rpmdsCompare(s->ds, ods->ds));
151 }
152
153 static PyObject *rpmds_Instance(rpmdsObject * s)
154 {
155     return Py_BuildValue("i", rpmdsInstance(s->ds));
156 }
157
158 static PyObject * rpmds_Rpmlib(rpmdsObject * s, PyObject *args, PyObject *kwds)
159 {
160     rpmstrPool pool = NULL;
161     rpmds ds = NULL;
162     char * kwlist[] = {"pool", NULL};
163
164     if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O&:rpmds_Rpmlib", kwlist, 
165                  &poolFromPyObject, &pool))
166         return NULL;
167
168     /* XXX check return code, permit arg (NULL uses system default). */
169     rpmdsRpmlibPool(pool, &ds, NULL);
170
171     return rpmds_Wrap(&rpmds_Type, ds);
172 }
173
174 static struct PyMethodDef rpmds_methods[] = {
175  {"Count",      (PyCFunction)rpmds_Count,       METH_NOARGS,
176         "Deprecated, use len(ds) instead.\n" },
177  {"Ix",         (PyCFunction)rpmds_Ix,          METH_NOARGS,
178         "ds.Ix -> Ix -- Return current element index.\n" },
179  {"DNEVR",      (PyCFunction)rpmds_DNEVR,       METH_NOARGS,
180         "ds.DNEVR -> DNEVR -- Return current DNEVR.\n" },
181  {"N",          (PyCFunction)rpmds_N,           METH_NOARGS,
182         "ds.N -> N -- Return current N.\n" },
183  {"EVR",        (PyCFunction)rpmds_EVR,         METH_NOARGS,
184         "ds.EVR -> EVR -- Return current EVR.\n" },
185  {"Flags",      (PyCFunction)rpmds_Flags,       METH_NOARGS,
186         "ds.Flags -> Flags -- Return current Flags.\n" },
187  {"TagN",       (PyCFunction)rpmds_TagN,        METH_NOARGS,
188   "ds.TagN -> TagN -- Return TagN (RPMTAG_*NAME)\n\n"
189   "the type of all dependencies in this set.\n" },
190  {"Color",      (PyCFunction)rpmds_Color,       METH_NOARGS,
191         "ds.Color -> Color -- Return current Color.\n" },
192  {"SetNoPromote",(PyCFunction)rpmds_SetNoPromote, METH_VARARGS|METH_KEYWORDS,
193   "ds.SetNoPromote(noPromote) -- Set noPromote for this instance.\n\n"
194   "If True non existing epochs are no longer equal to an epoch of 0."},
195  {"Sort",       (PyCFunction)rpmds_Sort,        METH_NOARGS,
196         NULL},
197  {"Find",       (PyCFunction)rpmds_Find,        METH_O,
198   "ds.find(other_ds) -- Return index of other_ds in ds"},
199  {"Merge",      (PyCFunction)rpmds_Merge,       METH_O,
200         NULL},
201  {"Search",     (PyCFunction)rpmds_Search,      METH_O,
202 "ds.Search(element) -> matching ds index (-1 on failure)\n\
203 Check that element dependency range overlaps some member of ds.\n\
204 The current index in ds is positioned at overlapping member." },
205  {"Rpmlib",     (PyCFunction)rpmds_Rpmlib,      METH_VARARGS|METH_KEYWORDS|METH_STATIC,
206         "ds.Rpmlib -> nds -- Return internal rpmlib dependency set.\n"},
207  {"Compare",    (PyCFunction)rpmds_Compare,     METH_O,
208   "ds.compare(other) -- Compare current entries of self and other.\n\nReturns True if the entries match each other, False otherwise"},
209  {"Instance",   (PyCFunction)rpmds_Instance,    METH_NOARGS,
210   "ds.Instance() -- Return rpmdb key of corresponding package or 0."},
211  {NULL,         NULL}           /* sentinel */
212 };
213
214 /* ---------- */
215
216 static void
217 rpmds_dealloc(rpmdsObject * s)
218 {
219     s->ds = rpmdsFree(s->ds);
220     Py_TYPE(s)->tp_free((PyObject *)s);
221 }
222
223 static Py_ssize_t rpmds_length(rpmdsObject * s)
224 {
225     return rpmdsCount(s->ds);
226 }
227
228 static PyObject *
229 rpmds_subscript(rpmdsObject * s, PyObject * key)
230 {
231     int ix;
232
233     if (!PyInt_Check(key)) {
234         PyErr_SetString(PyExc_TypeError, "integer expected");
235         return NULL;
236     }
237
238     ix = (int) PyInt_AsLong(key);
239     rpmdsSetIx(s->ds, ix);
240     return Py_BuildValue("s", rpmdsDNEVR(s->ds));
241 }
242
243 static PyMappingMethods rpmds_as_mapping = {
244         (lenfunc) rpmds_length,         /* mp_length */
245         (binaryfunc) rpmds_subscript,   /* mp_subscript */
246         (objobjargproc)0,               /* mp_ass_subscript */
247 };
248
249 static int rpmds_init(rpmdsObject * s, PyObject *args, PyObject *kwds)
250 {
251     s->active = 0;
252     return 0;
253 }
254
255 static int depflags(PyObject *o, rpmsenseFlags *senseFlags)
256 {
257     int ok = 0;
258     PyObject *str = NULL;
259     rpmsenseFlags flags = RPMSENSE_ANY;
260
261     if (PyInt_Check(o)) {
262         ok = 1;
263         flags = PyInt_AsLong(o);
264     } else if (utf8FromPyObject(o, &str)) {
265         ok = 1;
266         for (const char *s = PyBytes_AsString(str); *s; s++) {
267             switch (*s) {
268             case '=':
269                 flags |= RPMSENSE_EQUAL;
270                 break;
271             case '<':
272                 flags |= RPMSENSE_LESS;
273                 break;
274             case '>':
275                 flags |= RPMSENSE_GREATER;
276                 break;
277             default:
278                 ok = 0;
279                 break;
280             }
281         }
282         Py_DECREF(str);
283     }
284
285     if (flags == (RPMSENSE_EQUAL|RPMSENSE_LESS|RPMSENSE_GREATER))
286         ok = 0;
287
288     if (ok)
289         *senseFlags = flags;
290
291     return ok;
292 }
293
294 static PyObject * rpmds_new(PyTypeObject * subtype, PyObject *args, PyObject *kwds)
295 {
296     PyObject *obj;
297     rpmTagVal tagN = RPMTAG_REQUIRENAME;
298     rpmds ds = NULL;
299     Header h = NULL;
300     rpmstrPool pool = NULL;
301     char * kwlist[] = {"obj", "tag", "pool", NULL};
302
303     if (!PyArg_ParseTupleAndKeywords(args, kwds, "OO&|O&:rpmds_new", kwlist, 
304                  &obj, tagNumFromPyObject, &tagN,
305                  &poolFromPyObject, &pool))
306         return NULL;
307
308     if (PyTuple_Check(obj)) {
309         const char *name = NULL;
310         const char *evr = NULL;
311         rpmsenseFlags flags = RPMSENSE_ANY;
312         /* TODO: if flags are specified, evr should be required too */
313         if (PyArg_ParseTuple(obj, "s|O&s", &name, depflags, &flags, &evr)) {
314             ds = rpmdsSinglePool(pool, tagN, name, evr, flags);
315         } else {
316             PyErr_SetString(PyExc_ValueError, "invalid dependency tuple");
317             return NULL;
318         }
319     } else if (hdrFromPyObject(obj, &h)) {
320         if (tagN == RPMTAG_NEVR) {
321             ds = rpmdsThisPool(pool, h, RPMTAG_PROVIDENAME, RPMSENSE_EQUAL);
322         } else {
323             ds = rpmdsNewPool(pool, h, tagN, 0);
324         }
325     } else {
326         PyErr_SetString(PyExc_TypeError, "header or tuple expected");
327         return NULL;
328     }
329     
330     return rpmds_Wrap(subtype, ds);
331 }
332
333 static char rpmds_doc[] =
334     "rpm.ds (dependendcy set) gives a more convenient access to dependencies\n\n"
335     "It can hold multiple entries of Name Flags and EVR.\n"
336     "It typically represents all dependencies of one kind of a package\n"
337     "e.g. all Requires or all Conflicts.\n"
338     ;
339
340 PyTypeObject rpmds_Type = {
341         PyVarObject_HEAD_INIT(&PyType_Type, 0)
342         "rpm.ds",                       /* tp_name */
343         sizeof(rpmdsObject),            /* tp_basicsize */
344         0,                              /* tp_itemsize */
345         /* methods */
346         (destructor) rpmds_dealloc,     /* tp_dealloc */
347         0,                              /* tp_print */
348         (getattrfunc)0,                 /* tp_getattr */
349         (setattrfunc)0,                 /* tp_setattr */
350         0,                              /* tp_compare */
351         (reprfunc)0,                    /* tp_repr */
352         0,                              /* tp_as_number */
353         0,                              /* tp_as_sequence */
354         &rpmds_as_mapping,              /* tp_as_mapping */
355         (hashfunc)0,                    /* tp_hash */
356         (ternaryfunc)0,                 /* tp_call */
357         (reprfunc)0,                    /* tp_str */
358         PyObject_GenericGetAttr,        /* tp_getattro */
359         PyObject_GenericSetAttr,        /* tp_setattro */
360         0,                              /* tp_as_buffer */
361         Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
362         rpmds_doc,                      /* tp_doc */
363         0,                              /* tp_traverse */
364         0,                              /* tp_clear */
365         0,                              /* tp_richcompare */
366         0,                              /* tp_weaklistoffset */
367         PyObject_SelfIter,              /* tp_iter */
368         (iternextfunc) rpmds_iternext,  /* tp_iternext */
369         rpmds_methods,                  /* tp_methods */
370         0,                              /* tp_members */
371         0,                              /* tp_getset */
372         0,                              /* tp_base */
373         0,                              /* tp_dict */
374         0,                              /* tp_descr_get */
375         0,                              /* tp_descr_set */
376         0,                              /* tp_dictoffset */
377         (initproc) rpmds_init,          /* tp_init */
378         0,                              /* tp_alloc */
379         (newfunc) rpmds_new,            /* tp_new */
380         0,                              /* tp_free */
381         0,                              /* tp_is_gc */
382 };
383
384 /* ---------- */
385
386 rpmds dsFromDs(rpmdsObject * s)
387 {
388     return s->ds;
389 }
390
391 PyObject * rpmds_Wrap(PyTypeObject *subtype, rpmds ds)
392 {
393     rpmdsObject * s = (rpmdsObject *)subtype->tp_alloc(subtype, 0);
394     if (s == NULL) return NULL;
395
396     s->ds = ds;
397     s->active = 0;
398     return (PyObject *) s;
399 }
400