1 #include "rpmsystem-py.h"
3 #include <rpm/rpmlib.h> /* rpmvercmp */
4 #include <rpm/rpmtag.h>
5 #include <rpm/rpmstring.h>
6 #include <rpm/rpmts.h> /* XXX rpmtsCreate/rpmtsFree */
16 * \brief START HERE / RPM base module for the Python API
18 * The rpm base module provides the main starting point for
19 * accessing RPM from Python. For most usage, call
20 * the TransactionSet method to get a transaction set (rpmts).
26 * ts = rpm.TransactionSet()
29 * The transaction set will open the RPM database as needed, so
30 * in most cases, you do not need to explicitly open the
31 * database. The transaction set is the workhorse of RPM.
33 * You can open another RPM database, such as one that holds
34 * all packages for a given Linux distribution, to provide
35 * packages used to solve dependencies. To do this, use
39 * rpm.addMacro('_dbpath', '/path/to/alternate/database')
40 * solvets = rpm.TransactionSet()
42 * rpm.delMacro('_dbpath')
44 * # Open default database
45 * ts = rpm.TransactionSet()
48 * This code gives you access to two RPM databases through
49 * two transaction sets (rpmts): ts is a transaction set
50 * associated with the default RPM database and solvets
51 * is a transaction set tied to an alternate database, which
52 * is very useful for resolving dependencies.
54 * The rpm methods used here are:
56 * - addMacro(macro, value)
57 * @param macro Name of macro to add
58 * @param value Value for the macro
61 * @param macro Name of macro to delete
67 * \brief A python header object represents an RPM package header.
69 * All RPM packages have headers that provide metadata for the package.
70 * Header objects can be returned by database queries or loaded from a
71 * binary package on disk.
73 * The ts.hdrFromFdno() function returns the package header from a
74 * package on disk, verifying package signatures and digests of the
75 * package while reading.
77 * Note: The older method rpm.headerFromPackage() which has been replaced
78 * by ts.hdrFromFdno() used to return a (hdr, isSource) tuple.
80 * If you need to distinguish source/binary headers, do:
84 * ts = rpm.TransactionSet()
85 * fdno = os.open("/tmp/foo-1.0-1.i386.rpm", os.O_RDONLY)
86 * hdr = ts.hdrFromFdno(fdno)
88 * if hdr[rpm.RPMTAG_SOURCEPACKAGE]:
89 * print "header is from a source package"
91 * print "header is from a binary package"
94 * The Python interface to the header data is quite elegant. It
95 * presents the data in a dictionary form. We'll take the header we
96 * just loaded and access the data within it:
98 * print hdr[rpm.RPMTAG_NAME]
99 * print hdr[rpm.RPMTAG_VERSION]
100 * print hdr[rpm.RPMTAG_RELEASE]
102 * in the case of our "foo-1.0-1.i386.rpm" package, this code would
110 * You make also access the header data by string name:
113 * print hdr['version']
114 * print hdr['release']
117 * This method of access is a teensy bit slower because the name must be
118 * translated into the tag number dynamically. You also must make sure
119 * the strings in header lookups don't get translated, or the lookups
124 * \name Class: rpm.hdr
133 static PyObject * hdrKeyList(hdrObject * s)
139 keys = PyList_New(0);
144 hi = headerInitIterator(s->h);
145 while ((tag = headerNextTag(hi)) != RPMTAG_NOT_FOUND) {
146 PyObject *to = PyLong_FromLong(tag);
148 headerFreeIterator(hi);
152 PyList_Append(keys, to);
155 headerFreeIterator(hi);
160 static PyObject * hdrAsBytes(hdrObject * s)
162 PyObject *res = NULL;
163 unsigned int len = 0;
164 char *buf = headerExport(s->h, &len);
166 if (buf == NULL || len == 0) {
167 PyErr_SetString(pyrpmError, "can't unload bad header\n");
169 res = PyBytes_FromStringAndSize(buf, len);
175 static PyObject * hdrUnload(hdrObject * s)
177 return hdrAsBytes(s);
180 static PyObject * hdrExpandFilelist(hdrObject * s)
182 DEPRECATED_METHOD("use hdr.convert() instead");
183 headerConvert(s->h, HEADERCONV_EXPANDFILELIST);
188 static PyObject * hdrCompressFilelist(hdrObject * s)
190 DEPRECATED_METHOD("use hdr.convert() instead");
191 headerConvert(s->h, HEADERCONV_COMPRESSFILELIST);
196 /* make a header with _all_ the tags we need */
197 static PyObject * hdrFullFilelist(hdrObject * s)
199 rpmtd fileNames = rpmtdNew();
202 DEPRECATED_METHOD("obsolete method");
203 if (!headerIsEntry (h, RPMTAG_BASENAMES)
204 || !headerIsEntry (h, RPMTAG_DIRNAMES)
205 || !headerIsEntry (h, RPMTAG_DIRINDEXES))
206 headerConvert(h, HEADERCONV_COMPRESSFILELIST);
208 if (headerGet(h, RPMTAG_FILENAMES, fileNames, HEADERGET_EXT)) {
209 rpmtdSetTag(fileNames, RPMTAG_OLDFILENAMES);
210 headerPut(h, fileNames, HEADERPUT_DEFAULT);
212 rpmtdFree(fileNames);
217 static PyObject * hdrFormat(hdrObject * s, PyObject * args, PyObject * kwds)
223 char * kwlist[] = {"format", NULL};
225 if (!PyArg_ParseTupleAndKeywords(args, kwds, "s", kwlist, &fmt))
228 r = headerFormat(s->h, fmt, &err);
230 PyErr_SetString(pyrpmError, err);
234 result = utf8FromString(r);
240 static PyObject *hdrIsSource(hdrObject *s)
242 return PyBool_FromLong(headerIsSource(s->h));
245 static int hdrContains(hdrObject *s, PyObject *pytag)
248 if (!tagNumFromPyObject(pytag, &tag)) return -1;
250 return headerIsEntry(s->h, tag);
253 static PyObject *hdrConvert(hdrObject *self, PyObject *args, PyObject *kwds)
255 char *kwlist[] = {"op", NULL};
258 if (!PyArg_ParseTupleAndKeywords(args, kwds, "i", kwlist, &op)) {
261 return PyBool_FromLong(headerConvert(self->h, op));
264 static PyObject * hdrWrite(hdrObject *s, PyObject *args, PyObject *kwds)
266 char *kwlist[] = { "file", "magic", NULL };
267 int magic = HEADER_MAGIC_YES;
268 rpmfdObject *fdo = NULL;
271 if (!PyArg_ParseTupleAndKeywords(args, kwds, "O&|i", kwlist,
272 rpmfdFromPyObject, &fdo, &magic))
275 Py_BEGIN_ALLOW_THREADS;
276 rc = headerWrite(rpmfdGetFd(fdo), s->h,
277 magic ? HEADER_MAGIC_YES : HEADER_MAGIC_NO);
278 Py_END_ALLOW_THREADS;
280 if (rc) PyErr_SetFromErrno(PyExc_IOError);
281 Py_XDECREF(fdo); /* avoid messing up errno with file close */
288 * Just a backwards-compatibility dummy, the arguments are not looked at
289 * or used. TODO: push this over to python side...
291 static PyObject * hdr_fiFromHeader(PyObject * s, PyObject * args, PyObject * kwds)
293 return PyObject_CallFunctionObjArgs((PyObject *) &rpmfi_Type, s, NULL);
296 /* Backwards compatibility. Flags argument is just a dummy and discarded. */
297 static PyObject * hdr_dsFromHeader(PyObject * s, PyObject * args, PyObject * kwds)
299 rpmTagVal tag = RPMTAG_REQUIRENAME;
300 rpmsenseFlags flags = 0;
301 char * kwlist[] = {"to", "flags", NULL};
302 if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O&i:dsFromHeader", kwlist,
303 tagNumFromPyObject, &tag, &flags))
306 return PyObject_CallFunction((PyObject *) &rpmds_Type,
310 static PyObject * hdr_dsOfHeader(PyObject * s)
312 return PyObject_CallFunction((PyObject *) &rpmds_Type,
313 "(Oi)", s, RPMTAG_NEVR);
316 static long hdr_hash(PyObject * h)
321 static PyObject * hdr_reduce(hdrObject *s)
323 PyObject *res = NULL;
324 PyObject *blob = hdrAsBytes(s);
326 res = Py_BuildValue("O(O)", Py_TYPE(s), blob);
332 static struct PyMethodDef hdr_methods[] = {
333 {"keys", (PyCFunction) hdrKeyList, METH_NOARGS,
334 "hdr.keys() -- Return a list of the header's rpm tags (int RPMTAG_*)." },
335 {"unload", (PyCFunction) hdrUnload, METH_NOARGS,
336 "hdr.unload() -- Return binary representation\nof the header." },
337 {"expandFilelist", (PyCFunction) hdrExpandFilelist,METH_NOARGS,
338 "DEPRECATED -- Use hdr.convert() instead." },
339 {"compressFilelist",(PyCFunction) hdrCompressFilelist,METH_NOARGS,
340 "DEPRECATED -- Use hdr.convert() instead." },
341 {"fullFilelist", (PyCFunction) hdrFullFilelist, METH_NOARGS,
342 "DEPRECATED -- Obsolete method."},
343 {"convert", (PyCFunction) hdrConvert, METH_VARARGS|METH_KEYWORDS,
344 "hdr.convert(op=-1) -- Convert header - See HEADERCONV_*\nfor possible values of op."},
345 {"format", (PyCFunction) hdrFormat, METH_VARARGS|METH_KEYWORDS,
346 "hdr.format(format) -- Expand a query string with the header data.\n\nSee rpm -q for syntax." },
347 {"sprintf", (PyCFunction) hdrFormat, METH_VARARGS|METH_KEYWORDS,
348 "Alias for .format()." },
349 {"isSource", (PyCFunction)hdrIsSource, METH_NOARGS,
350 "hdr.isSource() -- Return if header describes a source package." },
351 {"write", (PyCFunction)hdrWrite, METH_VARARGS|METH_KEYWORDS,
352 "hdr.write(file, magic=True) -- Write header to file." },
353 {"dsOfHeader", (PyCFunction)hdr_dsOfHeader, METH_NOARGS,
354 "hdr.dsOfHeader() -- Return dependency set with the header's NEVR."},
355 {"dsFromHeader", (PyCFunction)hdr_dsFromHeader, METH_VARARGS|METH_KEYWORDS,
356 "hdr.dsFromHeader(to=RPMTAG_REQUIRENAME, flags=None)\nGet dependency set from header. to must be one of the NAME tags\nbelonging to a dependency:\n'Providename', 'Requirename', 'Obsoletename', 'Conflictname',\n'Triggername', 'Recommendname', 'Suggestname', 'Supplementname',\n'Enhancename' or one of the corresponding RPMTAG_*NAME constants." },
357 {"fiFromHeader", (PyCFunction)hdr_fiFromHeader, METH_VARARGS|METH_KEYWORDS,
358 "hdr.fiFromHeader() -- Return rpm.fi object containing the file\nmeta data from the header.\n\nDEPRECATED - Use rpm.files(hdr) instead."},
359 {"__reduce__", (PyCFunction)hdr_reduce, METH_NOARGS,
362 {NULL, NULL} /* sentinel */
365 /* TODO: permit keyring check + retrofits on copy/load */
366 static PyObject *hdr_new(PyTypeObject *subtype, PyObject *args, PyObject *kwds)
368 PyObject *obj = NULL;
369 rpmfdObject *fdo = NULL;
371 char *kwlist[] = { "obj", NULL };
373 if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O", kwlist, &obj)) {
379 } else if (CAPSULE_CHECK(obj)) {
380 h = CAPSULE_EXTRACT(obj, PYTHON_MODULENAME"._C_Header");
382 } else if (hdrObject_Check(obj)) {
383 h = headerCopy(((hdrObject*) obj)->h);
384 } else if (PyBytes_Check(obj)) {
385 h = headerCopyLoad(PyBytes_AsString(obj));
386 } else if (rpmfdFromPyObject(obj, &fdo)) {
387 Py_BEGIN_ALLOW_THREADS;
388 h = headerRead(rpmfdGetFd(fdo), HEADER_MAGIC_YES);
389 Py_END_ALLOW_THREADS;
392 PyErr_SetString(PyExc_TypeError, "header, blob or file expected");
397 PyErr_SetString(pyrpmError, "bad header");
401 return hdr_Wrap(subtype, h);
404 static void hdr_dealloc(hdrObject * s)
406 if (s->h) headerFree(s->h);
407 Py_TYPE(s)->tp_free((PyObject *)s);
410 static PyObject * hdr_iternext(hdrObject *s)
412 PyObject *res = NULL;
415 if (s->hi == NULL) s->hi = headerInitIterator(s->h);
417 if ((tag = headerNextTag(s->hi)) != RPMTAG_NOT_FOUND) {
418 res = PyLong_FromLong(tag);
420 s->hi = headerFreeIterator(s->hi);
425 int utf8FromPyObject(PyObject *item, PyObject **str)
427 PyObject *res = NULL;
428 if (PyBytes_Check(item)) {
431 } else if (PyUnicode_Check(item)) {
432 res = PyUnicode_AsUTF8String(item);
434 if (res == NULL) return 0;
440 int tagNumFromPyObject (PyObject *item, rpmTagVal *tagp)
442 rpmTagVal tag = RPMTAG_NOT_FOUND;
443 PyObject *str = NULL;
445 if (PyLong_Check(item)) {
446 /* XXX we should probably validate tag numbers too */
447 tag = PyLong_AsLong(item);
448 } else if (utf8FromPyObject(item, &str)) {
449 tag = rpmTagGetValue(PyBytes_AsString(str));
452 PyErr_SetString(PyExc_TypeError, "expected a string or integer");
455 if (tag == RPMTAG_NOT_FOUND) {
456 PyErr_SetString(PyExc_ValueError, "unknown header tag");
464 static PyObject * hdrGetTag(Header h, rpmTagVal tag)
466 PyObject *res = NULL;
469 (void) headerGet(h, tag, &td, HEADERGET_EXT);
470 if (rpmtdGetFlags(&td) & RPMTD_INVALID) {
471 PyErr_SetString(pyrpmError, "invalid header data");
473 /* rpmtd_AsPyobj() knows how to handle empty containers and all */
474 res = rpmtd_AsPyobj(&td);
480 static int validItem(rpmTagClass tclass, PyObject *item)
485 case RPM_NUMERIC_CLASS:
486 rc = (PyLong_Check(item) || PyLong_Check(item));
488 case RPM_STRING_CLASS:
489 rc = (PyBytes_Check(item) || PyUnicode_Check(item));
491 case RPM_BINARY_CLASS:
492 rc = PyBytes_Check(item);
501 static int validData(rpmTagVal tag, rpmTagType type, rpmTagReturnType retype, PyObject *value)
503 rpmTagClass tclass = rpmTagGetClass(tag);
506 if (retype == RPM_SCALAR_RETURN_TYPE) {
507 valid = validItem(tclass, value);
508 } else if (retype == RPM_ARRAY_RETURN_TYPE && PyList_Check(value)) {
509 /* python lists can contain arbitrary objects, validate each item */
510 Py_ssize_t len = PyList_Size(value);
513 for (Py_ssize_t i = 0; i < len; i++) {
514 PyObject *item = PyList_GetItem(value, i);
515 if (!validItem(tclass, item)) {
526 static int hdrAppendItem(Header h, rpmTagVal tag, rpmTagType type, PyObject *item)
531 case RPM_I18NSTRING_TYPE: /* XXX this needs to be handled separately */
532 case RPM_STRING_TYPE:
533 case RPM_STRING_ARRAY_TYPE: {
534 PyObject *str = NULL;
535 if (utf8FromPyObject(item, &str))
536 rc = headerPutString(h, tag, PyBytes_AsString(str));
540 uint8_t *val = (uint8_t *) PyBytes_AsString(item);
541 rpm_count_t len = PyBytes_Size(item);
542 rc = headerPutBin(h, tag, val, len);
544 case RPM_INT64_TYPE: {
545 uint64_t val = PyLong_AsUnsignedLongLongMask(item);
546 rc = headerPutUint64(h, tag, &val, 1);
548 case RPM_INT32_TYPE: {
549 uint32_t val = PyLong_AsUnsignedLongMask(item);
550 rc = headerPutUint32(h, tag, &val, 1);
552 case RPM_INT16_TYPE: {
553 uint16_t val = PyLong_AsUnsignedLongMask(item);
554 rc = headerPutUint16(h, tag, &val, 1);
557 case RPM_CHAR_TYPE: {
558 uint8_t val = PyLong_AsUnsignedLongMask(item);
559 rc = headerPutUint8(h, tag, &val, 1);
562 PyErr_SetString(PyExc_TypeError, "unhandled datatype");
567 static int hdrPutTag(Header h, rpmTagVal tag, PyObject *value)
569 rpmTagType type = rpmTagGetTagType(tag);
570 rpmTagReturnType retype = rpmTagGetReturnType(tag);
573 /* XXX this isn't really right (i18n strings etc) but for now ... */
574 if (headerIsEntry(h, tag)) {
575 PyErr_SetString(PyExc_TypeError, "tag already exists");
579 /* validate all data before trying to insert */
580 if (!validData(tag, type, retype, value)) {
581 PyErr_SetString(PyExc_TypeError, "invalid type for tag");
585 if (retype == RPM_SCALAR_RETURN_TYPE) {
586 rc = hdrAppendItem(h, tag, type, value);
587 } else if (retype == RPM_ARRAY_RETURN_TYPE && PyList_Check(value)) {
588 Py_ssize_t len = PyList_Size(value);
589 for (Py_ssize_t i = 0; i < len; i++) {
590 PyObject *item = PyList_GetItem(value, i);
591 rc = hdrAppendItem(h, tag, type, item);
594 PyErr_SetString(PyExc_RuntimeError, "can't happen, right?");
600 static PyObject * hdr_subscript(hdrObject * s, PyObject * item)
604 if (!tagNumFromPyObject(item, &tag)) return NULL;
605 return hdrGetTag(s->h, tag);
608 static int hdr_ass_subscript(hdrObject *s, PyObject *key, PyObject *value)
611 if (!tagNumFromPyObject(key, &tag)) return -1;
614 /* XXX should failure raise key error? */
615 headerDel(s->h, tag);
616 } else if (!hdrPutTag(s->h, tag, value)) {
622 static PyObject * hdr_getattro(hdrObject * s, PyObject * n)
624 PyObject *res = PyObject_GenericGetAttr((PyObject *) s, n);
626 PyObject *type, *value, *traceback;
629 /* Save and restore original exception if it's not a valid tag either */
630 PyErr_Fetch(&type, &value, &traceback);
631 if (tagNumFromPyObject(n, &tag)) {
634 Py_XDECREF(traceback);
635 res = hdrGetTag(s->h, tag);
637 PyErr_Restore(type, value, traceback);
643 static int hdr_setattro(PyObject * o, PyObject * n, PyObject * v)
645 return PyObject_GenericSetAttr(o, n, v);
648 static PyMappingMethods hdr_as_mapping = {
649 (lenfunc) 0, /* mp_length */
650 (binaryfunc) hdr_subscript, /* mp_subscript */
651 (objobjargproc)hdr_ass_subscript,/* mp_ass_subscript */
654 static PySequenceMethods hdr_as_sequence = {
661 0, /* sq_ass_slice */
662 (objobjproc)hdrContains, /* sq_contains */
663 0, /* sq_inplace_concat */
664 0, /* sq_inplace_repeat */
667 static char hdr_doc[] =
668 "A header object represents an RPM package header.\n"
670 "All RPM packages have headers that provide metadata for the package.\n"
671 "Header objects can be returned by database queries or loaded from a\n"
672 "binary package on disk.\n"
674 "The ts.hdrFromFdno() function returns the package header from a\n"
675 "package on disk, verifying package signatures and digests of the\n"
676 "package while reading.\n"
678 "Note: The older method rpm.headerFromPackage() which has been replaced\n"
679 "by ts.hdrFromFdno() used to return a (hdr, isSource) tuple.\n"
681 "If you need to distinguish source/binary headers, do:\n"
685 " ts = rpm.TransactionSet()\n"
686 " fdno = os.open('/tmp/foo-1.0-1.i386.rpm', os.O_RDONLY)\n"
687 " hdr = ts.hdrFromFdno(fdno)\n"
689 " if hdr[rpm.RPMTAG_SOURCEPACKAGE]:\n"
690 " print 'header is from a source package'\n"
692 " print 'header is from a binary package'\n"
694 "The Python interface to the header data is quite elegant. It\n"
695 "presents the data in a dictionary form. We'll take the header we\n"
696 "just loaded and access the data within it:\n"
698 " print hdr[rpm.RPMTAG_NAME]\n"
699 " print hdr[rpm.RPMTAG_VERSION]\n"
700 " print hdr[rpm.RPMTAG_RELEASE]\n"
702 "in the case of our 'foo-1.0-1.i386.rpm' package, this code would\n"
708 "You make also access the header data by string name:\n"
710 " print hdr['name']\n"
711 " print hdr['version']\n"
712 " print hdr['release']\n"
714 "This method of access is a teensy bit slower because the name must be\n"
715 "translated into the tag number dynamically. You also must make sure\n"
716 "the strings in header lookups don't get translated, or the lookups\n"
719 PyTypeObject hdr_Type = {
720 PyVarObject_HEAD_INIT(&PyType_Type, 0)
721 PYTHON_MODULENAME".hdr", /* tp_name */
722 sizeof(hdrObject), /* tp_size */
724 (destructor) hdr_dealloc, /* tp_dealloc */
726 (getattrfunc) 0, /* tp_getattr */
730 0, /* tp_as_number */
731 &hdr_as_sequence, /* tp_as_sequence */
732 &hdr_as_mapping, /* tp_as_mapping */
733 hdr_hash, /* tp_hash */
736 (getattrofunc) hdr_getattro, /* tp_getattro */
737 (setattrofunc) hdr_setattro, /* tp_setattro */
738 0, /* tp_as_buffer */
739 Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, /* tp_flags */
740 hdr_doc, /* tp_doc */
743 0, /* tp_richcompare */
744 0, /* tp_weaklistoffset */
745 PyObject_SelfIter, /* tp_iter */
746 (iternextfunc)hdr_iternext, /* tp_iternext */
747 hdr_methods, /* tp_methods */
752 0, /* tp_descr_get */
753 0, /* tp_descr_set */
754 0, /* tp_dictoffset */
757 hdr_new, /* tp_new */
762 PyObject * hdr_Wrap(PyTypeObject *subtype, Header h)
764 hdrObject * hdr = (hdrObject *)subtype->tp_alloc(subtype, 0);
765 if (hdr == NULL) return NULL;
767 return (PyObject *) hdr;
770 int hdrFromPyObject(PyObject *item, Header *hptr)
772 if (hdrObject_Check(item)) {
773 *hptr = ((hdrObject *) item)->h;
776 PyErr_SetString(PyExc_TypeError, "header object expected");
782 * This assumes the order of list matches the order of the new headers, and
783 * throws an exception if that isn't true.
785 static int rpmMergeHeaders(PyObject * list, FD_t fd, int matchTag)
789 rpmTagVal newMatch, oldMatch;
791 rpm_count_t count = 0;
792 int rc = 1; /* assume failure */
793 rpmtd td = rpmtdNew();
795 Py_BEGIN_ALLOW_THREADS
796 h = headerRead(fd, HEADER_MAGIC_YES);
800 if (!headerGet(h, matchTag, td, HEADERGET_MINMEM)) {
801 PyErr_SetString(pyrpmError, "match tag missing in new header");
804 newMatch = rpmtdTag(td);
807 hdr = (hdrObject *) PyList_GetItem(list, count++);
810 if (!headerGet(hdr->h, matchTag, td, HEADERGET_MINMEM)) {
811 PyErr_SetString(pyrpmError, "match tag missing in new header");
814 oldMatch = rpmtdTag(td);
817 if (newMatch != oldMatch) {
818 PyErr_SetString(pyrpmError, "match tag mismatch");
822 for (hi = headerInitIterator(h); headerNext(hi, td); rpmtdFreeData(td))
825 headerDel(hdr->h, rpmtdTag(td));
826 headerPut(hdr->h, td, HEADERPUT_DEFAULT);
829 headerFreeIterator(hi);
832 Py_BEGIN_ALLOW_THREADS
833 h = headerRead(fd, HEADER_MAGIC_YES);
844 rpmMergeHeadersFromFD(PyObject * self, PyObject * args, PyObject * kwds)
851 char * kwlist[] = {"list", "fd", "matchTag", NULL};
853 if (!PyArg_ParseTupleAndKeywords(args, kwds, "Oii", kwlist, &list,
857 if (!PyList_Check(list)) {
858 PyErr_SetString(PyExc_TypeError, "first parameter must be a list");
864 rc = rpmMergeHeaders (list, fd, matchTag);
874 PyObject * versionCompare (PyObject * self, PyObject * args, PyObject * kwds)
876 hdrObject * h1, * h2;
877 char * kwlist[] = {"version0", "version1", NULL};
879 if (!PyArg_ParseTupleAndKeywords(args, kwds, "O!O!", kwlist, &hdr_Type,
880 &h1, &hdr_Type, &h2))
883 return Py_BuildValue("i", rpmVersionCompare(h1->h, h2->h));
886 static int compare_values(const char *str1, const char *str2)
890 else if (str1 && !str2)
892 else if (!str1 && str2)
894 return rpmvercmp(str1, str2);
897 PyObject * labelCompare (PyObject * self, PyObject * args)
899 const char *v1, *r1, *v2, *r2;
903 if (!PyArg_ParseTuple(args, "(zzz)(zzz)",
904 &e1, &v1, &r1, &e2, &v2, &r2))
907 if (e1 == NULL) e1 = "0";
908 if (e2 == NULL) e2 = "0";
910 rc = compare_values(e1, e2);
912 rc = compare_values(v1, v2);
914 rc = compare_values(r1, r2);
916 return Py_BuildValue("i", rc);