2 * \file python/header-py.c
7 #include <rpm/rpmlib.h> /* rpmvercmp */
8 #include <rpm/rpmtag.h>
9 #include <rpm/rpmstring.h>
10 #include <rpm/rpmts.h> /* XXX rpmtsCreate/rpmtsFree */
12 #include "lib/legacy.h" /* XXX expand/compressFilelist(), providePackageNVR() */
14 #include "header-py.h"
22 * \brief START HERE / RPM base module for the Python API
24 * The rpm base module provides the main starting point for
25 * accessing RPM from Python. For most usage, call
26 * the TransactionSet method to get a transaction set (rpmts).
32 * ts = rpm.TransactionSet()
35 * The transaction set will open the RPM database as needed, so
36 * in most cases, you do not need to explicitly open the
37 * database. The transaction set is the workhorse of RPM.
39 * You can open another RPM database, such as one that holds
40 * all packages for a given Linux distribution, to provide
41 * packages used to solve dependencies. To do this, use
45 * rpm.addMacro('_dbpath', '/path/to/alternate/database')
46 * solvets = rpm.TransactionSet()
48 * rpm.delMacro('_dbpath')
50 * # Open default database
51 * ts = rpm.TransactionSet()
54 * This code gives you access to two RPM databases through
55 * two transaction sets (rpmts): ts is a transaction set
56 * associated with the default RPM database and solvets
57 * is a transaction set tied to an alternate database, which
58 * is very useful for resolving dependencies.
60 * The rpm methods used here are:
62 * - addMacro(macro, value)
63 * @param macro Name of macro to add
64 * @param value Value for the macro
67 * @param macro Name of macro to delete
73 * \brief A python header object represents an RPM package header.
75 * All RPM packages have headers that provide metadata for the package.
76 * Header objects can be returned by database queries or loaded from a
77 * binary package on disk.
79 * The ts.hdrFromFdno() function returns the package header from a
80 * package on disk, verifying package signatures and digests of the
81 * package while reading.
83 * Note: The older method rpm.headerFromPackage() which has been replaced
84 * by ts.hdrFromFdno() used to return a (hdr, isSource) tuple.
86 * If you need to distinguish source/binary headers, do:
90 * ts = rpm.TranssactionSet()
91 * fdno = os.open("/tmp/foo-1.0-1.i386.rpm", os.O_RDONLY)
92 * hdr = ts.hdrFromFdno(fdno)
94 * if hdr[rpm.RPMTAG_SOURCEPACKAGE]:
95 * print "header is from a source package"
97 * print "header is from a binary package"
100 * The Python interface to the header data is quite elegant. It
101 * presents the data in a dictionary form. We'll take the header we
102 * just loaded and access the data within it:
104 * print hdr[rpm.RPMTAG_NAME]
105 * print hdr[rpm.RPMTAG_VERSION]
106 * print hdr[rpm.RPMTAG_RELEASE]
108 * in the case of our "foo-1.0-1.i386.rpm" package, this code would
116 * You make also access the header data by string name:
119 * print hdr['version']
120 * print hdr['release']
123 * This method of access is a teensy bit slower because the name must be
124 * translated into the tag number dynamically. You also must make sure
125 * the strings in header lookups don't get translated, or the lookups
130 * \name Class: rpm.hdr
142 static PyObject * hdrKeyList(hdrObject * s)
149 list = PyList_New(0);
151 hi = headerInitIterator(s->h);
152 while (headerNextIterator(hi, &tag, &type, NULL, NULL)) {
153 if (tag == HEADER_I18NTABLE) continue;
161 case RPM_STRING_ARRAY_TYPE:
162 case RPM_STRING_TYPE:
163 PyList_Append(list, o=PyInt_FromLong(tag));
166 case RPM_I18NSTRING_TYPE: /* hum.. ?`*/
172 headerFreeIterator(hi);
179 static PyObject * hdrUnload(hdrObject * s, PyObject * args, PyObject *keywords)
185 static char *kwlist[] = { "legacyHeader", NULL};
187 if (!PyArg_ParseTupleAndKeywords(args, keywords, "|i", kwlist, &legacy))
190 h = headerLink(s->h);
191 /* XXX this legacy switch is a hack, needs to be removed. */
193 h = headerCopy(s->h); /* XXX strip region tags, etc */
196 len = headerSizeof(h, 0);
197 buf = headerUnload(h);
200 if (buf == NULL || len == 0) {
201 PyErr_SetString(pyrpmError, "can't unload bad header\n");
205 rc = PyString_FromStringAndSize(buf, len);
213 static PyObject * hdrExpandFilelist(hdrObject * s)
215 expandFilelist (s->h);
223 static PyObject * hdrCompressFilelist(hdrObject * s)
225 compressFilelist (s->h);
231 /* make a header with _all_ the tags we need */
234 static void mungeFilelist(Header h)
236 const char ** fileNames = NULL;
237 rpm_count_t count = 0;
239 if (!headerIsEntry (h, RPMTAG_BASENAMES)
240 || !headerIsEntry (h, RPMTAG_DIRNAMES)
241 || !headerIsEntry (h, RPMTAG_DIRINDEXES))
244 rpmfiBuildFNames(h, RPMTAG_BASENAMES, &fileNames, &count);
246 if (fileNames == NULL || count <= 0)
249 /* XXX Legacy tag needs to go away. */
250 headerAddEntry(h, RPMTAG_OLDFILENAMES, RPM_STRING_ARRAY_TYPE,
253 fileNames = _free(fileNames);
258 static PyObject * hdrFullFilelist(hdrObject * s)
260 mungeFilelist (s->h);
268 static PyObject * hdrSprintf(hdrObject * s, PyObject * args, PyObject * kwds)
274 char * kwlist[] = {"format", NULL};
276 if (!PyArg_ParseTupleAndKeywords(args, kwds, "s", kwlist, &fmt))
279 r = headerSprintf(s->h, fmt, rpmTagTable, rpmHeaderFormats, &err);
281 PyErr_SetString(pyrpmError, err);
285 result = Py_BuildValue("s", r);
293 static int hdr_compare(hdrObject * a, hdrObject * b)
295 return rpmVersionCompare(a->h, b->h);
298 static long hdr_hash(PyObject * h)
305 static struct PyMethodDef hdr_methods[] = {
306 {"keys", (PyCFunction) hdrKeyList, METH_NOARGS,
308 {"unload", (PyCFunction) hdrUnload, METH_VARARGS|METH_KEYWORDS,
310 {"expandFilelist", (PyCFunction) hdrExpandFilelist,METH_NOARGS,
312 {"compressFilelist",(PyCFunction) hdrCompressFilelist,METH_NOARGS,
314 {"fullFilelist", (PyCFunction) hdrFullFilelist, METH_NOARGS,
316 {"sprintf", (PyCFunction) hdrSprintf, METH_VARARGS|METH_KEYWORDS,
319 {"dsOfHeader", (PyCFunction)hdr_dsOfHeader, METH_NOARGS,
321 {"dsFromHeader", (PyCFunction)hdr_dsFromHeader, METH_VARARGS|METH_KEYWORDS,
323 {"fiFromHeader", (PyCFunction)hdr_fiFromHeader, METH_VARARGS|METH_KEYWORDS,
326 {NULL, NULL} /* sentinel */
331 static void hdr_dealloc(hdrObject * s)
333 if (s->h) headerFree(s->h);
339 rpm_tag_t tagNumFromPyObject (PyObject *item)
343 if (PyInt_Check(item)) {
344 return PyInt_AsLong(item);
345 } else if (PyString_Check(item)) {
346 str = PyString_AsString(item);
347 return rpmTagGetValue(str);
349 return RPMTAG_NOT_FOUND;
353 * Retrieve tag info from header.
354 * This is a "dressed" entry to headerGetEntry to do:
355 * 1) DIRNAME/BASENAME/DIRINDICES -> FILENAMES tag conversions.
356 * 2) i18n lookaside (if enabled).
360 * @retval type address of tag value data type
361 * @retval p address of pointer to tag value(s)
362 * @retval c address of number of values
363 * @return 0 on success, 1 on bad magic, 2 on error
365 static int dressedHeaderGetEntry(Header h, rpm_tag_t tag, rpmTagType *type,
366 void **p, rpm_count_t *c)
369 case RPMTAG_OLDFILENAMES:
370 { const char ** fl = NULL;
372 rpmfiBuildFNames(h, RPMTAG_BASENAMES, &fl, &count);
376 if (type) *type = RPM_STRING_ARRAY_TYPE;
384 case RPMTAG_DESCRIPTION:
391 (void) stpcpy( stpcpy( stpcpy( fmt, "%{"), rpmTagGetName(tag)), "}\n");
393 /* XXX FIXME: memory leak. */
394 msgstr = headerSprintf(h, fmt, rpmTagTable, rpmHeaderFormats, &errstr);
396 *p = (void *) msgstr;
397 if (type) *type = RPM_STRING_TYPE;
407 return headerGetEntry(h, tag, type, p, c);
414 static PyObject * hdr_subscript(hdrObject * s, PyObject * item)
416 rpmTagType tagtype, type;
417 rpm_tag_t tag = RPMTAG_NOT_FOUND;
418 rpm_count_t count, i;
420 PyObject * o, * metao;
425 const struct headerSprintfExtension_s * ext = NULL;
426 const struct headerSprintfExtension_s * extensions = rpmHeaderFormats;
428 if (PyCObject_Check (item))
429 ext = PyCObject_AsVoidPtr(item);
431 tag = tagNumFromPyObject (item);
432 if (tag == RPMTAG_NOT_FOUND && PyString_Check(item)) {
433 /* if we still don't have the tag, go looking for the header
435 str = PyString_AsString(item);
436 while (extensions->name) {
437 if (extensions->type == HEADER_EXT_TAG
438 && !xstrcasecmp(extensions->name + 7, str)) {
445 /* Retrieve data from extension or header. */
447 ext->u.tagFunction(s->h, &type, &data, &count, &freeData);
449 if (tag == RPMTAG_NOT_FOUND) {
450 PyErr_SetString(PyExc_KeyError, "unknown header tag");
454 if (!dressedHeaderGetEntry(s->h, tag, &type, &data, &count)) {
466 return PyList_New(0);
472 tagtype = rpmTagGetType(tag);
474 /* this blows up with header extension types */
475 type = tagtype & RPM_MASK_TYPE;
477 forceArray = (tagtype & RPM_MASK_RETURN_TYPE) == RPM_ARRAY_RETURN_TYPE;
478 freeData = (tagtype & RPM_MASK_TYPE) == RPM_I18NSTRING_TYPE;
482 o = PyString_FromStringAndSize(data, count);
486 if (count != 1 || forceArray) {
487 metao = PyList_New(0);
488 for (i = 0; i < count; i++) {
489 o = PyInt_FromLong(((int *) data)[i]);
490 PyList_Append(metao, o);
495 o = PyInt_FromLong(*((int *) data));
501 if (count != 1 || forceArray) {
502 metao = PyList_New(0);
503 for (i = 0; i < count; i++) {
504 o = PyInt_FromLong(((char *) data)[i]);
505 PyList_Append(metao, o);
510 o = PyInt_FromLong(*((char *) data));
515 if (count != 1 || forceArray) {
516 metao = PyList_New(0);
517 for (i = 0; i < count; i++) {
518 o = PyInt_FromLong(((short *) data)[i]);
519 PyList_Append(metao, o);
524 o = PyInt_FromLong(*((short *) data));
528 case RPM_STRING_ARRAY_TYPE:
531 metao = PyList_New(0);
532 for (i = 0; i < count; i++) {
533 o = PyString_FromString(stringArray[i]);
534 PyList_Append(metao, o);
541 case RPM_STRING_TYPE:
542 case RPM_I18NSTRING_TYPE:
543 if (count != 1 || forceArray) {
546 metao = PyList_New(0);
547 for (i=0; i < count; i++) {
548 o = PyString_FromString(stringArray[i]);
549 PyList_Append(metao, o);
554 o = PyString_FromString(data);
561 PyErr_SetString(PyExc_TypeError, "unsupported type in header");
568 static PyObject * hdr_getattro(PyObject * o, PyObject * n)
571 res = PyObject_GenericGetAttr(o, n);
573 res = hdr_subscript(o, n);
577 static int hdr_setattro(PyObject * o, PyObject * n, PyObject * v)
579 return PyObject_GenericSetAttr(o, n, v);
584 static PyMappingMethods hdr_as_mapping = {
585 (lenfunc) 0, /* mp_length */
586 (binaryfunc) hdr_subscript, /* mp_subscript */
587 (objobjargproc)0, /* mp_ass_subscript */
592 static char hdr_doc[] =
597 PyTypeObject hdr_Type = {
598 PyObject_HEAD_INIT(&PyType_Type)
600 "rpm.hdr", /* tp_name */
601 sizeof(hdrObject), /* tp_size */
603 (destructor) hdr_dealloc, /* tp_dealloc */
605 (getattrfunc) 0, /* tp_getattr */
607 (cmpfunc) hdr_compare, /* tp_compare */
609 0, /* tp_as_number */
610 0, /* tp_as_sequence */
611 &hdr_as_mapping, /* tp_as_mapping */
612 hdr_hash, /* tp_hash */
615 (getattrofunc) hdr_getattro, /* tp_getattro */
616 (setattrofunc) hdr_setattro, /* tp_setattro */
617 0, /* tp_as_buffer */
618 Py_TPFLAGS_DEFAULT, /* tp_flags */
619 hdr_doc, /* tp_doc */
620 #if Py_TPFLAGS_HAVE_ITER
623 0, /* tp_richcompare */
624 0, /* tp_weaklistoffset */
627 hdr_methods, /* tp_methods */
632 0, /* tp_descr_get */
633 0, /* tp_descr_set */
634 0, /* tp_dictoffset */
643 hdrObject * hdr_Wrap(Header h)
645 hdrObject * hdr = PyObject_New(hdrObject, &hdr_Type);
646 hdr->h = headerLink(h);
650 Header hdrGetHeader(hdrObject * s)
657 PyObject * hdrLoad(PyObject * self, PyObject * args, PyObject * kwds)
663 char * kwlist[] = {"headers", NULL};
665 if (!PyArg_ParseTupleAndKeywords(args, kwds, "s#", kwlist, &obj, &len))
668 /* copy is needed to avoid surprises from data swab in headerLoad(). */
669 h = headerCopyLoad(obj);
671 if (errno == ENOMEM) {
672 PyErr_SetString(pyrpmError, "out of memory");
674 PyErr_SetString(pyrpmError, "bad header");
678 compressFilelist (h);
679 providePackageNVR (h);
682 h = headerFree(h); /* XXX ref held by hdr */
684 return (PyObject *) hdr;
689 PyObject * rpmReadHeaders (FD_t fd)
696 PyErr_SetFromErrno(pyrpmError);
700 list = PyList_New(0);
701 Py_BEGIN_ALLOW_THREADS
702 h = headerRead(fd, HEADER_MAGIC_YES);
707 providePackageNVR(h);
709 if (PyList_Append(list, (PyObject *) hdr)) {
716 h = headerFree(h); /* XXX ref held by hdr */
718 Py_BEGIN_ALLOW_THREADS
719 h = headerRead(fd, HEADER_MAGIC_YES);
728 PyObject * rpmHeaderFromFD(PyObject * self, PyObject * args, PyObject * kwds)
733 char * kwlist[] = {"fd", NULL};
735 if (!PyArg_ParseTupleAndKeywords(args, kwds, "i", kwlist, &fileno))
740 list = rpmReadHeaders (fd);
748 PyObject * rpmHeaderFromFile(PyObject * self, PyObject * args, PyObject *kwds)
753 char * kwlist[] = {"file", NULL};
755 if (!PyArg_ParseTupleAndKeywords(args, kwds, "s", kwlist, &filespec))
758 fd = Fopen(filespec, "r.fdio");
761 PyErr_SetFromErrno(pyrpmError);
765 list = rpmReadHeaders (fd);
772 * This assumes the order of list matches the order of the new headers, and
773 * throws an exception if that isn't true.
775 int rpmMergeHeaders(PyObject * list, FD_t fd, int matchTag)
782 rpm_count_t c, count = 0;
787 Py_BEGIN_ALLOW_THREADS
788 h = headerRead(fd, HEADER_MAGIC_YES);
792 if (!headerGetEntry(h, matchTag, NULL, (void **) &newMatch, NULL)) {
793 PyErr_SetString(pyrpmError, "match tag missing in new header");
797 hdr = (hdrObject *) PyList_GetItem(list, count++);
800 if (!headerGetEntry(hdr->h, matchTag, NULL, (void **) &oldMatch, NULL)) {
801 PyErr_SetString(pyrpmError, "match tag missing in new header");
805 if (*newMatch != *oldMatch) {
806 PyErr_SetString(pyrpmError, "match tag mismatch");
810 for (hi = headerInitIterator(h);
811 headerNextIterator(hi, &tag, &type, (void *) &p, &c);
812 p = headerFreeData(p, type))
815 headerRemoveEntry(hdr->h, tag);
816 headerAddEntry(hdr->h, tag, type, p, c);
819 headerFreeIterator(hi);
822 Py_BEGIN_ALLOW_THREADS
823 h = headerRead(fd, HEADER_MAGIC_YES);
831 rpmMergeHeadersFromFD(PyObject * self, PyObject * args, PyObject * kwds)
838 char * kwlist[] = {"list", "fd", "matchTag", NULL};
840 if (!PyArg_ParseTupleAndKeywords(args, kwds, "Oii", kwlist, &list,
844 if (!PyList_Check(list)) {
845 PyErr_SetString(PyExc_TypeError, "first parameter must be a list");
851 rc = rpmMergeHeaders (list, fd, matchTag);
865 rpmSingleHeaderFromFD(PyObject * self, PyObject * args, PyObject * kwds)
872 char * kwlist[] = {"fd", NULL};
874 if (!PyArg_ParseTupleAndKeywords(args, kwds, "i", kwlist, &fileno))
877 offset = lseek(fileno, 0, SEEK_CUR);
882 PyErr_SetFromErrno(pyrpmError);
886 Py_BEGIN_ALLOW_THREADS
887 h = headerRead(fd, HEADER_MAGIC_YES);
892 tuple = PyTuple_New(2);
895 PyTuple_SET_ITEM(tuple, 0, (PyObject *) hdr_Wrap(h));
896 PyTuple_SET_ITEM(tuple, 1, PyLong_FromLong(offset));
901 PyTuple_SET_ITEM(tuple, 0, Py_None);
902 PyTuple_SET_ITEM(tuple, 1, Py_None);
910 PyObject * versionCompare (PyObject * self, PyObject * args, PyObject * kwds)
912 hdrObject * h1, * h2;
913 char * kwlist[] = {"version0", "version1", NULL};
915 if (!PyArg_ParseTupleAndKeywords(args, kwds, "O!O!", kwlist, &hdr_Type,
916 &h1, &hdr_Type, &h2))
919 return Py_BuildValue("i", hdr_compare(h1, h2));
924 static int compare_values(const char *str1, const char *str2)
928 else if (str1 && !str2)
930 else if (!str1 && str2)
932 return rpmvercmp(str1, str2);
935 PyObject * labelCompare (PyObject * self, PyObject * args)
937 char *v1, *r1, *v2, *r2;
941 if (!PyArg_ParseTuple(args, "(zzz)(zzz)",
942 &e1, &v1, &r1, &e2, &v2, &r2))
945 if (e1 == NULL) e1 = "0";
946 if (e2 == NULL) e2 = "0";
948 rc = compare_values(e1, e2);
950 rc = compare_values(v1, v2);
952 rc = compare_values(r1, r2);
954 return Py_BuildValue("i", rc);