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
132 static PyObject * hdrKeyList(hdrObject * s)
136 rpmtd td = rpmtdNew();
138 list = PyList_New(0);
140 hi = headerInitIterator(s->h);
141 while (headerNext(hi, td)) {
142 rpmTag tag = rpmtdTag(td);
143 if (tag == HEADER_I18NTABLE) continue;
145 switch (rpmtdType(td)) {
151 case RPM_STRING_ARRAY_TYPE:
152 case RPM_STRING_TYPE:
153 PyList_Append(list, o=PyInt_FromLong(tag));
156 case RPM_I18NSTRING_TYPE: /* hum.. ?`*/
163 headerFreeIterator(hi);
169 static PyObject * hdrUnload(hdrObject * s, PyObject * args, PyObject *keywords)
175 static char *kwlist[] = { "legacyHeader", NULL};
177 if (!PyArg_ParseTupleAndKeywords(args, keywords, "|i", kwlist, &legacy))
180 h = headerLink(s->h);
181 /* XXX this legacy switch is a hack, needs to be removed. */
183 h = headerCopy(s->h); /* XXX strip region tags, etc */
186 len = headerSizeof(h, 0);
187 buf = headerUnload(h);
190 if (buf == NULL || len == 0) {
191 PyErr_SetString(pyrpmError, "can't unload bad header\n");
195 rc = PyString_FromStringAndSize(buf, len);
201 static PyObject * hdrExpandFilelist(hdrObject * s)
203 headerConvert(s->h, HEADERCONV_EXPANDFILELIST);
208 static PyObject * hdrCompressFilelist(hdrObject * s)
210 headerConvert(s->h, HEADERCONV_COMPRESSFILELIST);
215 /* make a header with _all_ the tags we need */
216 static void mungeFilelist(Header h)
218 rpmtd fileNames = rpmtdNew();
220 if (!headerIsEntry (h, RPMTAG_BASENAMES)
221 || !headerIsEntry (h, RPMTAG_DIRNAMES)
222 || !headerIsEntry (h, RPMTAG_DIRINDEXES))
223 headerConvert(h, HEADERCONV_COMPRESSFILELIST);
225 if (headerGet(h, RPMTAG_FILENAMES, fileNames, HEADERGET_EXT)) {
226 rpmtdSetTag(fileNames, RPMTAG_OLDFILENAMES);
227 headerPut(h, fileNames, HEADERPUT_DEFAULT);
228 rpmtdFreeData(fileNames);
230 rpmtdFree(fileNames);
233 static PyObject * hdrFullFilelist(hdrObject * s)
235 mungeFilelist (s->h);
240 static PyObject * hdrSprintf(hdrObject * s, PyObject * args, PyObject * kwds)
246 char * kwlist[] = {"format", NULL};
248 if (!PyArg_ParseTupleAndKeywords(args, kwds, "s", kwlist, &fmt))
251 r = headerFormat(s->h, fmt, &err);
253 PyErr_SetString(pyrpmError, err);
257 result = Py_BuildValue("s", r);
263 static PyObject *hdrIsSource(hdrObject *s)
265 return PyBool_FromLong(headerIsSource(s->h));
268 static int hdr_compare(hdrObject * a, hdrObject * b)
270 return rpmVersionCompare(a->h, b->h);
273 static long hdr_hash(PyObject * h)
278 static struct PyMethodDef hdr_methods[] = {
279 {"keys", (PyCFunction) hdrKeyList, METH_NOARGS,
281 {"unload", (PyCFunction) hdrUnload, METH_VARARGS|METH_KEYWORDS,
283 {"expandFilelist", (PyCFunction) hdrExpandFilelist,METH_NOARGS,
285 {"compressFilelist",(PyCFunction) hdrCompressFilelist,METH_NOARGS,
287 {"fullFilelist", (PyCFunction) hdrFullFilelist, METH_NOARGS,
289 {"sprintf", (PyCFunction) hdrSprintf, METH_VARARGS|METH_KEYWORDS,
291 {"isSource", (PyCFunction)hdrIsSource, METH_NOARGS,
294 {"dsOfHeader", (PyCFunction)hdr_dsOfHeader, METH_NOARGS,
296 {"dsFromHeader", (PyCFunction)hdr_dsFromHeader, METH_VARARGS|METH_KEYWORDS,
298 {"fiFromHeader", (PyCFunction)hdr_fiFromHeader, METH_VARARGS|METH_KEYWORDS,
301 {NULL, NULL} /* sentinel */
304 static void hdr_dealloc(hdrObject * s)
306 if (s->h) headerFree(s->h);
310 rpmTag tagNumFromPyObject (PyObject *item)
312 rpmTag tag = RPMTAG_NOT_FOUND;
314 if (PyInt_Check(item)) {
315 /* XXX we should probably validate tag numbers too */
316 tag = PyInt_AsLong(item);
317 } else if (PyString_Check(item)) {
318 tag = rpmTagGetValue(PyString_AsString(item));
320 if (tag == RPMTAG_NOT_FOUND) {
321 PyErr_SetString(PyExc_ValueError, "unknown header tag");
327 static PyObject * hdr_subscript(hdrObject * s, PyObject * item)
329 rpmTagType tagtype, type;
330 rpmTag tag = RPMTAG_NOT_FOUND;
331 rpm_count_t count, i;
333 PyObject * o, * metao;
338 tag = tagNumFromPyObject (item);
339 if (tag == RPMTAG_NOT_FOUND) return NULL;
341 tagtype = rpmTagGetType(tag);
342 forceArray = (tagtype & RPM_MASK_RETURN_TYPE) == RPM_ARRAY_RETURN_TYPE;
344 /* Retrieve data from extension or header. */
345 if (!headerGet(s->h, tag, &td, HEADERGET_EXT)) {
361 o = PyString_FromStringAndSize(data, count);
365 if (count != 1 || forceArray) {
366 metao = PyList_New(0);
367 for (i = 0; i < count; i++) {
368 o = PyInt_FromLong(((int *) data)[i]);
369 PyList_Append(metao, o);
374 o = PyInt_FromLong(*((int *) data));
380 if (count != 1 || forceArray) {
381 metao = PyList_New(0);
382 for (i = 0; i < count; i++) {
383 o = PyInt_FromLong(((char *) data)[i]);
384 PyList_Append(metao, o);
389 o = PyInt_FromLong(*((char *) data));
394 if (count != 1 || forceArray) {
395 metao = PyList_New(0);
396 for (i = 0; i < count; i++) {
397 o = PyInt_FromLong(((short *) data)[i]);
398 PyList_Append(metao, o);
403 o = PyInt_FromLong(*((short *) data));
407 case RPM_STRING_ARRAY_TYPE:
410 metao = PyList_New(0);
411 for (i = 0; i < count; i++) {
412 o = PyString_FromString(stringArray[i]);
413 PyList_Append(metao, o);
419 case RPM_STRING_TYPE:
420 case RPM_I18NSTRING_TYPE:
421 if (count != 1 || forceArray) {
424 metao = PyList_New(0);
425 for (i=0; i < count; i++) {
426 o = PyString_FromString(stringArray[i]);
427 PyList_Append(metao, o);
432 o = PyString_FromString(data);
437 PyErr_SetString(PyExc_TypeError, "unsupported type in header");
445 static PyObject * hdr_getattro(PyObject * o, PyObject * n)
448 res = PyObject_GenericGetAttr(o, n);
450 res = hdr_subscript((hdrObject *)o, n);
454 static int hdr_setattro(PyObject * o, PyObject * n, PyObject * v)
456 return PyObject_GenericSetAttr(o, n, v);
459 static PyMappingMethods hdr_as_mapping = {
460 (lenfunc) 0, /* mp_length */
461 (binaryfunc) hdr_subscript, /* mp_subscript */
462 (objobjargproc)0, /* mp_ass_subscript */
465 static char hdr_doc[] =
468 PyTypeObject hdr_Type = {
469 PyObject_HEAD_INIT(&PyType_Type)
471 "rpm.hdr", /* tp_name */
472 sizeof(hdrObject), /* tp_size */
474 (destructor) hdr_dealloc, /* tp_dealloc */
476 (getattrfunc) 0, /* tp_getattr */
478 (cmpfunc) hdr_compare, /* tp_compare */
480 0, /* tp_as_number */
481 0, /* tp_as_sequence */
482 &hdr_as_mapping, /* tp_as_mapping */
483 hdr_hash, /* tp_hash */
486 (getattrofunc) hdr_getattro, /* tp_getattro */
487 (setattrofunc) hdr_setattro, /* tp_setattro */
488 0, /* tp_as_buffer */
489 Py_TPFLAGS_DEFAULT, /* tp_flags */
490 hdr_doc, /* tp_doc */
493 0, /* tp_richcompare */
494 0, /* tp_weaklistoffset */
497 hdr_methods, /* tp_methods */
502 0, /* tp_descr_get */
503 0, /* tp_descr_set */
504 0, /* tp_dictoffset */
512 PyObject * hdr_Wrap(Header h)
514 hdrObject * hdr = PyObject_New(hdrObject, &hdr_Type);
515 if (hdr == NULL) return PyErr_NoMemory();
517 hdr->h = headerLink(h);
518 return (PyObject *) hdr;
521 Header hdrGetHeader(hdrObject * s)
526 PyObject * hdrLoad(PyObject * self, PyObject * args, PyObject * kwds)
532 char * kwlist[] = {"headers", NULL};
534 if (!PyArg_ParseTupleAndKeywords(args, kwds, "s#", kwlist, &obj, &len))
537 /* copy is needed to avoid surprises from data swab in headerLoad(). */
538 h = headerCopyLoad(obj);
540 PyErr_SetString(pyrpmError, "bad header");
543 headerConvert(h, HEADERCONV_RETROFIT_V3);
546 h = headerFree(h); /* XXX ref held by hdr */
551 PyObject * rpmReadHeaders (FD_t fd)
558 PyErr_SetFromErrno(pyrpmError);
562 list = PyList_New(0);
563 Py_BEGIN_ALLOW_THREADS
564 h = headerRead(fd, HEADER_MAGIC_YES);
568 headerConvert(h, HEADERCONV_RETROFIT_V3);
570 if (PyList_Append(list, (PyObject *) hdr)) {
577 h = headerFree(h); /* XXX ref held by hdr */
579 Py_BEGIN_ALLOW_THREADS
580 h = headerRead(fd, HEADER_MAGIC_YES);
587 PyObject * rpmHeaderFromFD(PyObject * self, PyObject * args, PyObject * kwds)
592 char * kwlist[] = {"fd", NULL};
594 if (!PyArg_ParseTupleAndKeywords(args, kwds, "i", kwlist, &fileno))
599 list = rpmReadHeaders (fd);
605 PyObject * rpmHeaderFromFile(PyObject * self, PyObject * args, PyObject *kwds)
610 char * kwlist[] = {"file", NULL};
612 if (!PyArg_ParseTupleAndKeywords(args, kwds, "s", kwlist, &filespec))
615 fd = Fopen(filespec, "r.fdio");
618 PyErr_SetFromErrno(pyrpmError);
622 list = rpmReadHeaders (fd);
629 * This assumes the order of list matches the order of the new headers, and
630 * throws an exception if that isn't true.
632 int rpmMergeHeaders(PyObject * list, FD_t fd, int matchTag)
636 rpmTag newMatch, oldMatch;
638 rpm_count_t count = 0;
639 int rc = 1; /* assume failure */
640 rpmtd td = rpmtdNew();
642 Py_BEGIN_ALLOW_THREADS
643 h = headerRead(fd, HEADER_MAGIC_YES);
647 if (!headerGet(h, matchTag, td, HEADERGET_MINMEM)) {
648 PyErr_SetString(pyrpmError, "match tag missing in new header");
651 newMatch = rpmtdTag(td);
654 hdr = (hdrObject *) PyList_GetItem(list, count++);
657 if (!headerGet(hdr->h, matchTag, td, HEADERGET_MINMEM)) {
658 PyErr_SetString(pyrpmError, "match tag missing in new header");
661 oldMatch = rpmtdTag(td);
664 if (newMatch != oldMatch) {
665 PyErr_SetString(pyrpmError, "match tag mismatch");
669 for (hi = headerInitIterator(h); headerNext(hi, td); rpmtdFreeData(td))
672 headerDel(hdr->h, rpmtdTag(td));
673 headerPut(hdr->h, td, HEADERPUT_DEFAULT);
676 headerFreeIterator(hi);
679 Py_BEGIN_ALLOW_THREADS
680 h = headerRead(fd, HEADER_MAGIC_YES);
691 rpmMergeHeadersFromFD(PyObject * self, PyObject * args, PyObject * kwds)
698 char * kwlist[] = {"list", "fd", "matchTag", NULL};
700 if (!PyArg_ParseTupleAndKeywords(args, kwds, "Oii", kwlist, &list,
704 if (!PyList_Check(list)) {
705 PyErr_SetString(PyExc_TypeError, "first parameter must be a list");
711 rc = rpmMergeHeaders (list, fd, matchTag);
722 rpmSingleHeaderFromFD(PyObject * self, PyObject * args, PyObject * kwds)
729 char * kwlist[] = {"fd", NULL};
731 if (!PyArg_ParseTupleAndKeywords(args, kwds, "i", kwlist, &fileno))
734 offset = lseek(fileno, 0, SEEK_CUR);
739 PyErr_SetFromErrno(pyrpmError);
743 Py_BEGIN_ALLOW_THREADS
744 h = headerRead(fd, HEADER_MAGIC_YES);
749 tuple = PyTuple_New(2);
752 PyTuple_SET_ITEM(tuple, 0, hdr_Wrap(h));
753 PyTuple_SET_ITEM(tuple, 1, PyLong_FromLong(offset));
758 PyTuple_SET_ITEM(tuple, 0, Py_None);
759 PyTuple_SET_ITEM(tuple, 1, Py_None);
765 PyObject * versionCompare (PyObject * self, PyObject * args, PyObject * kwds)
767 hdrObject * h1, * h2;
768 char * kwlist[] = {"version0", "version1", NULL};
770 if (!PyArg_ParseTupleAndKeywords(args, kwds, "O!O!", kwlist, &hdr_Type,
771 &h1, &hdr_Type, &h2))
774 return Py_BuildValue("i", hdr_compare(h1, h2));
777 static int compare_values(const char *str1, const char *str2)
781 else if (str1 && !str2)
783 else if (!str1 && str2)
785 return rpmvercmp(str1, str2);
788 PyObject * labelCompare (PyObject * self, PyObject * args)
790 char *v1, *r1, *v2, *r2;
794 if (!PyArg_ParseTuple(args, "(zzz)(zzz)",
795 &e1, &v1, &r1, &e2, &v2, &r2))
798 if (e1 == NULL) e1 = "0";
799 if (e2 == NULL) e2 = "0";
801 rc = compare_values(e1, e2);
803 rc = compare_values(v1, v2);
805 rc = compare_values(r1, r2);
807 return Py_BuildValue("i", rc);