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 */
18 * \brief START HERE / RPM base module for the Python API
20 * The rpm base module provides the main starting point for
21 * accessing RPM from Python. For most usage, call
22 * the TransactionSet method to get a transaction set (rpmts).
28 * ts = rpm.TransactionSet()
31 * The transaction set will open the RPM database as needed, so
32 * in most cases, you do not need to explicitly open the
33 * database. The transaction set is the workhorse of RPM.
35 * You can open another RPM database, such as one that holds
36 * all packages for a given Linux distribution, to provide
37 * packages used to solve dependencies. To do this, use
41 * rpm.addMacro('_dbpath', '/path/to/alternate/database')
42 * solvets = rpm.TransactionSet()
44 * rpm.delMacro('_dbpath')
46 * # Open default database
47 * ts = rpm.TransactionSet()
50 * This code gives you access to two RPM databases through
51 * two transaction sets (rpmts): ts is a transaction set
52 * associated with the default RPM database and solvets
53 * is a transaction set tied to an alternate database, which
54 * is very useful for resolving dependencies.
56 * The rpm methods used here are:
58 * - addMacro(macro, value)
59 * @param macro Name of macro to add
60 * @param value Value for the macro
63 * @param macro Name of macro to delete
69 * \brief A python header object represents an RPM package header.
71 * All RPM packages have headers that provide metadata for the package.
72 * Header objects can be returned by database queries or loaded from a
73 * binary package on disk.
75 * The ts.hdrFromFdno() function returns the package header from a
76 * package on disk, verifying package signatures and digests of the
77 * package while reading.
79 * Note: The older method rpm.headerFromPackage() which has been replaced
80 * by ts.hdrFromFdno() used to return a (hdr, isSource) tuple.
82 * If you need to distinguish source/binary headers, do:
86 * ts = rpm.TransactionSet()
87 * fdno = os.open("/tmp/foo-1.0-1.i386.rpm", os.O_RDONLY)
88 * hdr = ts.hdrFromFdno(fdno)
90 * if hdr[rpm.RPMTAG_SOURCEPACKAGE]:
91 * print "header is from a source package"
93 * print "header is from a binary package"
96 * The Python interface to the header data is quite elegant. It
97 * presents the data in a dictionary form. We'll take the header we
98 * just loaded and access the data within it:
100 * print hdr[rpm.RPMTAG_NAME]
101 * print hdr[rpm.RPMTAG_VERSION]
102 * print hdr[rpm.RPMTAG_RELEASE]
104 * in the case of our "foo-1.0-1.i386.rpm" package, this code would
112 * You make also access the header data by string name:
115 * print hdr['version']
116 * print hdr['release']
119 * This method of access is a teensy bit slower because the name must be
120 * translated into the tag number dynamically. You also must make sure
121 * the strings in header lookups don't get translated, or the lookups
126 * \name Class: rpm.hdr
135 static PyObject * hdrKeyList(hdrObject * s)
137 PyObject * keys = PyList_New(0);
138 HeaderIterator hi = headerInitIterator(s->h);
141 while ((tag = headerNextTag(hi)) != RPMTAG_NOT_FOUND) {
142 PyList_Append(keys, PyInt_FromLong(tag));
144 headerFreeIterator(hi);
149 static PyObject * hdrUnload(hdrObject * s, PyObject * args, PyObject *keywords)
155 static char *kwlist[] = { "legacyHeader", NULL};
157 if (!PyArg_ParseTupleAndKeywords(args, keywords, "|i", kwlist, &legacy))
160 h = headerLink(s->h);
161 /* XXX this legacy switch is a hack, needs to be removed. */
163 h = headerCopy(s->h); /* XXX strip region tags, etc */
166 len = headerSizeof(h, 0);
167 buf = headerUnload(h);
170 if (buf == NULL || len == 0) {
171 PyErr_SetString(pyrpmError, "can't unload bad header\n");
175 rc = PyBytes_FromStringAndSize(buf, len);
181 static PyObject * hdrExpandFilelist(hdrObject * s)
183 DEPRECATED_METHOD("use hdr.convert() instead");
184 headerConvert(s->h, HEADERCONV_EXPANDFILELIST);
189 static PyObject * hdrCompressFilelist(hdrObject * s)
191 DEPRECATED_METHOD("use hdr.convert() instead");
192 headerConvert(s->h, HEADERCONV_COMPRESSFILELIST);
197 /* make a header with _all_ the tags we need */
198 static PyObject * hdrFullFilelist(hdrObject * s)
200 rpmtd fileNames = rpmtdNew();
203 DEPRECATED_METHOD("obsolete method");
204 if (!headerIsEntry (h, RPMTAG_BASENAMES)
205 || !headerIsEntry (h, RPMTAG_DIRNAMES)
206 || !headerIsEntry (h, RPMTAG_DIRINDEXES))
207 headerConvert(h, HEADERCONV_COMPRESSFILELIST);
209 if (headerGet(h, RPMTAG_FILENAMES, fileNames, HEADERGET_EXT)) {
210 rpmtdSetTag(fileNames, RPMTAG_OLDFILENAMES);
211 headerPut(h, fileNames, HEADERPUT_DEFAULT);
212 rpmtdFreeData(fileNames);
214 rpmtdFree(fileNames);
219 static PyObject * hdrFormat(hdrObject * s, PyObject * args, PyObject * kwds)
225 char * kwlist[] = {"format", NULL};
227 if (!PyArg_ParseTupleAndKeywords(args, kwds, "s", kwlist, &fmt))
230 r = headerFormat(s->h, fmt, &err);
232 PyErr_SetString(pyrpmError, err);
236 result = Py_BuildValue("s", r);
242 static PyObject *hdrIsSource(hdrObject *s)
244 return PyBool_FromLong(headerIsSource(s->h));
247 static int hdrContains(hdrObject *s, PyObject *pytag)
250 if (!tagNumFromPyObject(pytag, &tag)) return -1;
252 return headerIsEntry(s->h, tag);
255 static PyObject *hdrConvert(hdrObject *self, PyObject *args, PyObject *kwds)
257 char *kwlist[] = {"op", NULL};
258 headerConvOps op = -1;
260 if (!PyArg_ParseTupleAndKeywords(args, kwds, "i", kwlist, &op)) {
263 return PyBool_FromLong(headerConvert(self->h, op));
266 static PyObject * hdrWrite(hdrObject *s, PyObject *args, PyObject *kwds)
268 char *kwlist[] = { "file", "magic", NULL };
270 rpmfdObject *fdo = NULL;
273 if (!PyArg_ParseTupleAndKeywords(args, kwds, "O&|i", kwlist,
274 rpmfdFromPyObject, &fdo, &magic))
277 Py_BEGIN_ALLOW_THREADS;
278 rc = headerWrite(rpmfdGetFd(fdo), s->h,
279 magic ? HEADER_MAGIC_YES : HEADER_MAGIC_NO);
280 Py_END_ALLOW_THREADS;
282 if (rc) PyErr_SetFromErrno(PyExc_IOError);
283 Py_XDECREF(fdo); /* avoid messing up errno with file close */
289 static PyObject * hdr_fiFromHeader(PyObject * s, PyObject * args, PyObject * kwds)
291 /* XXX this isn't quite right wrt arg passing */
292 return PyObject_Call((PyObject *) &rpmfi_Type,
293 Py_BuildValue("(O)", s), kwds);
296 static PyObject * hdr_dsFromHeader(PyObject * s, PyObject * args, PyObject * kwds)
298 /* XXX this isn't quite right wrt arg passing */
299 return PyObject_Call((PyObject *) &rpmds_Type,
300 Py_BuildValue("(O)", s), kwds);
303 static PyObject * hdr_dsOfHeader(PyObject * s)
305 return PyObject_Call((PyObject *) &rpmds_Type,
306 Py_BuildValue("(Oi)", s, RPMTAG_NEVR), NULL);
309 static long hdr_hash(PyObject * h)
314 static struct PyMethodDef hdr_methods[] = {
315 {"keys", (PyCFunction) hdrKeyList, METH_NOARGS,
317 {"unload", (PyCFunction) hdrUnload, METH_VARARGS|METH_KEYWORDS,
319 {"expandFilelist", (PyCFunction) hdrExpandFilelist,METH_NOARGS,
321 {"compressFilelist",(PyCFunction) hdrCompressFilelist,METH_NOARGS,
323 {"fullFilelist", (PyCFunction) hdrFullFilelist, METH_NOARGS,
325 {"convert", (PyCFunction) hdrConvert, METH_VARARGS|METH_KEYWORDS,
327 {"format", (PyCFunction) hdrFormat, METH_VARARGS|METH_KEYWORDS,
329 {"sprintf", (PyCFunction) hdrFormat, METH_VARARGS|METH_KEYWORDS,
331 {"isSource", (PyCFunction)hdrIsSource, METH_NOARGS,
333 {"write", (PyCFunction)hdrWrite, METH_VARARGS|METH_KEYWORDS,
335 {"dsOfHeader", (PyCFunction)hdr_dsOfHeader, METH_NOARGS,
337 {"dsFromHeader", (PyCFunction)hdr_dsFromHeader, METH_VARARGS|METH_KEYWORDS,
339 {"fiFromHeader", (PyCFunction)hdr_fiFromHeader, METH_VARARGS|METH_KEYWORDS,
342 {NULL, NULL} /* sentinel */
345 /* TODO: permit keyring check + retrofits on copy/load */
346 static PyObject *hdr_new(PyTypeObject *subtype, PyObject *args, PyObject *kwds)
348 PyObject *obj = NULL;
349 rpmfdObject *fdo = NULL;
351 char *kwlist[] = { "obj", NULL };
353 if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O", kwlist, &obj)) {
359 } else if (PyCObject_Check(obj)) {
360 h = PyCObject_AsVoidPtr(obj);
361 } else if (hdrObject_Check(obj)) {
362 h = headerCopy(((hdrObject*) obj)->h);
363 } else if (PyBytes_Check(obj)) {
364 h = headerCopyLoad(PyBytes_AsString(obj));
365 } else if (rpmfdFromPyObject(obj, &fdo)) {
366 Py_BEGIN_ALLOW_THREADS;
367 h = headerRead(rpmfdGetFd(fdo), HEADER_MAGIC_YES);
368 Py_END_ALLOW_THREADS;
371 PyErr_SetString(PyExc_TypeError, "header, blob or file expected");
376 PyErr_SetString(pyrpmError, "bad header");
380 return hdr_Wrap(subtype, h);
383 static void hdr_dealloc(hdrObject * s)
385 if (s->h) headerFree(s->h);
386 Py_TYPE(s)->tp_free((PyObject *)s);
389 static PyObject * hdr_iternext(hdrObject *s)
391 PyObject *res = NULL;
394 if (s->hi == NULL) s->hi = headerInitIterator(s->h);
396 if ((tag = headerNextTag(s->hi)) != RPMTAG_NOT_FOUND) {
398 res = PyObject_Call((PyObject *) &rpmtd_Type,
399 Py_BuildValue("(Oii)", s, tag, raw), NULL);
401 s->hi = headerFreeIterator(s->hi);
406 int utf8FromPyObject(PyObject *item, PyObject **str)
408 PyObject *res = NULL;
409 if (PyBytes_Check(item)) {
412 } else if (PyUnicode_Check(item)) {
413 res = PyUnicode_AsUTF8String(item);
415 if (res == NULL) return 0;
421 int tagNumFromPyObject (PyObject *item, rpmTag *tagp)
423 rpmTag tag = RPMTAG_NOT_FOUND;
424 PyObject *str = NULL;
426 if (PyInt_Check(item)) {
427 /* XXX we should probably validate tag numbers too */
428 tag = PyInt_AsLong(item);
429 } else if (utf8FromPyObject(item, &str)) {
430 tag = rpmTagGetValue(PyBytes_AsString(str));
433 PyErr_SetString(PyExc_TypeError, "expected a string or integer");
436 if (tag == RPMTAG_NOT_FOUND) {
437 PyErr_SetString(PyExc_ValueError, "unknown header tag");
445 static PyObject * hdrGetTag(Header h, rpmTag tag)
447 PyObject *res = NULL;
450 /* rpmtd_AsPyObj() knows how to handle empty containers and all */
451 (void) headerGet(h, tag, &td, HEADERGET_EXT);
452 res = rpmtd_AsPyobj(&td);
457 static int validItem(rpmTagClass class, PyObject *item)
462 case RPM_NUMERIC_CLASS:
463 rc = (PyLong_Check(item) || PyInt_Check(item));
465 case RPM_STRING_CLASS:
466 rc = (PyBytes_Check(item) || PyUnicode_Check(item));
468 case RPM_BINARY_CLASS:
469 rc = PyBytes_Check(item);
478 static int validData(rpmTag tag, rpmTagType type, PyObject *value)
480 rpmTagClass class = rpmTagGetClass(tag);
481 rpmTagReturnType retype = (type & RPM_MASK_RETURN_TYPE);
484 printf("%s: tag %s retype %x\n", __func__, rpmTagGetName(tag), retype);
485 if (retype == RPM_SCALAR_RETURN_TYPE) {
486 valid = validItem(class, value);
487 } else if (retype == RPM_ARRAY_RETURN_TYPE && PyList_Check(value)) {
488 /* python lists can contain arbitrary objects, validate each item */
489 Py_ssize_t len = PyList_Size(value);
490 for (Py_ssize_t i = 0; i < len; i++) {
491 PyObject *item = PyList_GetItem(value, i);
492 if (!validItem(class, item)) {
503 static int hdrAppendItem(Header h, rpmTag tag, rpmTagType type, PyObject *item)
507 switch ((type & RPM_MASK_TYPE)) {
508 case RPM_I18NSTRING_TYPE: /* XXX this needs to be handled separately */
509 case RPM_STRING_TYPE:
510 case RPM_STRING_ARRAY_TYPE: {
511 PyObject *str = NULL;
512 if (utf8FromPyObject(item, &str))
513 rc = headerPutString(h, tag, PyBytes_AsString(str));
517 uint8_t *val = (uint8_t *) PyBytes_AsString(item);
518 rpm_count_t len = PyBytes_Size(item);
519 rc = headerPutBin(h, tag, val, len);
521 case RPM_INT64_TYPE: {
522 uint64_t val = PyInt_AsUnsignedLongLongMask(item);
523 rc = headerPutUint64(h, tag, &val, 1);
525 case RPM_INT32_TYPE: {
526 uint32_t val = PyInt_AsUnsignedLongMask(item);
527 rc = headerPutUint32(h, tag, &val, 1);
529 case RPM_INT16_TYPE: {
530 uint16_t val = PyInt_AsUnsignedLongMask(item);
531 rc = headerPutUint16(h, tag, &val, 1);
534 case RPM_CHAR_TYPE: {
535 uint8_t val = PyInt_AsUnsignedLongMask(item);
536 rc = headerPutUint8(h, tag, &val, 1);
539 PyErr_SetString(PyExc_TypeError, "unhandled datatype");
544 static int hdrPutTag(Header h, rpmTag tag, PyObject *value)
546 rpmTagType type = rpmTagGetType(tag);
547 rpmTagReturnType retype = (type & RPM_MASK_RETURN_TYPE);
550 /* XXX this isn't really right (i18n strings etc) but for now ... */
551 if (headerIsEntry(h, tag)) {
552 PyErr_SetString(PyExc_TypeError, "tag already exists");
556 /* validate all data before trying to insert */
557 if (!validData(tag, type, value)) {
558 PyErr_SetString(PyExc_TypeError, "invalid type for tag");
562 if (retype == RPM_SCALAR_RETURN_TYPE) {
563 rc = hdrAppendItem(h, tag, type, value);
564 } else if (retype == RPM_ARRAY_RETURN_TYPE && PyList_Check(value)) {
565 Py_ssize_t len = PyList_Size(value);
566 for (Py_ssize_t i = 0; i < len; i++) {
567 PyObject *item = PyList_GetItem(value, i);
568 rc = hdrAppendItem(h, tag, type, item);
571 PyErr_SetString(PyExc_RuntimeError, "cant happen, right?");
577 static PyObject * hdr_subscript(hdrObject * s, PyObject * item)
581 if (!tagNumFromPyObject(item, &tag)) return NULL;
582 return hdrGetTag(s->h, tag);
585 static int hdr_ass_subscript(hdrObject *s, PyObject *key, PyObject *value)
588 if (!tagNumFromPyObject(key, &tag)) return -1;
591 /* XXX should failure raise key error? */
592 headerDel(s->h, tag);
593 } else if (!hdrPutTag(s->h, tag, value)) {
599 static PyObject * hdr_getattro(hdrObject * s, PyObject * n)
601 PyObject *res = PyObject_GenericGetAttr((PyObject *) s, n);
604 if (tagNumFromPyObject(n, &tag)) {
606 res = hdrGetTag(s->h, tag);
612 static int hdr_setattro(PyObject * o, PyObject * n, PyObject * v)
614 return PyObject_GenericSetAttr(o, n, v);
617 static PyMappingMethods hdr_as_mapping = {
618 (lenfunc) 0, /* mp_length */
619 (binaryfunc) hdr_subscript, /* mp_subscript */
620 (objobjargproc)hdr_ass_subscript,/* mp_ass_subscript */
623 static PySequenceMethods hdr_as_sequence = {
630 0, /* sq_ass_slice */
631 (objobjproc)hdrContains, /* sq_contains */
632 0, /* sq_inplace_concat */
633 0, /* sq_inplace_repeat */
636 static char hdr_doc[] =
639 PyTypeObject hdr_Type = {
640 PyVarObject_HEAD_INIT(&PyType_Type, 0)
641 "rpm.hdr", /* tp_name */
642 sizeof(hdrObject), /* tp_size */
644 (destructor) hdr_dealloc, /* tp_dealloc */
646 (getattrfunc) 0, /* tp_getattr */
650 0, /* tp_as_number */
651 &hdr_as_sequence, /* tp_as_sequence */
652 &hdr_as_mapping, /* tp_as_mapping */
653 hdr_hash, /* tp_hash */
656 (getattrofunc) hdr_getattro, /* tp_getattro */
657 (setattrofunc) hdr_setattro, /* tp_setattro */
658 0, /* tp_as_buffer */
659 Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, /* tp_flags */
660 hdr_doc, /* tp_doc */
663 0, /* tp_richcompare */
664 0, /* tp_weaklistoffset */
665 PyObject_SelfIter, /* tp_iter */
666 (iternextfunc)hdr_iternext, /* tp_iternext */
667 hdr_methods, /* tp_methods */
672 0, /* tp_descr_get */
673 0, /* tp_descr_set */
674 0, /* tp_dictoffset */
677 hdr_new, /* tp_new */
682 PyObject * hdr_Wrap(PyTypeObject *subtype, Header h)
684 hdrObject * hdr = (hdrObject *)subtype->tp_alloc(subtype, 0);
685 if (hdr == NULL) return NULL;
687 hdr->h = headerLink(h);
688 return (PyObject *) hdr;
691 int hdrFromPyObject(PyObject *item, Header *hptr)
693 if (hdrObject_Check(item)) {
694 *hptr = ((hdrObject *) item)->h;
697 PyErr_SetString(PyExc_TypeError, "header object expected");
703 * This assumes the order of list matches the order of the new headers, and
704 * throws an exception if that isn't true.
706 static int rpmMergeHeaders(PyObject * list, FD_t fd, int matchTag)
710 rpmTag newMatch, oldMatch;
712 rpm_count_t count = 0;
713 int rc = 1; /* assume failure */
714 rpmtd td = rpmtdNew();
716 Py_BEGIN_ALLOW_THREADS
717 h = headerRead(fd, HEADER_MAGIC_YES);
721 if (!headerGet(h, matchTag, td, HEADERGET_MINMEM)) {
722 PyErr_SetString(pyrpmError, "match tag missing in new header");
725 newMatch = rpmtdTag(td);
728 hdr = (hdrObject *) PyList_GetItem(list, count++);
731 if (!headerGet(hdr->h, matchTag, td, HEADERGET_MINMEM)) {
732 PyErr_SetString(pyrpmError, "match tag missing in new header");
735 oldMatch = rpmtdTag(td);
738 if (newMatch != oldMatch) {
739 PyErr_SetString(pyrpmError, "match tag mismatch");
743 for (hi = headerInitIterator(h); headerNext(hi, td); rpmtdFreeData(td))
746 headerDel(hdr->h, rpmtdTag(td));
747 headerPut(hdr->h, td, HEADERPUT_DEFAULT);
750 headerFreeIterator(hi);
753 Py_BEGIN_ALLOW_THREADS
754 h = headerRead(fd, HEADER_MAGIC_YES);
765 rpmMergeHeadersFromFD(PyObject * self, PyObject * args, PyObject * kwds)
772 char * kwlist[] = {"list", "fd", "matchTag", NULL};
774 if (!PyArg_ParseTupleAndKeywords(args, kwds, "Oii", kwlist, &list,
778 if (!PyList_Check(list)) {
779 PyErr_SetString(PyExc_TypeError, "first parameter must be a list");
785 rc = rpmMergeHeaders (list, fd, matchTag);
795 PyObject * versionCompare (PyObject * self, PyObject * args, PyObject * kwds)
797 hdrObject * h1, * h2;
798 char * kwlist[] = {"version0", "version1", NULL};
800 if (!PyArg_ParseTupleAndKeywords(args, kwds, "O!O!", kwlist, &hdr_Type,
801 &h1, &hdr_Type, &h2))
804 return Py_BuildValue("i", rpmVersionCompare(h1->h, h2->h));
807 static int compare_values(const char *str1, const char *str2)
811 else if (str1 && !str2)
813 else if (!str1 && str2)
815 return rpmvercmp(str1, str2);
818 PyObject * labelCompare (PyObject * self, PyObject * args)
820 char *v1, *r1, *v2, *r2;
824 if (!PyArg_ParseTuple(args, "(zzz)(zzz)",
825 &e1, &v1, &r1, &e2, &v2, &r2))
828 if (e1 == NULL) e1 = "0";
829 if (e2 == NULL) e2 = "0";
831 rc = compare_values(e1, e2);
833 rc = compare_values(v1, v2);
835 rc = compare_values(r1, r2);
837 return Py_BuildValue("i", rc);