diff options
Diffstat (limited to 'python')
30 files changed, 1899 insertions, 501 deletions
diff --git a/python/.gitignore b/python/.gitignore deleted file mode 100644 index ca7802a2b..000000000 --- a/python/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/setup.py diff --git a/python/MANIFEST.in b/python/MANIFEST.in deleted file mode 100644 index a4306366e..000000000 --- a/python/MANIFEST.in +++ /dev/null @@ -1 +0,0 @@ -include MANIFEST.in *.h diff --git a/python/Makefile.am b/python/Makefile.am index 1f2e596ac..a9bd34729 100644 --- a/python/Makefile.am +++ b/python/Makefile.am @@ -1,52 +1,56 @@ # Makefile for rpm library. +include $(top_srcdir)/rpm.am +AM_CFLAGS = @RPMCFLAGS@ + EXTRA_DIST = rpm/__init__.py rpm/transaction.py AM_CPPFLAGS = -I$(top_builddir)/include/ AM_CPPFLAGS += -I$(top_srcdir)/python -AM_CPPFLAGS += -I@WITH_PYTHON_INCLUDE@ -AM_CPPFLAGS += -I$(top_srcdir) +AM_CPPFLAGS += @PYTHON_CFLAGS@ -rpmpyexec_LTLIBRARIES = _rpm.la _rpmb.la _rpms.la -rpmpyexec_DATA = rpm/__init__.py rpm/transaction.py -rpmpyexecdir = @pyexecdir@/@PYTHON_MODULENAME@ +pkgpyexec_LTLIBRARIES = _rpmmodule.la _rpmbmodule.la _rpmsmodule.la +pkgpyexec_DATA = rpm/__init__.py rpm/transaction.py -_rpm_la_LDFLAGS = -module -avoid-version -shared -_rpm_la_LIBADD = \ +_rpmmodule_la_LDFLAGS = -module -avoid-version -shared +_rpmmodule_la_LIBADD = \ $(top_builddir)/lib/librpm.la \ $(top_builddir)/rpmio/librpmio.la \ - @WITH_PYTHON_LIB@ + @PYTHON_LIBS@ -_rpm_la_SOURCES = rpmmodule.c rpmsystem-py.h \ +_rpmmodule_la_SOURCES = rpmmodule.c rpmsystem-py.h \ header-py.c header-py.h \ + rpmarchive-py.c rpmarchive-py.h \ rpmds-py.c rpmds-py.h \ rpmfd-py.c rpmfd-py.h \ rpmfi-py.c rpmfi-py.h \ + rpmfiles-py.c rpmfiles-py.h \ rpmkeyring-py.c rpmkeyring-py.h \ rpmmi-py.c rpmmi-py.h \ rpmii-py.c rpmii-py.h \ rpmps-py.c rpmps-py.h \ rpmmacro-py.c rpmmacro-py.h \ + rpmstrpool-py.c rpmstrpool-py.h \ rpmtd-py.c rpmtd-py.h \ rpmte-py.c rpmte-py.h \ rpmts-py.c rpmts-py.h -_rpmb_la_LDFLAGS = -module -avoid-version -shared -_rpmb_la_LIBADD = \ +_rpmbmodule_la_LDFLAGS = -module -avoid-version -shared +_rpmbmodule_la_LIBADD = \ $(top_builddir)/build/librpmbuild.la \ $(top_builddir)/lib/librpm.la \ $(top_builddir)/rpmio/librpmio.la \ - @WITH_PYTHON_LIB@ + @PYTHON_LIBS@ -_rpmb_la_SOURCES = rpmbmodule.c rpmsystem-py.h \ +_rpmbmodule_la_SOURCES = rpmbmodule.c rpmsystem-py.h \ spec-py.c spec-py.h -_rpms_la_LDFLAGS = -module -avoid-version -shared -_rpms_la_LIBADD = \ +_rpmsmodule_la_LDFLAGS = -module -avoid-version -shared +_rpmsmodule_la_LIBADD = \ $(top_builddir)/sign/librpmsign.la \ $(top_builddir)/lib/librpm.la \ $(top_builddir)/rpmio/librpmio.la \ - @WITH_PYTHON_LIB@ + @PYTHON_LIBS@ -_rpms_la_SOURCES = rpmsmodule.c rpmsystem-py.h +_rpmsmodule_la_SOURCES = rpmsmodule.c rpmsystem-py.h diff --git a/python/header-py.c b/python/header-py.c index ff581f112..45af51637 100644 --- a/python/header-py.c +++ b/python/header-py.c @@ -157,20 +157,11 @@ static PyObject * hdrKeyList(hdrObject * s) return keys; } -static PyObject * hdrAsBytes(hdrObject * s, int legacy) +static PyObject * hdrAsBytes(hdrObject * s) { PyObject *res = NULL; - char *buf = NULL; - unsigned int len; - Header h = headerLink(s->h); - - /* XXX this legacy switch is a hack, needs to be removed. */ - if (legacy) { - h = headerCopy(s->h); /* XXX strip region tags, etc */ - headerFree(s->h); - } - buf = headerExport(h, &len); - h = headerFree(h); + unsigned int len = 0; + char *buf = headerExport(s->h, &len); if (buf == NULL || len == 0) { PyErr_SetString(pyrpmError, "can't unload bad header\n"); @@ -181,15 +172,9 @@ static PyObject * hdrAsBytes(hdrObject * s, int legacy) return res; } -static PyObject * hdrUnload(hdrObject * s, PyObject * args, PyObject *keywords) +static PyObject * hdrUnload(hdrObject * s) { - int legacy = 0; - static char *kwlist[] = { "legacyHeader", NULL}; - - if (!PyArg_ParseTupleAndKeywords(args, keywords, "|i", kwlist, &legacy)) - return NULL; - - return hdrAsBytes(s, legacy); + return hdrAsBytes(s); } static PyObject * hdrExpandFilelist(hdrObject * s) @@ -223,7 +208,6 @@ static PyObject * hdrFullFilelist(hdrObject * s) if (headerGet(h, RPMTAG_FILENAMES, fileNames, HEADERGET_EXT)) { rpmtdSetTag(fileNames, RPMTAG_OLDFILENAMES); headerPut(h, fileNames, HEADERPUT_DEFAULT); - rpmtdFreeData(fileNames); } rpmtdFree(fileNames); @@ -337,7 +321,7 @@ static long hdr_hash(PyObject * h) static PyObject * hdr_reduce(hdrObject *s) { PyObject *res = NULL; - PyObject *blob = hdrAsBytes(s, 0); + PyObject *blob = hdrAsBytes(s); if (blob) { res = Py_BuildValue("O(O)", Py_TYPE(s), blob); Py_DECREF(blob); @@ -347,31 +331,31 @@ static PyObject * hdr_reduce(hdrObject *s) static struct PyMethodDef hdr_methods[] = { {"keys", (PyCFunction) hdrKeyList, METH_NOARGS, - NULL }, - {"unload", (PyCFunction) hdrUnload, METH_VARARGS|METH_KEYWORDS, - NULL }, + "hdr.keys() -- Return a list of the header's rpm tags (int RPMTAG_*)." }, + {"unload", (PyCFunction) hdrUnload, METH_NOARGS, + "hdr.unload() -- Return binary representation\nof the header." }, {"expandFilelist", (PyCFunction) hdrExpandFilelist,METH_NOARGS, - NULL }, + "DEPRECATED -- Use hdr.convert() instead." }, {"compressFilelist",(PyCFunction) hdrCompressFilelist,METH_NOARGS, - NULL }, + "DEPRECATED -- Use hdr.convert() instead." }, {"fullFilelist", (PyCFunction) hdrFullFilelist, METH_NOARGS, - NULL }, + "DEPRECATED -- Obsolete method."}, {"convert", (PyCFunction) hdrConvert, METH_VARARGS|METH_KEYWORDS, - NULL }, + "hdr.convert(op=-1) -- Convert header - See HEADERCONV_*\nfor possible values of op."}, {"format", (PyCFunction) hdrFormat, METH_VARARGS|METH_KEYWORDS, - NULL }, + "hdr.format(format) -- Expand a query string with the header data.\n\nSee rpm -q for syntax." }, {"sprintf", (PyCFunction) hdrFormat, METH_VARARGS|METH_KEYWORDS, - NULL }, + "Alias for .format()." }, {"isSource", (PyCFunction)hdrIsSource, METH_NOARGS, - NULL }, + "hdr.isSource() -- Return if header describes a source package." }, {"write", (PyCFunction)hdrWrite, METH_VARARGS|METH_KEYWORDS, - NULL }, + "hdr.write(file, magic=True) -- Write header to file." }, {"dsOfHeader", (PyCFunction)hdr_dsOfHeader, METH_NOARGS, - NULL}, + "hdr.dsOfHeader() -- Return dependency set with the header's NEVR."}, {"dsFromHeader", (PyCFunction)hdr_dsFromHeader, METH_VARARGS|METH_KEYWORDS, - NULL}, + "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." }, {"fiFromHeader", (PyCFunction)hdr_fiFromHeader, METH_VARARGS|METH_KEYWORDS, - NULL}, + "hdr.fiFromHeader() -- Return rpm.fi object containing the file\nmeta data from the header.\n\nDEPRECATED - Use rpm.files(hdr) instead."}, {"__reduce__", (PyCFunction)hdr_reduce, METH_NOARGS, NULL}, @@ -393,7 +377,8 @@ static PyObject *hdr_new(PyTypeObject *subtype, PyObject *args, PyObject *kwds) if (obj == NULL) { h = headerNew(); } else if (CAPSULE_CHECK(obj)) { - h = CAPSULE_EXTRACT(obj, PYTHON_MODULENAME"._C_Header"); + h = CAPSULE_EXTRACT(obj, "rpm._C_Header"); + headerLink(h); } else if (hdrObject_Check(obj)) { h = headerCopy(((hdrObject*) obj)->h); } else if (PyBytes_Check(obj)) { @@ -404,7 +389,7 @@ static PyObject *hdr_new(PyTypeObject *subtype, PyObject *args, PyObject *kwds) Py_END_ALLOW_THREADS; Py_XDECREF(fdo); } else { - PyErr_SetString(PyExc_TypeError, "header, blob or file expected!!"); + PyErr_SetString(PyExc_TypeError, "header, blob or file expected"); return NULL; } @@ -606,7 +591,7 @@ static int hdrPutTag(Header h, rpmTagVal tag, PyObject *value) rc = hdrAppendItem(h, tag, type, item); } } else { - PyErr_SetString(PyExc_RuntimeError, "cant happen, right?"); + PyErr_SetString(PyExc_RuntimeError, "can't happen, right?"); } return rc; @@ -680,11 +665,60 @@ static PySequenceMethods hdr_as_sequence = { }; static char hdr_doc[] = -""; + "A header object represents an RPM package header.\n" + "\n" + "All RPM packages have headers that provide metadata for the package.\n" + "Header objects can be returned by database queries or loaded from a\n" + "binary package on disk.\n" + "\n" + "The ts.hdrFromFdno() function returns the package header from a\n" + "package on disk, verifying package signatures and digests of the\n" + "package while reading.\n" + "\n" + "Note: The older method rpm.headerFromPackage() which has been replaced\n" + "by ts.hdrFromFdno() used to return a (hdr, isSource) tuple.\n" + "\n" + "If you need to distinguish source/binary headers, do:\n" + "\n" + " import os, rpm\n" + "\n" + " ts = rpm.TransactionSet()\n" + " fdno = os.open('/tmp/foo-1.0-1.i386.rpm', os.O_RDONLY)\n" + " hdr = ts.hdrFromFdno(fdno)\n" + " os.close(fdno)\n" + " if hdr[rpm.RPMTAG_SOURCEPACKAGE]:\n" + " print 'header is from a source package'\n" + " else:\n" + " print 'header is from a binary package'\n" + "\n" + "The Python interface to the header data is quite elegant. It\n" + "presents the data in a dictionary form. We'll take the header we\n" + "just loaded and access the data within it:\n" + "\n" + " print hdr[rpm.RPMTAG_NAME]\n" + " print hdr[rpm.RPMTAG_VERSION]\n" + " print hdr[rpm.RPMTAG_RELEASE]\n" + "\n" + "in the case of our 'foo-1.0-1.i386.rpm' package, this code would\n" + "output:\n" + " foo\n" + " 1.0\n" + " 1\n" + "\n" + "You make also access the header data by string name:\n" + "\n" + " print hdr['name']\n" + " print hdr['version']\n" + " print hdr['release']\n" + "\n" + "This method of access is a teensy bit slower because the name must be\n" + "translated into the tag number dynamically. You also must make sure\n" + "the strings in header lookups don't get translated, or the lookups\n" + "will fail.\n"; PyTypeObject hdr_Type = { PyVarObject_HEAD_INIT(&PyType_Type, 0) - PYTHON_MODULENAME".hdr", /* tp_name */ + "rpm.hdr", /* tp_name */ sizeof(hdrObject), /* tp_size */ 0, /* tp_itemsize */ (destructor) hdr_dealloc, /* tp_dealloc */ @@ -729,8 +763,7 @@ PyObject * hdr_Wrap(PyTypeObject *subtype, Header h) { hdrObject * hdr = (hdrObject *)subtype->tp_alloc(subtype, 0); if (hdr == NULL) return NULL; - - hdr->h = headerLink(h); + hdr->h = h; return (PyObject *) hdr; } diff --git a/python/rpm/__init__.py.in b/python/rpm/__init__.py index df1e3a282..54728bbd4 100644 --- a/python/rpm/__init__.py.in +++ b/python/rpm/__init__.py @@ -2,13 +2,42 @@ r"""RPM Module This module enables you to manipulate rpms and the rpm database. +The rpm base module provides the main starting point for +accessing RPM from Python. For most usage, call +the TransactionSet method to get a transaction set (rpmts). + +For example: + import rpm + ts = rpm.TransactionSet() + +The transaction set will open the RPM database as needed, so +in most cases, you do not need to explicitly open the +database. The transaction set is the workhorse of RPM. + +You can open another RPM database, such as one that holds +all packages for a given Linux distribution, to provide +packages used to solve dependencies. To do this, use +the following code: + +rpm.addMacro('_dbpath', '/path/to/alternate/database') +solvets = rpm.TransactionSet() +solvets.openDB() +rpm.delMacro('_dbpath') + +# Open default database +ts = rpm.TransactionSet() + +This code gives you access to two RPM databases through +two transaction sets (rpmts): ts is a transaction set +associated with the default RPM database and solvets +is a transaction set tied to an alternate database, which +is very useful for resolving dependencies. """ import warnings -import os -from @PYTHON_MODULENAME@._rpm import * -from @PYTHON_MODULENAME@.transaction import * -import @PYTHON_MODULENAME@._rpm as _rpm +from rpm._rpm import * +from rpm.transaction import * +import rpm._rpm as _rpm _RPMVSF_NODIGESTS = _rpm._RPMVSF_NODIGESTS _RPMVSF_NOHEADER = _rpm._RPMVSF_NOHEADER _RPMVSF_NOPAYLOAD = _rpm._RPMVSF_NOPAYLOAD @@ -19,23 +48,26 @@ __version_info__ = tuple(__version__.split('.')) # try to import build bits but dont require it try: - from @PYTHON_MODULENAME@._rpmb import * + from rpm._rpmb import * except ImportError: pass # try to import signing bits but dont require it try: - from @PYTHON_MODULENAME@._rpms import * + from rpm._rpms import * except ImportError: pass # backwards compatibility + give the same class both ways ts = TransactionSet + def headerLoad(*args, **kwds): + """DEPRECATED! Use rpm.hdr() instead.""" warnings.warn("Use rpm.hdr() instead.", DeprecationWarning, stacklevel=2) return hdr(*args, **kwds) + def _doHeaderListFromFD(rpm_fd, retrofit): hlist = [] while 1: @@ -49,18 +81,22 @@ def _doHeaderListFromFD(rpm_fd, retrofit): return hlist -def readHeaderListFromFD(file_desc, retrofit = True): + +def readHeaderListFromFD(file_desc, retrofit=True): if not isinstance(file_desc, fd): file_desc = fd(file_desc) return _doHeaderListFromFD(file_desc, retrofit) - -def readHeaderListFromFile(path, retrofit = True): + + +def readHeaderListFromFile(path, retrofit=True): f = fd(path) hlist = _doHeaderListFromFD(f, retrofit) f.close() return hlist - + + def readHeaderFromFD(file_desc): + """Return (header, pos_before_hdr)""" if not isinstance(file_desc, fd): file_desc = fd(file_desc) try: @@ -72,7 +108,9 @@ def readHeaderFromFD(file_desc): return (h, offset) + def signalsCaught(siglist): + """Returns list of signals that were caught.""" caught = [] for sig in siglist: if signalCaught(sig): @@ -80,5 +118,11 @@ def signalsCaught(siglist): return caught -def dsSingle(TagN, N, EVR = "", Flags = RPMSENSE_ANY): - return ds((N, EVR, Flags), TagN) + +def dsSingle(TagN, N, EVR="", Flags=RPMSENSE_ANY): + """ + Creates a single entry dependency set (ds) + + dsSingle(RPMTAG_CONFLICTNAME, "rpm") corresponds to "Conflicts: rpm" + """ + return ds((N, Flags, EVR), TagN) diff --git a/python/rpm/transaction.py.in b/python/rpm/transaction.py index e73075923..675ecaf8e 100644 --- a/python/rpm/transaction.py.in +++ b/python/rpm/transaction.py @@ -1,7 +1,14 @@ -#!/usr/bin/python +from __future__ import with_statement + +import sys +import rpm +from rpm._rpm import ts as TransactionSetCore + +if sys.version_info[0] == 3: + _string_types = str, +else: + _string_types = basestring, -import @PYTHON_MODULENAME@ as rpm -from @PYTHON_MODULENAME@._rpm import ts as TransactionSetCore # TODO: migrate relevant documentation from C-side class TransactionSet(TransactionSetCore): @@ -11,7 +18,7 @@ class TransactionSet(TransactionSetCore): oval = getattr(self, attr) setattr(self, attr, val) return oval - + def setVSFlags(self, flags): return self._wrapSetGet('_vsflags', flags) @@ -31,8 +38,8 @@ class TransactionSet(TransactionSetCore): return self._wrapSetGet('_probFilter', ignoreSet) def parseSpec(self, specfile): - import _rpmb - return _rpmb.spec(specfile) + import rpm._rpmb + return rpm._rpmb.spec(specfile) def getKeys(self): keys = [] @@ -44,23 +51,32 @@ class TransactionSet(TransactionSetCore): else: return tuple(keys) - def addInstall(self, item, key, how="u"): - if isinstance(item, basestring): - f = file(item) - header = self.hdrFromFdno(f) - f.close() - elif isinstance(item, file): - header = self.hdrFromFdno(item) - else: + def _f2hdr(self, item): + if isinstance(item, _string_types): + with open(item) as f: + header = self.hdrFromFdno(f) + elif isinstance(item, rpm.hdr): header = item + else: + header = self.hdrFromFdno(item) + return header + + def addInstall(self, item, key, how="u"): + header = self._f2hdr(item) - if not how in ['u', 'i']: + if how not in ['u', 'i']: raise ValueError('how argument must be "u" or "i"') upgrade = (how == "u") if not TransactionSetCore.addInstall(self, header, key, upgrade): raise rpm.error("adding package to transaction failed") + def addReinstall(self, item, key): + header = self._f2hdr(item) + + if not TransactionSetCore.addReinstall(self, header, key): + raise rpm.error("adding package to transaction failed") + def addErase(self, item): hdrs = [] if isinstance(item, rpm.hdr): @@ -69,7 +85,7 @@ class TransactionSet(TransactionSetCore): hdrs = item elif isinstance(item, int): hdrs = self.dbMatch(rpm.RPMDBI_PACKAGES, item) - elif isinstance(item, basestring): + elif isinstance(item, _string_types): hdrs = self.dbMatch(rpm.RPMDBI_LABEL, item) else: raise TypeError("invalid type %s" % type(item)) @@ -86,7 +102,7 @@ class TransactionSet(TransactionSetCore): rc = TransactionSetCore.run(self, callback, data, self._probFilter) # crazy backwards compatibility goo: None for ok, list of problems - # if transaction didnt complete and empty list if it completed + # if transaction didn't complete and empty list if it completed # with errors if rc == 0: return None @@ -122,14 +138,18 @@ class TransactionSet(TransactionSetCore): needflags = rpm.RPMSENSE_ANY if len(needs) == 3: needop = needs[1] - if needop.find('<') >= 0: needflags |= rpm.RPMSENSE_LESS - if needop.find('=') >= 0: needflags |= rpm.RPMSENSE_EQUAL - if needop.find('>') >= 0: needflags |= rpm.RPMSENSE_GREATER + if '<' in needop: + needflags |= rpm.RPMSENSE_LESS + if '=' in needop: + needflags |= rpm.RPMSENSE_EQUAL + if '>' in needop: + needflags |= rpm.RPMSENSE_GREATER needver = needs[2] else: needver = "" - res.append(((n, v, r),(needname,needver),needflags,sense,p.key)) + res.append(((n, v, r), + (needname, needver), needflags, sense, p.key)) return res diff --git a/python/rpmarchive-py.c b/python/rpmarchive-py.c new file mode 100644 index 000000000..53a078a4e --- /dev/null +++ b/python/rpmarchive-py.c @@ -0,0 +1,275 @@ +#include "rpmsystem-py.h" + +#include <rpm/rpmtypes.h> +#include <rpm/rpmpgp.h> + +#include "header-py.h" +#include "rpmfi-py.h" +#include "rpmfd-py.h" +#include "rpmfiles-py.h" +#include "rpmarchive-py.h" +#include "rpmstrpool-py.h" + +struct rpmarchiveObject_s { + PyObject_HEAD + PyObject *md_dict; + rpmfi archive; + rpmfiles files; +}; + +static void rpmarchive_dealloc(rpmarchiveObject * s) +{ + rpmfilesFree(s->files); + rpmfiArchiveClose(s->archive); + rpmfiFree(s->archive); + Py_TYPE(s)->tp_free((PyObject *)s); +} + +static PyObject *rpmarchive_error(int rc) +{ + PyErr_SetObject(PyExc_IOError, + Py_BuildValue("(is)", rc, rpmfileStrerror(rc))); + return NULL; +} + +static PyObject *rpmarchive_closed(void) +{ + PyErr_SetString(PyExc_IOError, "I/O operation on closed archive"); + return NULL; +} + +static PyObject *rpmarchive_tell(rpmarchiveObject *s) +{ + return PyLong_FromLongLong(rpmfiArchiveTell(s->archive)); +} + +static PyObject *rpmarchive_close(rpmarchiveObject *s) +{ + if (s->archive) { + int rc = rpmfiArchiveClose(s->archive); + s->archive = rpmfiFree(s->archive); + if (rc) + return rpmarchive_error(rc); + } + Py_RETURN_NONE; +} + +static PyObject *rpmarchive_has_content(rpmarchiveObject *s) +{ + return PyLong_FromLong(rpmfiArchiveHasContent(s->archive)); +} + +static PyObject *rpmarchive_read(rpmarchiveObject *s, + PyObject *args, PyObject *kwds) +{ + char *kwlist[] = { "size", NULL }; + char buf[BUFSIZ]; + ssize_t chunksize = sizeof(buf); + ssize_t left = -1; + ssize_t nb = 0; + PyObject *res = NULL; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|l", kwlist, &left)) + return NULL; + + if (s->archive == NULL) + return rpmarchive_closed(); + + /* ConcatAndDel() doesn't work on NULL string, meh */ + res = PyBytes_FromStringAndSize(NULL, 0); + do { + if (left >= 0 && left < chunksize) + chunksize = left; + + Py_BEGIN_ALLOW_THREADS + nb = rpmfiArchiveRead(s->archive, buf, chunksize); + Py_END_ALLOW_THREADS + + if (nb > 0) { + PyObject *tmp = PyBytes_FromStringAndSize(buf, nb); + PyBytes_ConcatAndDel(&res, tmp); + left -= nb; + } + } while (nb > 0); + + if (nb < 0) { + Py_XDECREF(res); + return rpmarchive_error(nb); + } else { + return res; + } +} + +static PyObject *rpmarchive_write(rpmarchiveObject *s, + PyObject *args, PyObject *kwds) +{ + const char *buf = NULL; + ssize_t size = 0; + char *kwlist[] = { "buffer", NULL }; + ssize_t rc = 0; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "s#", kwlist, &buf, &size)) { + return NULL; + } + + if (s->archive == NULL) + return rpmarchive_closed(); + + Py_BEGIN_ALLOW_THREADS + rc = rpmfiArchiveWrite(s->archive, buf, size); + Py_END_ALLOW_THREADS + + if (rc < 0) + return rpmarchive_error(rc); + else + return Py_BuildValue("n", rc); +} + +static PyObject *rpmarchive_readto(rpmarchiveObject *s, + PyObject *args, PyObject *kwds) +{ + rpmfdObject *fdo = NULL; + int nodigest = 0; + int rc; + char *kwlist[] = { "fd", "nodigest", NULL }; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "O&|i", kwlist, + rpmfdFromPyObject, &fdo, &nodigest)) { + return NULL; + } + + if (s->archive == NULL) + return rpmarchive_closed(); + + Py_BEGIN_ALLOW_THREADS + rc = rpmfiArchiveReadToFile(s->archive, rpmfdGetFd(fdo), nodigest); + Py_END_ALLOW_THREADS + + if (rc) + return rpmarchive_error(rc); + + Py_RETURN_NONE; +} + +static PyObject *rpmarchive_writeto(rpmarchiveObject *s, + PyObject *args, PyObject *kwds) +{ + rpmfdObject *fdo = NULL; + int rc; + char *kwlist[] = { "fd", NULL }; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "O&|i", kwlist, + rpmfdFromPyObject, &fdo)) { + return NULL; + } + + if (s->archive == NULL) + return rpmarchive_closed(); + + Py_BEGIN_ALLOW_THREADS + rc = rpmfiArchiveWriteFile(s->archive, rpmfdGetFd(fdo)); + Py_END_ALLOW_THREADS + + if (rc) + return rpmarchive_error(rc); + + Py_RETURN_NONE; +} + +static struct PyMethodDef rpmarchive_methods[] = { + { "tell", (PyCFunction)rpmarchive_tell, METH_NOARGS, + "archive.tell() -- Return current position in archive." }, + { "close", (PyCFunction)rpmarchive_close, METH_NOARGS, + "archive.close() -- Close archive and do final consistency checks."}, + { "read", (PyCFunction)rpmarchive_read, METH_VARARGS|METH_KEYWORDS, + "archive.read(size=None) -- Read next size bytes from current file.\n\n" + "Returns bytes\n"}, + { "write", (PyCFunction)rpmarchive_write, METH_VARARGS|METH_KEYWORDS, + "archive.write(buffer) -- Write buffer to current file." }, + { "readto", (PyCFunction)rpmarchive_readto, METH_VARARGS|METH_KEYWORDS, + "archive.readto(fd, nodigest=None) -- Read content of fd\n" + "and write as content of the current file to archive." }, + { "writeto", (PyCFunction)rpmarchive_writeto,METH_VARARGS|METH_KEYWORDS, + "archive.writeto(fd) -- Write content of current file in archive\n to fd." }, + { "hascontent", (PyCFunction)rpmarchive_has_content, METH_NOARGS, + "archive.hascontent() -- Return if current file has a content.\n\n" + "Returns false for non regular and all but one of hardlinked files."}, + { NULL, NULL, 0, NULL } +}; + +static char rpmarchive_doc[] = +"Gives access to the payload of an rpm package.\n\n" +"Is returned by .archive() method of an rpm.files instance.\n" +"All methods can raise an IOError exception."; + +static PyObject *rpmarchive_iternext(rpmarchiveObject *s) +{ + PyObject *next = NULL; + int fx = rpmfiNext(s->archive); + + if (fx >= 0) { + next = rpmfile_Wrap(s->files, fx); + } else if (fx < -1) { + next = rpmarchive_error(fx); + } else { + /* end of iteration, nothing to do */ + } + + return next; +} + +PyTypeObject rpmarchive_Type = { + PyVarObject_HEAD_INIT(&PyType_Type, 0) + "rpm.archive", /* tp_name */ + sizeof(rpmarchiveObject), /* tp_basicsize */ + 0, /* tp_itemsize */ + (destructor) rpmarchive_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + PyObject_GenericGetAttr, /* tp_getattro */ + PyObject_GenericSetAttr, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, /* tp_flags */ + rpmarchive_doc, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + PyObject_SelfIter, /* tp_iter */ + (iternextfunc) rpmarchive_iternext, /* tp_iternext */ + rpmarchive_methods, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + 0, /* tp_new */ + 0, /* tp_free */ + 0, /* tp_is_gc */ +}; + +PyObject * rpmarchive_Wrap(PyTypeObject *subtype, + rpmfiles files, rpmfi archive) +{ + rpmarchiveObject *s = (rpmarchiveObject *)subtype->tp_alloc(subtype, 0); + if (s == NULL) return NULL; + + s->files = rpmfilesLink(files); + s->archive = archive; + + return (PyObject *) s; +} + diff --git a/python/rpmarchive-py.h b/python/rpmarchive-py.h new file mode 100644 index 000000000..96f09fd29 --- /dev/null +++ b/python/rpmarchive-py.h @@ -0,0 +1,15 @@ +#ifndef H_RPMARCHIVE_PY +#define H_RPMARCHIVE_PY + +#include <rpm/rpmarchive.h> + +typedef struct rpmarchiveObject_s rpmarchiveObject; + +extern PyTypeObject rpmarchive_Type; + +#define rpmarchiveObject_Check(v) ((v)->ob_type == &rpmarchive_Type) + +PyObject * rpmarchive_Wrap(PyTypeObject *subtype, + rpmfiles files, rpmfi archive); + +#endif diff --git a/python/rpmds-py.c b/python/rpmds-py.c index 4b44220dc..9eae9a228 100644 --- a/python/rpmds-py.c +++ b/python/rpmds-py.c @@ -6,6 +6,7 @@ #include "header-py.h" #include "rpmds-py.h" +#include "rpmstrpool-py.h" struct rpmdsObject_s { PyObject_HEAD @@ -96,21 +97,6 @@ rpmds_SetNoPromote(rpmdsObject * s, PyObject * args, PyObject * kwds) return Py_BuildValue("i", rpmdsSetNoPromote(s->ds, nopromote)); } -static PyObject * -rpmds_Notify(rpmdsObject * s, PyObject * args, PyObject * kwds) -{ - const char * where; - int rc; - char * kwlist[] = {"location", "returnCode", NULL}; - - if (!PyArg_ParseTupleAndKeywords(args, kwds, "si:Notify", kwlist, - &where, &rc)) - return NULL; - - rpmdsNotify(s->ds, where, rc); - Py_RETURN_NONE; -} - /* XXX rpmdsFind uses bsearch on s->ds, so a sort is needed. */ static PyObject * rpmds_Sort(rpmdsObject * s) @@ -169,12 +155,18 @@ static PyObject *rpmds_Instance(rpmdsObject * s) return Py_BuildValue("i", rpmdsInstance(s->ds)); } -static PyObject * rpmds_Rpmlib(rpmdsObject * s) +static PyObject * rpmds_Rpmlib(rpmdsObject * s, PyObject *args, PyObject *kwds) { + rpmstrPool pool = NULL; rpmds ds = NULL; + char * kwlist[] = {"pool", NULL}; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O&:rpmds_Rpmlib", kwlist, + &poolFromPyObject, &pool)) + return NULL; /* XXX check return code, permit arg (NULL uses system default). */ - rpmdsRpmlib(&ds, NULL); + rpmdsRpmlibPool(pool, &ds, NULL); return rpmds_Wrap(&rpmds_Type, ds); } @@ -183,39 +175,39 @@ static struct PyMethodDef rpmds_methods[] = { {"Count", (PyCFunction)rpmds_Count, METH_NOARGS, "Deprecated, use len(ds) instead.\n" }, {"Ix", (PyCFunction)rpmds_Ix, METH_NOARGS, - "ds.Ix -> Ix - Return current element index.\n" }, + "ds.Ix -> Ix -- Return current element index.\n" }, {"DNEVR", (PyCFunction)rpmds_DNEVR, METH_NOARGS, - "ds.DNEVR -> DNEVR - Return current DNEVR.\n" }, + "ds.DNEVR -> DNEVR -- Return current DNEVR.\n" }, {"N", (PyCFunction)rpmds_N, METH_NOARGS, - "ds.N -> N - Return current N.\n" }, + "ds.N -> N -- Return current N.\n" }, {"EVR", (PyCFunction)rpmds_EVR, METH_NOARGS, - "ds.EVR -> EVR - Return current EVR.\n" }, + "ds.EVR -> EVR -- Return current EVR.\n" }, {"Flags", (PyCFunction)rpmds_Flags, METH_NOARGS, - "ds.Flags -> Flags - Return current Flags.\n" }, + "ds.Flags -> Flags -- Return current Flags.\n" }, {"TagN", (PyCFunction)rpmds_TagN, METH_NOARGS, - "ds.TagN -> TagN - Return current TagN.\n" }, + "ds.TagN -> TagN -- Return TagN (RPMTAG_*NAME)\n\n" + "the type of all dependencies in this set.\n" }, {"Color", (PyCFunction)rpmds_Color, METH_NOARGS, - "ds.Color -> Color - Return current Color.\n" }, + "ds.Color -> Color -- Return current Color.\n" }, {"SetNoPromote",(PyCFunction)rpmds_SetNoPromote, METH_VARARGS|METH_KEYWORDS, - NULL}, - {"Notify", (PyCFunction)rpmds_Notify, METH_VARARGS|METH_KEYWORDS, - NULL}, + "ds.SetNoPromote(noPromote) -- Set noPromote for this instance.\n\n" + "If True non existing epochs are no longer equal to an epoch of 0."}, {"Sort", (PyCFunction)rpmds_Sort, METH_NOARGS, NULL}, {"Find", (PyCFunction)rpmds_Find, METH_O, - NULL}, + "ds.find(other_ds) -- Return index of other_ds in ds"}, {"Merge", (PyCFunction)rpmds_Merge, METH_O, NULL}, {"Search", (PyCFunction)rpmds_Search, METH_O, "ds.Search(element) -> matching ds index (-1 on failure)\n\ -- Check that element dependency range overlaps some member of ds.\n\ -The current index in ds is positioned at overlapping member upon success.\n" }, - {"Rpmlib", (PyCFunction)rpmds_Rpmlib, METH_NOARGS|METH_STATIC, - "ds.Rpmlib -> nds - Return internal rpmlib dependency set.\n"}, +Check that element dependency range overlaps some member of ds.\n\ +The current index in ds is positioned at overlapping member." }, + {"Rpmlib", (PyCFunction)rpmds_Rpmlib, METH_VARARGS|METH_KEYWORDS|METH_STATIC, + "ds.Rpmlib -> nds -- Return internal rpmlib dependency set.\n"}, {"Compare", (PyCFunction)rpmds_Compare, METH_O, - NULL}, + "ds.compare(other) -- Compare current entries of self and other.\n\nReturns True if the entries match each other, False otherwise"}, {"Instance", (PyCFunction)rpmds_Instance, METH_NOARGS, - NULL}, + "ds.Instance() -- Return rpmdb key of corresponding package or 0."}, {NULL, NULL} /* sentinel */ }; @@ -305,10 +297,12 @@ static PyObject * rpmds_new(PyTypeObject * subtype, PyObject *args, PyObject *kw rpmTagVal tagN = RPMTAG_REQUIRENAME; rpmds ds = NULL; Header h = NULL; - char * kwlist[] = {"obj", "tag", NULL}; + rpmstrPool pool = NULL; + char * kwlist[] = {"obj", "tag", "pool", NULL}; - if (!PyArg_ParseTupleAndKeywords(args, kwds, "OO&:rpmds_new", kwlist, - &obj, tagNumFromPyObject, &tagN)) + if (!PyArg_ParseTupleAndKeywords(args, kwds, "OO&|O&:rpmds_new", kwlist, + &obj, tagNumFromPyObject, &tagN, + &poolFromPyObject, &pool)) return NULL; if (PyTuple_Check(obj)) { @@ -317,16 +311,16 @@ static PyObject * rpmds_new(PyTypeObject * subtype, PyObject *args, PyObject *kw rpmsenseFlags flags = RPMSENSE_ANY; /* TODO: if flags are specified, evr should be required too */ if (PyArg_ParseTuple(obj, "s|O&s", &name, depflags, &flags, &evr)) { - ds = rpmdsSingle(tagN, name, evr, flags); + ds = rpmdsSinglePool(pool, tagN, name, evr, flags); } else { PyErr_SetString(PyExc_ValueError, "invalid dependency tuple"); return NULL; } } else if (hdrFromPyObject(obj, &h)) { if (tagN == RPMTAG_NEVR) { - ds = rpmdsThis(h, RPMTAG_PROVIDENAME, RPMSENSE_EQUAL); + ds = rpmdsThisPool(pool, h, RPMTAG_PROVIDENAME, RPMSENSE_EQUAL); } else { - ds = rpmdsNew(h, tagN, 0); + ds = rpmdsNewPool(pool, h, tagN, 0); } } else { PyErr_SetString(PyExc_TypeError, "header or tuple expected"); @@ -337,11 +331,15 @@ static PyObject * rpmds_new(PyTypeObject * subtype, PyObject *args, PyObject *kw } static char rpmds_doc[] = -""; + "rpm.ds (dependendcy set) gives a more convenient access to dependencies\n\n" + "It can hold multiple entries of Name Flags and EVR.\n" + "It typically represents all dependencies of one kind of a package\n" + "e.g. all Requires or all Conflicts.\n" + ; PyTypeObject rpmds_Type = { PyVarObject_HEAD_INIT(&PyType_Type, 0) - PYTHON_MODULENAME".ds", /* tp_name */ + "rpm.ds", /* tp_name */ sizeof(rpmdsObject), /* tp_basicsize */ 0, /* tp_itemsize */ /* methods */ diff --git a/python/rpmfd-py.c b/python/rpmfd-py.c index 41f494108..85fb0cd24 100644 --- a/python/rpmfd-py.c +++ b/python/rpmfd-py.c @@ -8,6 +8,8 @@ struct rpmfdObject_s { PyObject_HEAD PyObject *md_dict; FD_t fd; + char *mode; + char *flags; }; FD_t rpmfdGetFd(rpmfdObject *fdo) @@ -43,14 +45,21 @@ static PyObject *err_closed(void) return NULL; } -static FD_t openPath(const char *path, const char *mode, const char *flags) +static FD_t openPath(const char *path, const char *mode) { FD_t fd; - char *m = rstrscat(NULL, mode, ".", flags, NULL); Py_BEGIN_ALLOW_THREADS - fd = Fopen(path, m); + fd = Fopen(path, mode); + Py_END_ALLOW_THREADS; + return fd; +} + +static FD_t openFd(FD_t ofd, const char *mode) +{ + FD_t fd; + Py_BEGIN_ALLOW_THREADS + fd = Fdopen(ofd, mode); Py_END_ALLOW_THREADS; - free(m); return fd; } @@ -59,6 +68,7 @@ static int rpmfd_init(rpmfdObject *s, PyObject *args, PyObject *kwds) char *kwlist[] = { "obj", "mode", "flags", NULL }; const char *mode = "r"; const char *flags = "ufdio"; + char *rpmio_mode = NULL; PyObject *fo = NULL; FD_t fd = NULL; int fdno; @@ -67,8 +77,10 @@ static int rpmfd_init(rpmfdObject *s, PyObject *args, PyObject *kwds) &fo, &mode, &flags)) return -1; + rpmio_mode = rstrscat(NULL, mode, ".", flags, NULL); + if (PyBytes_Check(fo)) { - fd = openPath(PyBytes_AsString(fo), mode, flags); + fd = openPath(PyBytes_AsString(fo), rpmio_mode); } else if (PyUnicode_Check(fo)) { PyObject *enc = NULL; int rc; @@ -78,26 +90,38 @@ static int rpmfd_init(rpmfdObject *s, PyObject *args, PyObject *kwds) rc = utf8FromPyObject(fo, &enc); #endif if (rc) { - fd = openPath(PyBytes_AsString(enc), mode, flags); + fd = openPath(PyBytes_AsString(enc), rpmio_mode); Py_DECREF(enc); } + } else if (rpmfdObject_Check(fo)) { + rpmfdObject *fdo = (rpmfdObject *)fo; + fd = openFd(fdDup(Fileno(fdo->fd)), rpmio_mode); } else if ((fdno = PyObject_AsFileDescriptor(fo)) >= 0) { - fd = fdDup(fdno); + fd = openFd(fdDup(fdno), rpmio_mode); } else { PyErr_SetString(PyExc_TypeError, "path or file object expected"); } if (fd != NULL) { - /* TODO: remember our filename, mode & flags */ Fclose(s->fd); /* in case __init__ was called again */ + free(s->mode); + free(s->flags); s->fd = fd; + s->mode = rstrdup(mode); + s->flags = rstrdup(flags); } else { PyErr_SetString(PyExc_IOError, Fstrerror(fd)); } + free(rpmio_mode); return (fd == NULL) ? -1 : 0; } +static PyObject *rpmfd_open(PyObject *cls, PyObject *args, PyObject *kwds) +{ + return PyObject_Call(cls, args, kwds); +} + static PyObject *do_close(rpmfdObject *s) { /* mimic python fileobject: close on closed file is not an error */ @@ -119,6 +143,8 @@ static void rpmfd_dealloc(rpmfdObject *s) { PyObject *res = do_close(s); Py_XDECREF(res); + free(s->mode); + free(s->flags); Py_TYPE(s)->tp_free((PyObject *)s); } @@ -272,6 +298,8 @@ static PyObject *rpmfd_write(rpmfdObject *s, PyObject *args, PyObject *kwds) static char rpmfd_doc[] = ""; static struct PyMethodDef rpmfd_methods[] = { + { "open", (PyCFunction) rpmfd_open, METH_VARARGS|METH_KEYWORDS|METH_CLASS, + NULL }, { "close", (PyCFunction) rpmfd_close, METH_NOARGS, NULL }, { "fileno", (PyCFunction) rpmfd_fileno, METH_NOARGS, @@ -302,15 +330,27 @@ static PyObject *rpmfd_get_name(rpmfdObject *s) return Py_BuildValue("s", Fdescr(s->fd)); } +static PyObject *rpmfd_get_mode(rpmfdObject *s) +{ + return Py_BuildValue("s", s->mode); +} + +static PyObject *rpmfd_get_flags(rpmfdObject *s) +{ + return Py_BuildValue("s", s->flags); +} + static PyGetSetDef rpmfd_getseters[] = { { "closed", (getter)rpmfd_get_closed, NULL, NULL }, { "name", (getter)rpmfd_get_name, NULL, NULL }, + { "mode", (getter)rpmfd_get_mode, NULL, NULL }, + { "flags", (getter)rpmfd_get_flags, NULL, NULL }, { NULL }, }; PyTypeObject rpmfd_Type = { PyVarObject_HEAD_INIT(&PyType_Type, 0) - PYTHON_MODULENAME".fd", /* tp_name */ + "rpm.fd", /* tp_name */ sizeof(rpmfdObject), /* tp_size */ 0, /* tp_itemsize */ /* methods */ diff --git a/python/rpmfi-py.c b/python/rpmfi-py.c index 14e89df1f..a1a743a1d 100644 --- a/python/rpmfi-py.c +++ b/python/rpmfi-py.c @@ -5,6 +5,7 @@ #include "header-py.h" #include "rpmfi-py.h" +#include "rpmstrpool-py.h" struct rpmfiObject_s { PyObject_HEAD @@ -56,6 +57,18 @@ rpmfi_FN(rpmfiObject * s, PyObject * unused) } static PyObject * +rpmfi_FindFN(rpmfiObject * s, PyObject * args, PyObject * kwds) +{ + char * kwlist[] = {"filename", NULL}; + PyObject * filename = NULL; + if (!PyArg_ParseTupleAndKeywords(args, kwds, "S:FindFN", kwlist, + &filename)) + return NULL; + return Py_BuildValue("i", rpmfiFindFN(s->fi, PyBytes_AsString(filename))); +} + + +static PyObject * rpmfi_FFlags(rpmfiObject * s, PyObject * unused) { return Py_BuildValue("i", rpmfiFFlags(s->fi)); @@ -146,6 +159,25 @@ rpmfi_FClass(rpmfiObject * s, PyObject * unused) } static PyObject * +rpmfi_FLinks(rpmfiObject * s, PyObject * unused) +{ + uint32_t nlinks; + const int * files; + PyObject * result; + + nlinks = rpmfiFLinks(s->fi, &files); + if (nlinks==1) { + return Py_BuildValue("(i)", rpmfiFX(s->fi)); + } + + result = PyTuple_New(nlinks); + for (uint32_t i=0; i<nlinks; i++) { + PyTuple_SET_ITEM(result, i, PyInt_FromLong(files[i])); + } + return result; +} + +static PyObject * rpmfi_iternext(rpmfiObject * s) { PyObject * result = NULL; @@ -206,47 +238,51 @@ rpmfi_iternext(rpmfiObject * s) static struct PyMethodDef rpmfi_methods[] = { {"FC", (PyCFunction)rpmfi_FC, METH_NOARGS, - NULL}, + "fi.FC() -- Return number of files entries."}, {"FX", (PyCFunction)rpmfi_FX, METH_NOARGS, - NULL}, + "fi.FX() -- Return current position of the iterator."}, {"DC", (PyCFunction)rpmfi_DC, METH_NOARGS, - NULL}, + "fi.DC() --Return number of directory entries."}, {"DX", (PyCFunction)rpmfi_DX, METH_NOARGS, - NULL}, + "fi.DX() -- Return number of directory entry matching current file."}, {"BN", (PyCFunction)rpmfi_BN, METH_NOARGS, - NULL}, + "fi.BN() -- Return base name of current file."}, {"DN", (PyCFunction)rpmfi_DN, METH_NOARGS, - NULL}, + "fi.DN() -- Return directory name of the current file."}, {"FN", (PyCFunction)rpmfi_FN, METH_NOARGS, - NULL}, + "fi.FN() -- Return the name/path of the current file."}, + {"FindFN", (PyCFunction)rpmfi_FindFN, METH_VARARGS|METH_KEYWORDS, + "fi.FindFN(pathname) -- Return entry number of given pathname.\n\nReturn -1 if file is not found.\nLeading '.' in the given name is stripped before the search."}, {"FFlags", (PyCFunction)rpmfi_FFlags, METH_NOARGS, - NULL}, + "fi.FFlags() -- Return the flags of the current file."}, {"VFlags", (PyCFunction)rpmfi_VFlags, METH_NOARGS, - NULL}, + "fi.VFlags() -- Return the verify flags of the current file.\n\nSee RPMVERIFY_* (in rpmvf.h)"}, {"FMode", (PyCFunction)rpmfi_FMode, METH_NOARGS, - NULL}, + "fi.FMode() -- Return the mode flags of the current file."}, {"FState", (PyCFunction)rpmfi_FState, METH_NOARGS, - NULL}, + "fi.FState() -- Return the file state of the current file."}, {"MD5", (PyCFunction)rpmfi_Digest, METH_NOARGS, - NULL}, + "fi.() -- Return the checksum of the current file.\n\nDEPRECATED! Use fi.Digest instead!"}, {"Digest", (PyCFunction)rpmfi_Digest, METH_NOARGS, - NULL}, + "fi.() -- Return the checksum of the current file."}, {"FLink", (PyCFunction)rpmfi_FLink, METH_NOARGS, - NULL}, + "fi.() -- Return the link target of the current file.\n\nFor soft links only."}, {"FSize", (PyCFunction)rpmfi_FSize, METH_NOARGS, - NULL}, + "fi.() -- Return the size of the current file."}, {"FRdev", (PyCFunction)rpmfi_FRdev, METH_NOARGS, - NULL}, + "fi.() -- Return the device number of the current file.\n\nFor device files only."}, {"FMtime", (PyCFunction)rpmfi_FMtime, METH_NOARGS, - NULL}, + "fi.() -- Return the modification time of the current file."}, {"FUser", (PyCFunction)rpmfi_FUser, METH_NOARGS, - NULL}, + "fi.() -- Return the user name owning the current file."}, {"FGroup", (PyCFunction)rpmfi_FGroup, METH_NOARGS, - NULL}, + "fi.() -- Return the group name of the current file."}, {"FColor", (PyCFunction)rpmfi_FColor, METH_NOARGS, - NULL}, + "fi.() -- Return the color of the current file.\n\n2 for 64 bit binaries\n1 for 32 bit binaries\n0 for everything else"}, {"FClass", (PyCFunction)rpmfi_FClass, METH_NOARGS, - NULL}, + "fi.() -- Return the classification of the current file."}, + {"FLinks", (PyCFunction)rpmfi_FLinks, METH_NOARGS, + "fi.() -- Return the number of hardlinks pointing to of the\ncurrent file."}, {NULL, NULL} /* sentinel */ }; @@ -299,13 +335,15 @@ static PyObject * rpmfi_new(PyTypeObject * subtype, PyObject *args, PyObject *kw rpmfi fi = NULL; rpmTagVal tagN = RPMTAG_BASENAMES; int flags = 0; - char * kwlist[] = {"header", "tag", "flags", NULL}; + rpmstrPool pool = NULL; + char * kwlist[] = {"header", "tag", "flags", "pool", NULL}; - if (!PyArg_ParseTupleAndKeywords(args, kwds, "O&|Oi:rpmfi_init", kwlist, - hdrFromPyObject, &h, &to, &flags)) + if (!PyArg_ParseTupleAndKeywords(args, kwds, "O&|OiO&:rpmfi_init", kwlist, + hdrFromPyObject, &h, &to, &flags, + poolFromPyObject, &pool)) return NULL; - fi = rpmfiNew(NULL, h, tagN, flags); + fi = rpmfiNewPool(pool, h, tagN, flags); if (fi == NULL) { PyErr_SetString(PyExc_ValueError, "invalid file data in header"); @@ -316,11 +354,15 @@ static PyObject * rpmfi_new(PyTypeObject * subtype, PyObject *args, PyObject *kw } static char rpmfi_doc[] = -""; +"File iterator\n\n" +"DEPRECATED! This old API mixes storing and iterating over the meta data\n" +"of the files of a package. Use rpm.files and rpm.file data types as a\n" +"much cleaner API.\n\n" +"Iteration returns a tuple of\n(FN, FSize, FMode, FMtime, FFlags, FRdev, FInode, FNlink, FState,\n VFlags, FUser, FGroup, Digest)"; PyTypeObject rpmfi_Type = { PyVarObject_HEAD_INIT(&PyType_Type, 0) - PYTHON_MODULENAME".fi", /* tp_name */ + "rpm.fi", /* tp_name */ sizeof(rpmfiObject), /* tp_basicsize */ 0, /* tp_itemsize */ /* methods */ diff --git a/python/rpmfiles-py.c b/python/rpmfiles-py.c new file mode 100644 index 000000000..d69d1f2ee --- /dev/null +++ b/python/rpmfiles-py.c @@ -0,0 +1,598 @@ +#include "rpmsystem-py.h" + +#include <rpm/rpmtypes.h> +#include <rpm/rpmpgp.h> + +#include "header-py.h" +#include "rpmfi-py.h" +#include "rpmfiles-py.h" +#include "rpmfd-py.h" +#include "rpmarchive-py.h" +#include "rpmstrpool-py.h" + +/* A single file from rpmfiles set, can't be independently instanciated */ +struct rpmfileObject_s { + PyObject_HEAD + PyObject *md_dict; + rpmfiles files; /* reference to rpmfiles */ + int ix; /* index to rpmfiles */ +}; + +static void rpmfile_dealloc(rpmfileObject * s) +{ + s->files = rpmfilesFree(s->files); + Py_TYPE(s)->tp_free((PyObject *)s); +} + +static char rpmfile_doc[] = + "Gives access to the meta data of a single file.\n\n" + "Instances of this class are only available through an rpm.files object."; + +static PyObject *rpmfile_fx(rpmfileObject *s) +{ + return Py_BuildValue("i", s->ix); +} + +static PyObject *rpmfile_dx(rpmfileObject *s) +{ + return Py_BuildValue("i", rpmfilesDI(s->files, s->ix)); +} + +static PyObject *rpmfile_name(rpmfileObject *s) +{ + char * fn = rpmfilesFN(s->files, s->ix); + PyObject *o = Py_BuildValue("s", fn); + free(fn); + return o; +} + +static PyObject *rpmfile_basename(rpmfileObject *s) +{ + return Py_BuildValue("s", rpmfilesBN(s->files, s->ix)); +} + +static PyObject *rpmfile_dirname(rpmfileObject *s) +{ + return Py_BuildValue("s", rpmfilesDN(s->files, rpmfilesDI(s->files, s->ix))); +} + +static PyObject *rpmfile_orig_name(rpmfileObject *s) +{ + char * fn = rpmfilesOFN(s->files, s->ix); + PyObject *o = Py_BuildValue("s", fn); + free(fn); + return o; +} + +static PyObject *rpmfile_orig_basename(rpmfileObject *s) +{ + return Py_BuildValue("s", rpmfilesOBN(s->files, s->ix)); +} + +static PyObject *rpmfile_orig_dirname(rpmfileObject *s) +{ + return Py_BuildValue("s", rpmfilesODN(s->files, rpmfilesODI(s->files, s->ix))); +} +static PyObject *rpmfile_mode(rpmfileObject *s) +{ + return Py_BuildValue("i", rpmfilesFMode(s->files, s->ix)); +} + +static PyObject *rpmfile_size(rpmfileObject *s) +{ + return Py_BuildValue("L", rpmfilesFSize(s->files, s->ix)); +} + +static PyObject *rpmfile_mtime(rpmfileObject *s) +{ + return Py_BuildValue("i", rpmfilesFMtime(s->files, s->ix)); +} + +static PyObject *rpmfile_rdev(rpmfileObject *s) +{ + return Py_BuildValue("i", rpmfilesFRdev(s->files, s->ix)); +} + +static PyObject *rpmfile_inode(rpmfileObject *s) +{ + return Py_BuildValue("i", rpmfilesFInode(s->files, s->ix)); +} + +static PyObject *rpmfile_nlink(rpmfileObject *s) +{ + return Py_BuildValue("i", rpmfilesFNlink(s->files, s->ix)); +} + +static PyObject *rpmfile_linkto(rpmfileObject *s) +{ + return Py_BuildValue("s", rpmfilesFLink(s->files, s->ix)); +} + +static PyObject *rpmfile_user(rpmfileObject *s) +{ + return Py_BuildValue("s", rpmfilesFUser(s->files, s->ix)); +} + +static PyObject *rpmfile_group(rpmfileObject *s) +{ + return Py_BuildValue("s", rpmfilesFGroup(s->files, s->ix)); +} + +static PyObject *rpmfile_fflags(rpmfileObject *s) +{ + return Py_BuildValue("i", rpmfilesFFlags(s->files, s->ix)); +} + +static PyObject *rpmfile_vflags(rpmfileObject *s) +{ + return Py_BuildValue("i", rpmfilesVFlags(s->files, s->ix)); +} + +static PyObject *rpmfile_color(rpmfileObject *s) +{ + return Py_BuildValue("i", rpmfilesFColor(s->files, s->ix)); +} + +static PyObject *rpmfile_state(rpmfileObject *s) +{ + return Py_BuildValue("i", rpmfilesFState(s->files, s->ix)); +} + +static PyObject *rpmfile_digest(rpmfileObject *s) +{ + size_t diglen = 0; + const unsigned char *digest = rpmfilesFDigest(s->files, s->ix, + NULL, &diglen); + if (digest) { + char * hex = pgpHexStr(digest, diglen); + PyObject *o = Py_BuildValue("s", hex); + free(hex); + return o; + } + Py_RETURN_NONE; +} + +static PyObject *rpmfile_class(rpmfileObject *s) +{ + return Py_BuildValue("s", rpmfilesFClass(s->files, s->ix)); +} + +static PyObject *rpmfile_caps(rpmfileObject *s) +{ + return Py_BuildValue("s", rpmfilesFCaps(s->files, s->ix)); +} + +static PyObject *rpmfile_langs(rpmfileObject *s) +{ + return Py_BuildValue("s", rpmfilesFLangs(s->files, s->ix)); +} + +static PyObject *rpmfile_links(rpmfileObject *s) +{ + PyObject *result = NULL; + const int * links = NULL; + uint32_t nlinks = rpmfilesFLinks(s->files, s->ix, &links); + + if (nlinks == 0) + Py_RETURN_NONE; + else if (nlinks == 1) + links = &s->ix; /* file itself */ + + result = PyTuple_New(nlinks); + if (result) { + for (uint32_t i = 0; i < nlinks; i++) { + int lix = links[i]; + PyObject * o; + + if (lix == s->ix) { + /* file itself, return a reference instead of new object */ + Py_INCREF(s); + o = (PyObject *) s; + } else { + o = rpmfile_Wrap(s->files, lix); + } + + PyTuple_SET_ITEM(result, i, o); + } + } + return result; +} + +/* + * Exported as "matches" instead of a rich comparison operator or such + * as this cannot be used for comparing file *object* equality, + * rpmfilesCompare() determines whether the file *contents* match. + */ +static PyObject *rpmfile_matches(rpmfileObject *s, PyObject *o) +{ + PyObject *result = NULL; + if (rpmfileObject_Check(o)) { + rpmfileObject *of = (rpmfileObject *)o; + int rc = rpmfilesCompare(s->files, s->ix, of->files, of->ix); + result = PyBool_FromLong(rc == 0); + } else { + PyErr_SetObject(PyExc_TypeError, o); + } + return result; +} + +static PyObject *rpmfile_verify(rpmfileObject *s, PyObject *args, PyObject *kwds) +{ + static char *kwlist[] = { "omitMask", NULL }; + rpmVerifyAttrs omitMask = 0; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|i", kwlist, &omitMask)) + return NULL; + + return Py_BuildValue("i", rpmfilesVerify(s->files, s->ix, omitMask)); +} + +static PyGetSetDef rpmfile_getseters[] = { + { "fx", (getter) rpmfile_fx, NULL, + "index in header and rpm.files object" }, + { "dx", (getter) rpmfile_dx, NULL, + "index of dirname entry" }, + { "name", (getter) rpmfile_name, NULL, + "file name (path)" }, + { "basename", (getter) rpmfile_basename, NULL, NULL }, + { "dirname", (getter) rpmfile_dirname, NULL, NULL }, + { "orig_name", (getter) rpmfile_orig_name, NULL, + "original file name (may differ due to relocation)" }, + { "orig_basename", (getter) rpmfile_orig_basename, NULL, + "original base name (may differ due to relocation)" }, + { "orig_dirname", (getter) rpmfile_orig_dirname, NULL, + "original dir name (may differ due to relocation)" }, + { "mode", (getter) rpmfile_mode, NULL, + "mode flags / unix permissions" }, + { "mtime", (getter) rpmfile_mtime, NULL, + "modification time (in unix time)" }, + { "size", (getter) rpmfile_size, NULL, + "file size" }, + { "rdev", (getter) rpmfile_rdev, NULL, + "device number - for device files only" }, + { "inode", (getter) rpmfile_inode, NULL, + "inode number - contains fake, data used to identify hard liked files" }, + { "fflags", (getter) rpmfile_fflags, NULL, + "file flags - see RPMFILE_* constants" }, + { "vflags", (getter) rpmfile_vflags, NULL, + "verification flags - see RPMVERIFY_* (in rpmvf.h)" }, + { "linkto", (getter) rpmfile_linkto, NULL, + "link target - symlinks only" }, + { "color", (getter) rpmfile_color, NULL, + "file color - 2 for 64 bit binaries, 1 for 32 bit binaries, 0 else" }, + { "nlink", (getter) rpmfile_nlink, NULL, + "number of hardlinks pointing to the same content as this file" }, + { "links", (getter) rpmfile_links, NULL, + "list of file indexes that are hardlinked with this file" }, + { "user", (getter) rpmfile_user, NULL, + "user name owning this file" }, + { "group", (getter) rpmfile_group, NULL, + "group name owning this file" }, + { "digest", (getter) rpmfile_digest, NULL, + "check sum of file content" }, + { "class", (getter) rpmfile_class, NULL, + "classfication of file content based on libmagic/file(1)" }, + { "state", (getter) rpmfile_state, NULL, + "file state - see RPMFILE_STATE_* constants" }, + { "langs", (getter) rpmfile_langs, NULL, + "language the file provides (typically for doc files)" }, + { "caps", (getter) rpmfile_caps, NULL, + "file capabilities" }, + { NULL, NULL, NULL, NULL } +}; + +static struct PyMethodDef rpmfile_methods[] = { + { "matches", (PyCFunction) rpmfile_matches, METH_O, + NULL }, + { "verify", (PyCFunction) rpmfile_verify, METH_VARARGS|METH_KEYWORDS, + NULL }, + { NULL, NULL, 0, NULL } +}; + +PyTypeObject rpmfile_Type = { + PyVarObject_HEAD_INIT(&PyType_Type, 0) + "rpm.file", /* tp_name */ + sizeof(rpmfileObject), /* tp_basicsize */ + 0, /* tp_itemsize */ + /* methods */ + (destructor) rpmfile_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + (reprfunc)rpmfile_name, /* tp_str */ + PyObject_GenericGetAttr, /* tp_getattro */ + PyObject_GenericSetAttr, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, /* tp_flags */ + rpmfile_doc, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + rpmfile_methods, /* tp_methods */ + 0, /* tp_members */ + rpmfile_getseters, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + 0, /* tp_new */ + 0, /* tp_free */ + 0, /* tp_is_gc */ +}; + +PyObject * rpmfile_Wrap(rpmfiles files, int ix) +{ + rpmfileObject *s = PyObject_New(rpmfileObject, &rpmfile_Type); + if (s == NULL) return NULL; + + s->files = rpmfilesLink(files); + s->ix = ix; + return (PyObject *) s; +} + +/* The actual rpmfiles info set */ +struct rpmfilesObject_s { + PyObject_HEAD + PyObject *md_dict; /*!< to look like PyModuleObject */ + rpmfiles files; +}; + +static void rpmfiles_dealloc(rpmfilesObject * s) +{ + s->files = rpmfilesFree(s->files); + Py_TYPE(s)->tp_free((PyObject *)s); +} + +static PyObject * rpmfiles_new(PyTypeObject * subtype, PyObject *args, PyObject *kwds) +{ + PyObject * to = NULL; + Header h = NULL; + rpmfiles files = NULL; + rpmTagVal tagN = RPMTAG_BASENAMES; + int flags = 0; + rpmstrPool pool = NULL; + char * kwlist[] = {"header", "tag", "flags", "pool", NULL}; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "O&|OiO&:rpmfiles_new", kwlist, + hdrFromPyObject, &h, &to, &flags, + poolFromPyObject, &pool)) + return NULL; + + files = rpmfilesNew(pool, h, tagN, flags); + + if (files == NULL) { + PyErr_SetString(PyExc_ValueError, "invalid file data in header"); + return NULL; + } + + return rpmfiles_Wrap(subtype, files); +} + +static Py_ssize_t rpmfiles_length(rpmfilesObject *s) +{ + return rpmfilesFC(s->files); +} + +static PyObject * rpmfiles_getitem(rpmfilesObject *s, Py_ssize_t ix) +{ + if (ix >= 0 && ix < rpmfilesFC(s->files)) + return rpmfile_Wrap(s->files, ix); + + PyErr_SetObject(PyExc_IndexError, Py_BuildValue("i", ix)); + return NULL; +} + +static int rpmfiles_contains(rpmfilesObject *s, PyObject *value) +{ + const char *fn = NULL; + + if (!PyArg_Parse(value, "s", &fn)) + return -1; + + return (rpmfilesFindFN(s->files, fn) >= 0) ? 1 : 0; +} + +static PySequenceMethods rpmfiles_as_sequence = { + (lenfunc)rpmfiles_length, /* sq_length */ + 0, /* sq_concat */ + 0, /* sq_repeat */ + (ssizeargfunc) rpmfiles_getitem, /* sq_item */ + 0, /* sq_slice */ + 0, /* sq_ass_item */ + 0, /* sq_ass_slice */ + (objobjproc)rpmfiles_contains, /* sq_contains */ + 0, /* sq_inplace_concat */ + 0, /* sq_inplace_repeat */ +}; + +static PyObject * rpmfiles_find(rpmfileObject *s, + PyObject *args, PyObject *kwds) +{ + const char *fn = NULL; + int fx, orig = 0; + char * kwlist[] = {"filename", "orig", NULL}; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "s|i", kwlist, &fn, &orig)) + return NULL; + + if (orig) + fx = rpmfilesFindOFN(s->files, fn); + else + fx = rpmfilesFindFN(s->files, fn); + + if (fx >= 0) + return rpmfile_Wrap(s->files, fx); + + Py_RETURN_NONE; +} + +static PyObject *rpmfiles_archive(rpmfilesObject *s, + PyObject *args, PyObject *kwds) +{ + char * kwlist[] = {"fd", "write", NULL}; + rpmfdObject *fdo = NULL; + FD_t fd = NULL; + rpmfi archive = NULL; + int writer = 0; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "O&|i", kwlist, + rpmfdFromPyObject, &fdo, &writer)) { + return NULL; + } + + fd = rpmfdGetFd(fdo); + if (writer) { + archive = rpmfiNewArchiveWriter(fd, s->files); + } else { + archive = rpmfiNewArchiveReader(fd, s->files, RPMFI_ITER_READ_ARCHIVE); + } + + return rpmarchive_Wrap(&rpmarchive_Type, s->files, archive); +} + +static PyObject *rpmfiles_subscript(rpmfilesObject *s, PyObject *item) +{ + PyObject *str = NULL; + + /* treat numbers as sequence accesses */ + if (PyInt_Check(item)) { + return rpmfiles_getitem(s, PyInt_AsSsize_t(item)); + } else if (PyLong_Check(item)) { + return rpmfiles_getitem(s, PyLong_AsSsize_t(item)); + } + + /* handle slices by returning tuples of rpm.file items */ + if (PySlice_Check(item)) { + Py_ssize_t start, stop, step, slicelength, i, cur; + PyObject * result; + + if (PySlice_GetIndicesEx( +#if PY_MAJOR_VERSION < 3 + (PySliceObject*) +#endif + item, rpmfiles_length(s), + &start, &stop, &step, &slicelength) < 0) { + return NULL; + } + + result = PyTuple_New(slicelength); + if (result) { + for (cur = start, i = 0; i < slicelength; cur += step, i++) { + PyTuple_SET_ITEM(result, i, rpmfiles_getitem(s, cur)); + } + } + return result; + } + + /* ... and strings as mapping access */ + if (utf8FromPyObject(item, &str)) { + int fx = rpmfilesFindFN(s->files, PyBytes_AsString(str)); + Py_DECREF(str); + + if (fx >= 0) { + return rpmfile_Wrap(s->files, fx); + } else { + PyErr_SetObject(PyExc_KeyError, item); + } + } else { + PyErr_SetObject(PyExc_TypeError, item); + } + + return NULL; +} + +static PyMappingMethods rpmfiles_as_mapping = { + (lenfunc) rpmfiles_length, /* mp_length */ + (binaryfunc) rpmfiles_subscript, /* mp_subscript */ + 0, /* mp_ass_subscript */ +}; + +static struct PyMethodDef rpmfiles_methods[] = { + { "archive", (PyCFunction) rpmfiles_archive, METH_VARARGS|METH_KEYWORDS, + "files.archive(fd, write=False) -- Return a rpm.archive object\n\n" + "Args:\n" + " fd : File to read from or write to.\n" + " write : True to get an archive writer, False for an archive reader"}, + { "find", (PyCFunction) rpmfiles_find, METH_VARARGS|METH_KEYWORDS, + "files.find(filename, orig=False) -- Return index of given file name.\n\n" + " Return -1 if file is not found.\n" + " Leading \".\" in filename is ignored."}, + { NULL, NULL, 0, NULL } +}; + +static char rpmfiles_doc[] = + "rpm.files(hdr, tag=RPMTAG_BASENAMES, flags=None, pool=None)\n\n" + "Stores the meta data of a package's files.\n\n" + "Args:\n" + "\thdr: The header object to get the data from.\n" + "\tflags : Controls which data to store and whether to create\n\t\tcopies or use the data from the header.\n\t\tBy default all data is copied.\n\t\tSee RPMFI_* constants in rpmfiles.h.\n" + "\tpool : rpm.strpool object to store the strings in.\n\t\tLeave empty to use global pool.\n" + "\ttag : Obsolete. Leave alone!\n\n" + "rpm.files is basically a sequence of rpm.file objects.\nNote that this is a read only data structure. To write file data you\nhave to write it directly into aheader object."; + +PyTypeObject rpmfiles_Type = { + PyVarObject_HEAD_INIT(&PyType_Type, 0) + "rpm.files", /* tp_name */ + sizeof(rpmfilesObject), /* tp_basicsize */ + 0, /* tp_itemsize */ + /* methods */ + (destructor) rpmfiles_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + &rpmfiles_as_sequence, /* tp_as_sequence */ + &rpmfiles_as_mapping, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + PyObject_GenericGetAttr, /* tp_getattro */ + PyObject_GenericSetAttr, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, /* tp_flags */ + rpmfiles_doc, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + rpmfiles_methods, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + (newfunc) rpmfiles_new, /* tp_new */ + 0, /* tp_free */ + 0, /* tp_is_gc */ +}; + +PyObject * rpmfiles_Wrap(PyTypeObject *subtype, rpmfiles files) +{ + rpmfilesObject *s = (rpmfilesObject *)subtype->tp_alloc(subtype, 0); + if (s == NULL) return NULL; + + s->files = files; + return (PyObject *) s; +} + diff --git a/python/rpmfiles-py.h b/python/rpmfiles-py.h new file mode 100644 index 000000000..2e27d3db4 --- /dev/null +++ b/python/rpmfiles-py.h @@ -0,0 +1,18 @@ +#ifndef H_RPMFILES_PY +#define H_RPMFILES_PY + +#include <rpm/rpmfiles.h> + +typedef struct rpmfileObject_s rpmfileObject; +typedef struct rpmfilesObject_s rpmfilesObject; + +extern PyTypeObject rpmfile_Type; +extern PyTypeObject rpmfiles_Type; + +#define rpmfileObject_Check(v) ((v)->ob_type == &rpmfile_Type) +#define rpmfilesObject_Check(v) ((v)->ob_type == &rpmfiles_Type) + +PyObject * rpmfile_Wrap(rpmfiles files, int ix); +PyObject * rpmfiles_Wrap(PyTypeObject *subtype, rpmfiles files); + +#endif diff --git a/python/rpmii-py.c b/python/rpmii-py.c index 9209b54e5..180741479 100644 --- a/python/rpmii-py.c +++ b/python/rpmii-py.c @@ -1,7 +1,9 @@ #include "rpmsystem-py.h" #include <rpm/rpmdb.h> +#include <rpm/rpmtd.h> +#include "rpmtd-py.h" #include "rpmii-py.h" #include "header-py.h" @@ -36,18 +38,25 @@ struct rpmiiObject_s { PyObject *md_dict; /*!< to look like PyModuleObject */ PyObject *ref; /* for db/ts refcounting */ rpmdbIndexIterator ii; + rpmtd keytd; }; static PyObject * rpmii_iternext(rpmiiObject * s) { - char * key; - size_t keylen; - if (s->ii == NULL || (rpmdbIndexIteratorNext(s->ii, (const void**)&key, &keylen)) != 0) { - s->ii = rpmdbIndexIteratorFree(s->ii); - return NULL; + PyObject *keyo = NULL; + + if (s->ii != NULL) { + if (rpmdbIndexIteratorNextTd(s->ii, s->keytd) == 0) { + /* The keys must never be arrays so rpmtd_AsPyObj() wont work */ + keyo = rpmtd_ItemAsPyobj(s->keytd, rpmtdClass(s->keytd)); + rpmtdFreeData(s->keytd); + } else { + s->ii = rpmdbIndexIteratorFree(s->ii); + } } - return PyBytes_FromStringAndSize(key, keylen); + + return keyo; }; static PyObject * @@ -75,6 +84,7 @@ static struct PyMethodDef rpmii_methods[] = { static void rpmii_dealloc(rpmiiObject * s) { s->ii = rpmdbIndexIteratorFree(s->ii); + rpmtdFree(s->keytd); Py_DECREF(s->ref); Py_TYPE(s)->tp_free((PyObject *)s); } @@ -88,6 +98,9 @@ static PyNumberMethods rpmii_as_number = { 0, /* nb_add */ 0, /* nb_subtract */ 0, /* nb_multiply */ +#if PY_MAJOR_VERSION < 3 + 0, /* nb_divide */ +#endif 0, /* nb_remainder */ 0, /* nb_divmod */ 0, /* nb_power */ @@ -102,7 +115,7 @@ static char rpmii_doc[] = PyTypeObject rpmii_Type = { PyVarObject_HEAD_INIT(&PyType_Type, 0) - PYTHON_MODULENAME".ii", /* tp_name */ + "rpm.ii", /* tp_name */ sizeof(rpmiiObject), /* tp_size */ 0, /* tp_itemsize */ (destructor) rpmii_dealloc, /* tp_dealloc */ @@ -150,6 +163,7 @@ PyObject * rpmii_Wrap(PyTypeObject *subtype, rpmdbIndexIterator ii, PyObject *s) iio->ii = ii; iio->ref = s; + iio->keytd = rpmtdNew(); Py_INCREF(iio->ref); return (PyObject *) iio; } diff --git a/python/rpmkeyring-py.c b/python/rpmkeyring-py.c index 7df847db7..d5f131e42 100644 --- a/python/rpmkeyring-py.c +++ b/python/rpmkeyring-py.c @@ -52,7 +52,7 @@ static char rpmPubkey_doc[] = ""; PyTypeObject rpmPubkey_Type = { PyVarObject_HEAD_INIT(&PyType_Type, 0) - PYTHON_MODULENAME".pubkey", /* tp_name */ + "rpm.pubkey", /* tp_name */ sizeof(rpmPubkeyObject), /* tp_size */ 0, /* tp_itemsize */ (destructor) rpmPubkey_dealloc,/* tp_dealloc */ @@ -133,7 +133,7 @@ static char rpmKeyring_doc[] = PyTypeObject rpmKeyring_Type = { PyVarObject_HEAD_INIT(&PyType_Type, 0) - PYTHON_MODULENAME".keyring", /* tp_name */ + "rpm.keyring", /* tp_name */ sizeof(rpmKeyringObject), /* tp_size */ 0, /* tp_itemsize */ (destructor) rpmKeyring_dealloc,/* tp_dealloc */ diff --git a/python/rpmmacro-py.c b/python/rpmmacro-py.c index 3eb0acb56..3cb1a51f5 100644 --- a/python/rpmmacro-py.c +++ b/python/rpmmacro-py.c @@ -2,6 +2,7 @@ #include <rpm/rpmmacro.h> +#include "header-py.h" /* XXX for pyrpmError, doh */ #include "rpmmacro-py.h" PyObject * @@ -14,7 +15,7 @@ rpmmacro_AddMacro(PyObject * self, PyObject * args, PyObject * kwds) &name, &val)) return NULL; - addMacro(NULL, name, NULL, val, -1); + rpmPushMacro(NULL, name, NULL, val, -1); Py_RETURN_NONE; } @@ -28,7 +29,7 @@ rpmmacro_DelMacro(PyObject * self, PyObject * args, PyObject * kwds) if (!PyArg_ParseTupleAndKeywords(args, kwds, "s:DelMacro", kwlist, &name)) return NULL; - delMacro(NULL, name); + rpmPopMacro(NULL, name); Py_RETURN_NONE; } @@ -37,7 +38,7 @@ PyObject * rpmmacro_ExpandMacro(PyObject * self, PyObject * args, PyObject * kwds) { const char *macro; - PyObject *res; + PyObject *res = NULL; int num = 0; char * kwlist[] = {"macro", "numeric", NULL}; @@ -47,8 +48,11 @@ rpmmacro_ExpandMacro(PyObject * self, PyObject * args, PyObject * kwds) if (num) { res = Py_BuildValue("i", rpmExpandNumeric(macro)); } else { - char *str = rpmExpand(macro, NULL); - res = Py_BuildValue("s", str); + char *str = NULL; + if (rpmExpandMacros(NULL, macro, &str, 0) < 0) + PyErr_SetString(pyrpmError, "error expanding macro"); + else + res = Py_BuildValue("s", str); free(str); } return res; diff --git a/python/rpmmi-py.c b/python/rpmmi-py.c index 70bb1665b..379cafb38 100644 --- a/python/rpmmi-py.c +++ b/python/rpmmi-py.c @@ -1,6 +1,7 @@ #include "rpmsystem-py.h" #include <rpm/rpmdb.h> +#include <rpm/header.h> #include "rpmmi-py.h" #include "header-py.h" @@ -36,20 +37,20 @@ * \code * import rpm * ts = rpm.TransactionSet() - * mi = ts.dbMatch('name', "kernel") + * mi = ts.dbMatch('name', 'kernel') * for h in mi: - * print "%s-%s-%s" % (h['name'], h['version'], h['release']) + * print '%s-%s-%s' % (h['name'], h['version'], h['release']) * \endcode * * Finally, here's an example that retrieves all packages whose name - * matches the glob expression "XFree*": + * matches the glob expression 'XFree*': * \code * import rpm * ts = rpm.TransactionSet() * mi = ts.dbMatch() - * mi.pattern('name', rpm.RPMMIRE_GLOB, "XFree*") + * mi.pattern('name', rpm.RPMMIRE_GLOB, 'XFree*') * for h in mi: - * print "%s-%s-%s" % (h['name'], h['version'], h['release']) + * print '%s-%s-%s' % (h['name'], h['version'], h['release']) * \endcode * */ @@ -74,6 +75,7 @@ rpmmi_iternext(rpmmiObject * s) s->mi = rpmdbFreeIterator(s->mi); return NULL; } + headerLink(h); return hdr_Wrap(&hdr_Type, h); } @@ -114,7 +116,7 @@ rpmmi_Pattern(rpmmiObject * s, PyObject * args, PyObject * kwds) static struct PyMethodDef rpmmi_methods[] = { {"instance", (PyCFunction) rpmmi_Instance, METH_NOARGS, - NULL }, + "mi.instance() -- Return the number (db key) of the current header."}, {"count", (PyCFunction) rpmmi_Count, METH_NOARGS, "Deprecated, use len(mi) instead.\n" }, {"pattern", (PyCFunction) rpmmi_Pattern, METH_VARARGS|METH_KEYWORDS, @@ -149,6 +151,9 @@ static PyNumberMethods rpmmi_as_number = { 0, /* nb_add */ 0, /* nb_subtract */ 0, /* nb_multiply */ +#if PY_MAJOR_VERSION < 3 + 0, /* nb_divide */ +#endif 0, /* nb_remainder */ 0, /* nb_divmod */ 0, /* nb_power */ @@ -159,11 +164,44 @@ static PyNumberMethods rpmmi_as_number = { }; static char rpmmi_doc[] = -""; + "rpm.mi match iterator object represents the result of a\n" + " database query.\n" + "\n" + "Instances of the rpm.mi object provide access to headers that match\n" + "certain criteria. Typically, a primary index is accessed to find\n" + "a set of headers that contain a key, and each header is returned\n" + "serially.\n" + "\n" + "To obtain a rpm.mi object to query the database used by a transaction,\n" + "the ts.match(tag,key,len) method is used.\n" + "\n" + "Here's an example that prints the name of all installed packages:\n" + " import rpm\n" + " ts = rpm.TransactionSet()\n" + " for h in ts.dbMatch():\n" + " print h['name']\n" + "\n" + "Here's a more typical example that uses the Name index to retrieve\n" + "all installed kernel(s):\n" + " import rpm\n" + " ts = rpm.TransactionSet()\n" + " mi = ts.dbMatch('name', 'kernel')\n" + " for h in mi:\n" + " print '%s-%s-%s' % (h['name'], h['version'], h['release'])\n" + "\n" + "Finally, here's an example that retrieves all packages whose name\n" + "matches the glob expression 'XFree*':\n" + " import rpm\n" + " ts = rpm.TransactionSet()\n" + " mi = ts.dbMatch()\n" + " mi.pattern('name', rpm.RPMMIRE_GLOB, 'XFree*')\n" + " for h in mi:\n" + " print '%s-%s-%s' % (h['name'], h['version'], h['release'])\n" +; PyTypeObject rpmmi_Type = { PyVarObject_HEAD_INIT(&PyType_Type, 0) - PYTHON_MODULENAME".mi", /* tp_name */ + "rpm.mi", /* tp_name */ sizeof(rpmmiObject), /* tp_size */ 0, /* tp_itemsize */ (destructor) rpmmi_dealloc, /* tp_dealloc */ diff --git a/python/rpmmodule.c b/python/rpmmodule.c index a4fe217dd..d1390e889 100644 --- a/python/rpmmodule.c +++ b/python/rpmmodule.c @@ -8,14 +8,17 @@ #include <rpm/rpmmacro.h> #include "header-py.h" +#include "rpmarchive-py.h" #include "rpmds-py.h" #include "rpmfd-py.h" #include "rpmfi-py.h" +#include "rpmfiles-py.h" #include "rpmkeyring-py.h" #include "rpmmi-py.h" #include "rpmii-py.h" #include "rpmps-py.h" #include "rpmmacro-py.h" +#include "rpmstrpool-py.h" #include "rpmtd-py.h" #include "rpmte-py.h" #include "rpmts-py.h" @@ -46,10 +49,18 @@ static PyObject * signalCaught(PyObject *self, PyObject *o) static PyObject * checkSignals(PyObject * self) { - rpmdbCheckSignals(); - Py_RETURN_NONE; + return Py_BuildValue("i", rpmsqPoll()); +} + +static PyObject * blockSignals(PyObject * self, PyObject *arg) +{ + int block; + if (!PyArg_Parse(arg, "p", &block)) return NULL; + + return Py_BuildValue("i", rpmsqBlock(block ? SIG_BLOCK : SIG_UNBLOCK)); } + static PyObject * setLogFile (PyObject * self, PyObject *arg) { FILE *fp; @@ -131,56 +142,83 @@ static PyObject * reloadConfig(PyObject * self, PyObject * args, PyObject *kwds) return PyBool_FromLong(rc == 0); } +static PyObject * setInterruptSafety(PyObject * self, PyObject * args, PyObject *kwds) +{ + int on = 1; + PyObject * obj; + char * kwlist[] = { "on", NULL }; + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O", kwlist, &obj)) + return NULL; + if (obj) { + on = PyObject_IsTrue(obj); + } + rpmsqSetInterruptSafety(on); + Py_RETURN_NONE; +} + static PyMethodDef rpmModuleMethods[] = { { "addMacro", (PyCFunction) rpmmacro_AddMacro, METH_VARARGS|METH_KEYWORDS, - NULL }, + "rpmPushMacro(macro, value)\n" + }, { "delMacro", (PyCFunction) rpmmacro_DelMacro, METH_VARARGS|METH_KEYWORDS, - NULL }, + "rpmPopMacro(macro)\n" + }, { "expandMacro", (PyCFunction) rpmmacro_ExpandMacro, METH_VARARGS|METH_KEYWORDS, - NULL }, + "expandMacro(string, numeric=False) -- expands a string containing macros\n\n" + "Returns an int if numeric is True. 'Y' or 'y' returns 1,\n'N' or 'n' returns 0\nAn undefined macro returns 0."}, { "archscore", (PyCFunction) archScore, METH_O, - NULL }, + "archscore(archname) -- How well does an architecture fit on this machine\n\n" + "0 for non matching arch names\n1 for best arch\nhigher numbers for less fitting arches\n(e.g. 2 for \"i586\" on an i686 machine)" }, { "signalCaught", (PyCFunction) signalCaught, METH_O, - NULL }, + "signalCaught(signo) -- Returns True if signal was caught." }, { "checkSignals", (PyCFunction) checkSignals, METH_NOARGS, - NULL }, + "checkSignals() -- Check for and exit on termination signals."}, + { "blockSignals", (PyCFunction) blockSignals, METH_O, + "blocksignals(True/False) -- Block/unblock signals, refcounted."}, { "mergeHeaderListFromFD", (PyCFunction) rpmMergeHeadersFromFD, METH_VARARGS|METH_KEYWORDS, NULL }, { "log", (PyCFunction) doLog, METH_VARARGS|METH_KEYWORDS, - NULL }, + "log(level, msg) -- Write msg to log if level is selected to be logged.\n\n" + "level must be one of the RPMLOG_* constants."}, { "setLogFile", (PyCFunction) setLogFile, METH_O, - NULL }, + "setLogFile(file) -- set file to write log messages to or None." }, { "versionCompare", (PyCFunction) versionCompare, METH_VARARGS|METH_KEYWORDS, - NULL }, + "versionCompare(version0, version1) -- compares two version strings\n\n" + "Returns 1 if version0 > version1\n" + "Returns 0 if version0 == version1\n" + "Returns -1 if version0 < version1\n"}, { "labelCompare", (PyCFunction) labelCompare, METH_VARARGS|METH_KEYWORDS, - NULL }, + "labelCompare(version0, version1) -- as versionCompare()\n\n" + "but arguments are tuples of of strings for (epoch, version, release)"}, { "setVerbosity", (PyCFunction) setVerbosity, METH_O, - NULL }, + "setVerbosity(level) -- Set log level. See RPMLOG_* constants." }, { "setEpochPromote", (PyCFunction) setEpochPromote, METH_O, - NULL }, + "setEpochPromote(bool) -- Set if no epoch shall be treated as epoch 0" }, { "setStats", (PyCFunction) setStats, METH_O, - NULL }, + "setStats(bool) -- Set if timing stats are printed after a transaction."}, { "reloadConfig", (PyCFunction) reloadConfig, METH_VARARGS|METH_KEYWORDS, - NULL }, - + "reloadConfig(target=None) -- Reload config from files.\n\n" + "Set all macros and settings accordingly."}, + + { "setInterruptSafety", (PyCFunction) setInterruptSafety, + METH_VARARGS|METH_KEYWORDS, + "setInterruptSafety(on=True) -- Set if various signals get intercepted.\n\n" + "By default, librpm will trap various unix signals (like SIGINT and\n" + "SIGTERM), in order to avoid process exit while locks are held or\n" + "a transaction is being performed.\n\n" + "If this is not the desired behaviour it's recommended to call this\n" + "once only at process startup because currently signal handlers will\n" + "not be retroactively applied if a database is open." + }, { NULL } } ; -/* -* Force clean up of open iterators and dbs on exit. -*/ -static void rpm_exithook(void) -{ - rpmdbCheckTerminate(1); -} - -static char rpm__doc__[] = -""; +static char rpm__doc__[] = ""; /* * Add rpm tag dictionaries to the module @@ -205,7 +243,6 @@ static void addRpmTags(PyObject *module) Py_DECREF(pyname); } PyModule_AddObject(module, "tagnames", dict); - rpmtdFreeData(names); rpmtdFree(names); } @@ -215,14 +252,18 @@ static void addRpmTags(PyObject *module) static int prepareInitModule(void) { if (PyType_Ready(&hdr_Type) < 0) return 0; + if (PyType_Ready(&rpmarchive_Type) < 0) return 0; if (PyType_Ready(&rpmds_Type) < 0) return 0; if (PyType_Ready(&rpmfd_Type) < 0) return 0; if (PyType_Ready(&rpmfi_Type) < 0) return 0; + if (PyType_Ready(&rpmfile_Type) < 0) return 0; + if (PyType_Ready(&rpmfiles_Type) < 0) return 0; if (PyType_Ready(&rpmKeyring_Type) < 0) return 0; if (PyType_Ready(&rpmmi_Type) < 0) return 0; if (PyType_Ready(&rpmii_Type) < 0) return 0; if (PyType_Ready(&rpmProblem_Type) < 0) return 0; if (PyType_Ready(&rpmPubkey_Type) < 0) return 0; + if (PyType_Ready(&rpmstrPool_Type) < 0) return 0; #if 0 if (PyType_Ready(&rpmtd_Type) < 0) return 0; #endif @@ -287,14 +328,9 @@ static int initModule(PyObject *m) { PyObject * d; - /* - * treat error to register rpm cleanup hook as fatal, tracebacks - * can and will leave stale locks around if we can't clean up - */ - if (Py_AtExit(rpm_exithook) == -1) - return 0; - - rpmReadConfigFiles(NULL, NULL); + /* failure to initialize rpm (crypto and all) is rather fatal too... */ + if (rpmReadConfigFiles(NULL, NULL) == -1) + return 0; d = PyModule_GetDict(m); @@ -305,6 +341,9 @@ static int initModule(PyObject *m) Py_INCREF(&hdr_Type); PyModule_AddObject(m, "hdr", (PyObject *) &hdr_Type); + Py_INCREF(&rpmarchive_Type); + PyModule_AddObject(m, "archive", (PyObject *) &rpmarchive_Type); + Py_INCREF(&rpmds_Type); PyModule_AddObject(m, "ds", (PyObject *) &rpmds_Type); @@ -314,6 +353,12 @@ static int initModule(PyObject *m) Py_INCREF(&rpmfi_Type); PyModule_AddObject(m, "fi", (PyObject *) &rpmfi_Type); + Py_INCREF(&rpmfile_Type); + PyModule_AddObject(m, "file", (PyObject *) &rpmfile_Type); + + Py_INCREF(&rpmfiles_Type); + PyModule_AddObject(m, "files", (PyObject *) &rpmfiles_Type); + Py_INCREF(&rpmKeyring_Type); PyModule_AddObject(m, "keyring", (PyObject *) &rpmKeyring_Type); @@ -329,6 +374,9 @@ static int initModule(PyObject *m) Py_INCREF(&rpmPubkey_Type); PyModule_AddObject(m, "pubkey", (PyObject *) &rpmPubkey_Type); + Py_INCREF(&rpmstrPool_Type); + PyModule_AddObject(m, "strpool", (PyObject *) &rpmstrPool_Type); + #if 0 Py_INCREF(&rpmtd_Type); PyModule_AddObject(m, "td", (PyObject *) &rpmtd_Type); @@ -344,6 +392,9 @@ static int initModule(PyObject *m) PyModule_AddStringConstant(m, "__version__", RPMVERSION); + PyModule_AddObject(m, "header_magic", + PyBytes_FromStringAndSize((const char *)rpm_header_magic, 8)); + #define REGISTER_ENUM(val) PyModule_AddIntConstant(m, #val, val) REGISTER_ENUM(RPMTAG_NOT_FOUND); @@ -362,12 +413,15 @@ static int initModule(PyObject *m) REGISTER_ENUM(RPMFILE_CONFIG); REGISTER_ENUM(RPMFILE_DOC); + REGISTER_ENUM(RPMFILE_ICON); REGISTER_ENUM(RPMFILE_MISSINGOK); REGISTER_ENUM(RPMFILE_NOREPLACE); + REGISTER_ENUM(RPMFILE_SPECFILE); REGISTER_ENUM(RPMFILE_GHOST); REGISTER_ENUM(RPMFILE_LICENSE); REGISTER_ENUM(RPMFILE_README); REGISTER_ENUM(RPMFILE_PUBKEY); + REGISTER_ENUM(RPMFILE_ARTIFACT); REGISTER_ENUM(RPMDEP_SENSE_REQUIRES); REGISTER_ENUM(RPMDEP_SENSE_CONFLICTS); @@ -395,6 +449,7 @@ static int initModule(PyObject *m) REGISTER_ENUM(RPMSENSE_KEYRING); REGISTER_ENUM(RPMSENSE_STRONG); REGISTER_ENUM(RPMSENSE_CONFIG); + REGISTER_ENUM(RPMSENSE_MISSINGOK); REGISTER_ENUM(RPMTRANS_FLAG_TEST); REGISTER_ENUM(RPMTRANS_FLAG_BUILD_PROBS); @@ -403,8 +458,10 @@ static int initModule(PyObject *m) REGISTER_ENUM(RPMTRANS_FLAG_NOTRIGGERS); REGISTER_ENUM(RPMTRANS_FLAG_NODOCS); REGISTER_ENUM(RPMTRANS_FLAG_ALLFILES); + REGISTER_ENUM(RPMTRANS_FLAG_NOPLUGINS); REGISTER_ENUM(RPMTRANS_FLAG_KEEPOBSOLETE); REGISTER_ENUM(RPMTRANS_FLAG_NOCONTEXTS); + REGISTER_ENUM(RPMTRANS_FLAG_NOCAPS); REGISTER_ENUM(RPMTRANS_FLAG_REPACKAGE); REGISTER_ENUM(RPMTRANS_FLAG_REVERSE); REGISTER_ENUM(RPMTRANS_FLAG_NOPRE); @@ -415,11 +472,14 @@ static int initModule(PyObject *m) REGISTER_ENUM(RPMTRANS_FLAG_NOPREUN); REGISTER_ENUM(RPMTRANS_FLAG_NOPOSTUN); REGISTER_ENUM(RPMTRANS_FLAG_NOTRIGGERPOSTUN); + REGISTER_ENUM(RPMTRANS_FLAG_NOPRETRANS); + REGISTER_ENUM(RPMTRANS_FLAG_NOPOSTTRANS); REGISTER_ENUM(RPMTRANS_FLAG_NOMD5); REGISTER_ENUM(RPMTRANS_FLAG_NOFILEDIGEST); REGISTER_ENUM(RPMTRANS_FLAG_NOSUGGEST); REGISTER_ENUM(RPMTRANS_FLAG_ADDINDEPS); REGISTER_ENUM(RPMTRANS_FLAG_NOCONFIGS); + REGISTER_ENUM(RPMTRANS_FLAG_DEPLOOPS); REGISTER_ENUM(RPMPROB_FILTER_IGNOREOS); REGISTER_ENUM(RPMPROB_FILTER_IGNOREARCH); @@ -451,6 +511,7 @@ static int initModule(PyObject *m) REGISTER_ENUM(RPMCALLBACK_SCRIPT_START); REGISTER_ENUM(RPMCALLBACK_SCRIPT_STOP); REGISTER_ENUM(RPMCALLBACK_INST_STOP); + REGISTER_ENUM(RPMCALLBACK_ELEM_PROGRESS); REGISTER_ENUM(RPMPROB_BADARCH); REGISTER_ENUM(RPMPROB_BADOS); @@ -486,10 +547,10 @@ static int initModule(PyObject *m) REGISTER_ENUM(RPMVSF_NOHDRCHK); REGISTER_ENUM(RPMVSF_NEEDPAYLOAD); REGISTER_ENUM(RPMVSF_NOSHA1HEADER); - REGISTER_ENUM(RPMVSF_NOMD5HEADER); + REGISTER_ENUM(RPMVSF_NOSHA256HEADER); REGISTER_ENUM(RPMVSF_NODSAHEADER); REGISTER_ENUM(RPMVSF_NORSAHEADER); - REGISTER_ENUM(RPMVSF_NOSHA1); + REGISTER_ENUM(RPMVSF_NOPAYLOAD); REGISTER_ENUM(RPMVSF_NOMD5); REGISTER_ENUM(RPMVSF_NODSA); REGISTER_ENUM(RPMVSF_NORSA); @@ -521,6 +582,20 @@ static int initModule(PyObject *m) REGISTER_ENUM(HEADERCONV_COMPRESSFILELIST); REGISTER_ENUM(HEADERCONV_RETROFIT_V3); + REGISTER_ENUM(RPMVERIFY_NONE); + REGISTER_ENUM(RPMVERIFY_FILEDIGEST); + REGISTER_ENUM(RPMVERIFY_FILESIZE); + REGISTER_ENUM(RPMVERIFY_LINKTO); + REGISTER_ENUM(RPMVERIFY_USER); + REGISTER_ENUM(RPMVERIFY_GROUP); + REGISTER_ENUM(RPMVERIFY_MTIME); + REGISTER_ENUM(RPMVERIFY_MODE); + REGISTER_ENUM(RPMVERIFY_RDEV); + REGISTER_ENUM(RPMVERIFY_CAPS); + REGISTER_ENUM(RPMVERIFY_READLINKFAIL); + REGISTER_ENUM(RPMVERIFY_READFAIL); + REGISTER_ENUM(RPMVERIFY_LSTATFAIL); + return 1; } diff --git a/python/rpmps-py.c b/python/rpmps-py.c index 3ee9d4a9a..bdc899a60 100644 --- a/python/rpmps-py.c +++ b/python/rpmps-py.c @@ -72,7 +72,7 @@ static void rpmprob_dealloc(rpmProblemObject *s) PyTypeObject rpmProblem_Type = { PyVarObject_HEAD_INIT(&PyType_Type, 0) - PYTHON_MODULENAME".prob", /* tp_name */ + "rpm.prob", /* tp_name */ sizeof(rpmProblemObject), /* tp_basicsize */ 0, /* tp_itemsize */ /* methods */ diff --git a/python/rpmsmodule.c b/python/rpmsmodule.c index a8289b5f6..72465221d 100644 --- a/python/rpmsmodule.c +++ b/python/rpmsmodule.c @@ -5,33 +5,36 @@ static char rpms__doc__[] = ""; +static int parseSignArgs(PyObject * args, PyObject *kwds, + const char **path, struct rpmSignArgs *sargs) +{ + char * kwlist[] = { "path", "keyid", "hashalgo", NULL }; + + memset(sargs, 0, sizeof(*sargs)); + return PyArg_ParseTupleAndKeywords(args, kwds, "s|si", kwlist, + path, &sargs->keyid, &sargs->hashalgo); +} + static PyObject * addSign(PyObject * self, PyObject * args, PyObject *kwds) { const char *path = NULL; - const char *passPhrase = NULL; - char * kwlist[] = { "path", "passPhrase", "keyid", "hashalgo", NULL }; - struct rpmSignArgs sig, *sigp = NULL; + struct rpmSignArgs sargs; - memset(&sig, 0, sizeof(sig)); - if (!PyArg_ParseTupleAndKeywords(args, kwds, "ss|si", kwlist, - &path, &passPhrase, &sig.keyid, &sig.hashalgo)) + if (parseSignArgs(args, kwds, &path, &sargs)) return NULL; - if (sig.keyid || sig.hashalgo) - sigp = &sig; - - return PyBool_FromLong(rpmPkgSign(path, sigp, passPhrase) == 0); + return PyBool_FromLong(rpmPkgSign(path, &sargs) == 0); } static PyObject * delSign(PyObject * self, PyObject * args, PyObject *kwds) { const char *path = NULL; - char * kwlist[] = { "path", NULL }; + struct rpmSignArgs sargs; - if (!PyArg_ParseTupleAndKeywords(args, kwds, "s", kwlist, &path)) + if (parseSignArgs(args, kwds, &path, &sargs)) return NULL; - return PyBool_FromLong(rpmPkgDelSign(path) == 0); + return PyBool_FromLong(rpmPkgDelSign(path, &sargs) == 0); } /* diff --git a/python/rpmstrpool-py.c b/python/rpmstrpool-py.c new file mode 100644 index 000000000..356bd1de5 --- /dev/null +++ b/python/rpmstrpool-py.c @@ -0,0 +1,156 @@ +#include "rpmsystem-py.h" +#include <rpm/rpmstrpool.h> +#include "rpmstrpool-py.h" + +struct rpmstrPoolObject_s { + PyObject_HEAD + PyObject *md_dict; + rpmstrPool pool; +}; + +static char strpool_doc[] = ""; + +static void strpool_dealloc(rpmstrPoolObject *s) +{ + s->pool = rpmstrPoolFree(s->pool); + Py_TYPE(s)->tp_free((PyObject *)s); +} + +static PyObject *strpool_new(PyTypeObject *subtype, + PyObject *args, PyObject *kwds) +{ + return rpmstrPool_Wrap(subtype, NULL); +} + +static PyObject *strpool_str2id(rpmstrPoolObject *s, + PyObject *args, PyObject *kwds) +{ + char * kwlist[] = { "str", "create", NULL }; + const char *str = NULL; + int create = 1; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "s|i", kwlist, &str, &create)) + return NULL; + + return PyLong_FromLong(rpmstrPoolId(s->pool, str, create)); +} + +static PyObject *strpool_id2str(rpmstrPoolObject *s, PyObject *item) +{ + PyObject *ret = NULL; + rpmsid id = 0; + + if (PyArg_Parse(item, "I", &id)) { + const char *str = rpmstrPoolStr(s->pool, id); + + if (str) + ret = PyBytes_FromString(str); + else + PyErr_SetObject(PyExc_KeyError, item); + } + return ret; +} + +static PyObject *strpool_freeze(rpmstrPoolObject *s, + PyObject *args, PyObject *kwds) +{ + char * kwlist[] = { "keephash", NULL }; + int keephash = 0; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|i", kwlist, &keephash)) + return NULL; + + rpmstrPoolFreeze(s->pool, keephash); + Py_RETURN_NONE; +} + +static PyObject *strpool_unfreeze(rpmstrPoolObject *s) +{ + rpmstrPoolUnfreeze(s->pool); + Py_RETURN_NONE; +} + +static Py_ssize_t strpool_length(rpmstrPoolObject *s) +{ + return rpmstrPoolNumStr(s->pool); +} + +static struct PyMethodDef strpool_methods[] = { + { "str2id", (PyCFunction)strpool_str2id, METH_VARARGS|METH_KEYWORDS, + NULL }, + { "id2str", (PyCFunction)strpool_id2str, METH_O, + NULL }, + { "freeze", (PyCFunction)strpool_freeze, METH_VARARGS|METH_KEYWORDS, + NULL }, + { "unfreeze", (PyCFunction)strpool_unfreeze, METH_NOARGS, + NULL }, + { NULL, NULL } +}; + +static PyMappingMethods strpool_as_mapping = { + (lenfunc) strpool_length, /* mp_length */ + (binaryfunc) strpool_id2str, /* mp_subscript */ + (objobjargproc) 0, /* mp_ass_subscript */ +}; + +PyTypeObject rpmstrPool_Type = { + PyVarObject_HEAD_INIT(&PyType_Type, 0) + "rpm.strpool", /* tp_name */ + sizeof(rpmstrPoolObject), /* tp_size */ + 0, /* tp_itemsize */ + (destructor) strpool_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + (getattrfunc)0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + &strpool_as_mapping, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + PyObject_GenericGetAttr, /* tp_getattro */ + PyObject_GenericSetAttr, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, /* tp_flags */ + strpool_doc, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + strpool_methods, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + strpool_new, /* tp_new */ + 0, /* tp_free */ + 0, /* tp_is_gc */ +}; + +PyObject * rpmstrPool_Wrap(PyTypeObject *subtype, rpmstrPool pool) +{ + rpmstrPoolObject *s = (rpmstrPoolObject *)subtype->tp_alloc(subtype, 0); + if (s == NULL) return NULL; + + /* permit referencing a pre-existing pool as well */ + s->pool = (pool != NULL) ? rpmstrPoolLink(pool) : rpmstrPoolCreate(); + + return (PyObject *) s; +} + +int poolFromPyObject(PyObject *item, rpmstrPool *pool) +{ + rpmstrPoolObject *p = NULL; + if (PyArg_Parse(item, "O!", &rpmstrPool_Type, &p)) + *pool = p->pool; + return (p != NULL); +} diff --git a/python/rpmstrpool-py.h b/python/rpmstrpool-py.h new file mode 100644 index 000000000..b91c8f642 --- /dev/null +++ b/python/rpmstrpool-py.h @@ -0,0 +1,14 @@ +#ifndef H_RPMSTRPOOL_PY +#define H_RPMSTRPOOL_PY + +#include <rpm/rpmtypes.h> + +typedef struct rpmstrPoolObject_s rpmstrPoolObject; + +extern PyTypeObject rpmstrPool_Type; + +PyObject * rpmstrPool_Wrap(PyTypeObject *subtype, rpmstrPool pool); + +int poolFromPyObject(PyObject *item, rpmstrPool *pool); + +#endif diff --git a/python/rpmsystem-py.h b/python/rpmsystem-py.h index 30f74561e..c8423e3dc 100644 --- a/python/rpmsystem-py.h +++ b/python/rpmsystem-py.h @@ -5,11 +5,10 @@ #include <sys/types.h> #endif +#define PY_SSIZE_T_CLEAN #include <Python.h> #include <structmember.h> -#include "config.h" - #if ((PY_MAJOR_VERSION << 8) | (PY_MINOR_VERSION << 0)) < 0x0205 typedef ssize_t Py_ssize_t; typedef Py_ssize_t (*lenfunc)(PyObject *); diff --git a/python/rpmtd-py.c b/python/rpmtd-py.c index ed3a1455a..247c7502a 100644 --- a/python/rpmtd-py.c +++ b/python/rpmtd-py.c @@ -11,7 +11,7 @@ /* * Convert single tag data item to python object of suitable type */ -static PyObject * rpmtd_ItemAsPyobj(rpmtd td, rpmTagClass tclass) +PyObject * rpmtd_ItemAsPyobj(rpmtd td, rpmTagClass tclass) { PyObject *res = NULL; @@ -61,161 +61,3 @@ PyObject *rpmtd_AsPyobj(rpmtd td) } return res; } - -#if 0 -struct rpmtdObject_s { - PyObject_HEAD - PyObject *md_dict; - struct rpmtd_s td; -}; - -/* string format should never fail but do regular repr just in case it does */ -static PyObject *rpmtd_str(rpmtdObject *s) -{ - PyObject *res = NULL; - char *str = rpmtdFormat(&(s->td), RPMTD_FORMAT_STRING, NULL); - if (str) { - res = PyBytes_FromString(str); - free(str); - } else { - res = PyObject_Repr((PyObject *)s); - } - return res; -} - -static PyObject *rpmtd_iternext(rpmtdObject *s) -{ - PyObject *next = NULL; - - if (rpmtdNext(&(s->td)) >= 0) { - Py_INCREF(s); - next = (PyObject*) s; - } - return next; -} - -static PyObject *rpmtd_new(PyTypeObject * subtype, PyObject *args, PyObject *kwds) -{ - rpmtdObject *s = NULL; - Header h = NULL; - rpmTagVal tag; - int raw = 0; - int noext = 0; - headerGetFlags flags = (HEADERGET_EXT | HEADERGET_ALLOC); - char *kwlist[] = { "header", "tag", "raw", "noext", NULL }; - - if (!PyArg_ParseTupleAndKeywords(args, kwds, "O&O&|ii", kwlist, - hdrFromPyObject, &h, tagNumFromPyObject, &tag, - &raw, &noext)) - return NULL; - - if (raw) { - flags |= HEADERGET_RAW; - noext = 1; /* extensions with raw dont make sense */ - } - if (noext) flags &= ~HEADERGET_EXT; - - if ((s = (rpmtdObject *)subtype->tp_alloc(subtype, 0)) == NULL) - return NULL; - - headerGet(h, tag, &(s->td), flags); - - return (PyObject *) s; -} - -static void rpmtd_dealloc(rpmtdObject * s) -{ - rpmtdFreeData(&(s->td)); - Py_TYPE(s)->tp_free((PyObject *)s); -} - -static int rpmtd_length(rpmtdObject *s) -{ - return rpmtdCount(&(s->td)); -} - -static PyMappingMethods rpmtd_as_mapping = { - (lenfunc) rpmtd_length, /* mp_length */ -}; - -static PyMemberDef rpmtd_members[] = { - { "type", T_INT, offsetof(rpmtdObject, td.type), READONLY, NULL }, - { NULL } -}; - -static PyObject *rpmtd_get_tag(rpmtdObject *s, void *closure) -{ - return Py_BuildValue("i", rpmtdTag(&(s->td))); -} - -static int rpmtd_set_tag(rpmtdObject *s, PyObject *value, void *closure) -{ - rpmTagVal tag; - if (!tagNumFromPyObject(value, &tag)) return -1; - - if (!rpmtdSetTag(&(s->td), tag)) { - PyErr_SetString(PyExc_ValueError, "incompatible tag for data"); - return -1; - } - return 0; -} - -static PyGetSetDef rpmtd_getseters[] = { - { "tag", (getter)rpmtd_get_tag, (setter)rpmtd_set_tag, NULL }, - { NULL } -}; - -PyTypeObject rpmtd_Type = { - PyVarObject_HEAD_INIT(&PyType_Type, 0) - PYTHON_MODULENAME".td", /* tp_name */ - sizeof(rpmtdObject), /* tp_size */ - 0, /* tp_itemsize */ - (destructor) rpmtd_dealloc, /* tp_dealloc */ - 0, /* tp_print */ - (getattrfunc)0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_compare */ - 0, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - &rpmtd_as_mapping, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - (reprfunc)rpmtd_str, /* tp_str */ - PyObject_GenericGetAttr, /* tp_getattro */ - PyObject_GenericSetAttr, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, /* tp_flags */ - 0, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - PyObject_SelfIter, /* tp_iter */ - (iternextfunc)rpmtd_iternext, /* tp_iternext */ - 0, /* tp_methods */ - rpmtd_members, /* tp_members */ - rpmtd_getseters, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - 0, /* tp_init */ - 0, /* tp_alloc */ - rpmtd_new, /* tp_new */ - 0, /* tp_free */ - 0, /* tp_is_gc */ -}; - -int rpmtdFromPyObject(PyObject *obj, rpmtd *td) -{ - if (rpmtdObject_Check(obj)) { - *td = &(((rpmtdObject *)obj)->td); - return 1; - } else { - PyErr_SetString(PyExc_TypeError, PYTHON_MODULENAME".td type expected"); - return 0; - } -} -#endif diff --git a/python/rpmtd-py.h b/python/rpmtd-py.h index 4c95e89b4..c7ac4091c 100644 --- a/python/rpmtd-py.h +++ b/python/rpmtd-py.h @@ -7,6 +7,7 @@ extern PyTypeObject rpmtd_Type; #define rpmtdObject_Check(v) ((v)->ob_type == &rpmtd_Type) +PyObject * rpmtd_ItemAsPyobj(rpmtd td, rpmTagClass tclass); PyObject * rpmtd_AsPyobj(rpmtd td); int rpmtdFromPyObject(PyObject *obj, rpmtd *td); diff --git a/python/rpmte-py.c b/python/rpmte-py.c index 6b338260f..6936e757e 100644 --- a/python/rpmte-py.c +++ b/python/rpmte-py.c @@ -3,6 +3,7 @@ #include "header-py.h" /* XXX tagNumFromPyObject */ #include "rpmds-py.h" #include "rpmfi-py.h" +#include "rpmfiles-py.h" #include "rpmte-py.h" #include "rpmps-py.h" @@ -35,8 +36,9 @@ * - te.Key() Return the associated opaque key, i.e. 2nd arg ts.addInstall(). * - te.DS(tag) Return package dependency set. * @param tag 'Providename', 'Requirename', 'Obsoletename', 'Conflictname' - * - te.FI(tag) Return package file info set. + * - te.FI(tag) Return package file info set iterator (deprecated). * @param tag 'Basenames' + * - te.Files() Return package file info set. */ struct rpmteObject_s { @@ -182,6 +184,8 @@ rpmte_FI(rpmteObject * s, PyObject * args, PyObject * kwds) { rpmfi fi; + DEPRECATED_METHOD("use .Files() instead"); + fi = rpmteFI(s->te); if (fi == NULL) { Py_RETURN_NONE; @@ -189,57 +193,60 @@ rpmte_FI(rpmteObject * s, PyObject * args, PyObject * kwds) return rpmfi_Wrap(&rpmfi_Type, rpmfiLink(fi)); } +static PyObject * +rpmte_Files(rpmteObject * s, PyObject * args, PyObject * kwds) +{ + rpmfiles files = rpmteFiles(s->te); + if (files == NULL) { + Py_RETURN_NONE; + } + return rpmfiles_Wrap(&rpmfiles_Type, files); +} static struct PyMethodDef rpmte_methods[] = { {"Type", (PyCFunction)rpmte_TEType, METH_NOARGS, -"te.Type() -> Type\n\ -- Return element type ("PYTHON_MODULENAME".TR_ADDED | "PYTHON_MODULENAME".TR_REMOVED).\n" }, + "te.Type() -- Return element type (rpm.TR_ADDED | rpm.TR_REMOVED).\n" }, {"N", (PyCFunction)rpmte_N, METH_NOARGS, -"te.N() -> N\n\ -- Return element name.\n" }, + "te.N() -- Return element name.\n" }, {"E", (PyCFunction)rpmte_E, METH_NOARGS, -"te.E() -> E\n\ -- Return element epoch.\n" }, + "te.E() -- Return element epoch.\n" }, {"V", (PyCFunction)rpmte_V, METH_NOARGS, -"te.V() -> V\n\ -- Return element version.\n" }, + "te.V() -- Return element version.\n" }, {"R", (PyCFunction)rpmte_R, METH_NOARGS, -"te.R() -> R\n\ -- Return element release.\n" }, + "te.R() -- Return element release.\n" }, {"A", (PyCFunction)rpmte_A, METH_NOARGS, -"te.A() -> A\n\ -- Return element arch.\n" }, + "te.A() -- Return element arch.\n" }, {"O", (PyCFunction)rpmte_O, METH_NOARGS, -"te.O() -> O\n\ -- Return element os.\n" }, + "te.O() -- Return element os.\n" }, {"NEVR", (PyCFunction)rpmte_NEVR, METH_NOARGS, -"te.NEVR() -> NEVR\n\ -- Return element name-[epoch:]version-release.\n" }, + "te.NEVR() -- Return element name-[epoch:]version-release.\n" }, {"NEVRA", (PyCFunction)rpmte_NEVRA, METH_NOARGS, -"te.NEVRA() -> NEVRA\n\ -- Return element name-[epoch:]version-release.arch\n" }, + "te.NEVRA() -- Return element name-[epoch:]version-release.arch\n" }, {"Color",(PyCFunction)rpmte_Color, METH_NOARGS, - NULL}, + "te.Color() -- Return package color bits."}, {"PkgFileSize",(PyCFunction)rpmte_PkgFileSize, METH_NOARGS, - NULL}, + "te.PkgFileSize() -- Return no. of bytes in package file (approx)."}, {"Parent", (PyCFunction)rpmte_Parent, METH_NOARGS, - NULL}, + "te.Parent() -- Return the parent element index."}, {"Problems",(PyCFunction)rpmte_Problems, METH_NOARGS, - NULL}, + "te.Problems() -- Return problems associated with this element."}, /* {"DependsOnKey",(PyCFunction)rpmte_DependsOnKey, METH_NOARGS, NULL}, */ {"DBOffset",(PyCFunction)rpmte_DBOffset, METH_NOARGS, - NULL}, + "te.DBOffset() -- Return the Package's database instance number.\n\nTR_REMOVED only"}, {"Failed", (PyCFunction)rpmte_Failed, METH_NOARGS, - NULL}, + "te.Failed() -- Return if there are any related errors."}, {"Key", (PyCFunction)rpmte_Key, METH_NOARGS, - NULL}, + "te.Key() -- Return the associated opaque key aka user data\n\ + as passed e.g. as data arg ts.addInstall()"}, {"DS", (PyCFunction)rpmte_DS, METH_VARARGS|METH_KEYWORDS, -"te.DS(TagN) -> DS\n\ -- Return the TagN dependency set (or None). TagN is one of\n\ - 'Providename', 'Requirename', 'Obsoletename', 'Conflictname'\n" }, +"te.DS(TagN) -- Return the TagN dependency set (or None).\n\ + TagN is one of 'Providename', 'Requirename', 'Obsoletename',\n\ + 'Conflictname', 'Triggername', 'Recommendname', 'Suggestname',\n\ + 'Supplementname', 'Enhancename'" }, {"FI", (PyCFunction)rpmte_FI, METH_VARARGS|METH_KEYWORDS, -"te.FI(TagN) -> FI\n\ -- Return the TagN dependency set (or None). TagN must be 'Basenames'.\n" }, +"te.FI(TagN) -- Return file info iterator of element.\n\n DEPRECATED! Use .Files() instead.\n" }, + {"Files", (PyCFunction)rpmte_Files, METH_NOARGS, +"te.Files() -- Return file info set of element.\n" }, {NULL, NULL} /* sentinel */ }; @@ -250,7 +257,7 @@ static char rpmte_doc[] = PyTypeObject rpmte_Type = { PyVarObject_HEAD_INIT(&PyType_Type, 0) - PYTHON_MODULENAME".te", /* tp_name */ + "rpm.te", /* tp_name */ sizeof(rpmteObject), /* tp_size */ 0, /* tp_itemsize */ (destructor)0, /* tp_dealloc */ diff --git a/python/rpmts-py.c b/python/rpmts-py.c index 1072f354e..d56a09c22 100644 --- a/python/rpmts-py.c +++ b/python/rpmts-py.c @@ -96,23 +96,26 @@ * @return None * * - ts.setFlags(transFlags) Set transaction set flags. - * @param transFlags - bit(s) to controll transaction operations. The + * @param transFlags - bit(s) to control transaction operations. The * following values can be logically OR'ed together: * - rpm.RPMTRANS_FLAG_TEST - test mode, do not modify the RPM * database, change any files, or run any package scripts * - rpm.RPMTRANS_FLAG_BUILD_PROBS - only build a list of * problems encountered when attempting to run this transaction * set - * - rpm.RPMTRANS_FLAG_NOSCRIPTS - do not execute package scripts * - rpm.RPMTRANS_FLAG_JUSTDB - only make changes to the rpm * database, do not modify files. + * - rpm.RPMTRANS_FLAG_NOSCRIPTS - do not execute package scripts * - rpm.RPMTRANS_FLAG_NOTRIGGERS - do not run trigger scripts + * - rpm.RPMTRANS_FLAG_NO* - disable specific scripts and triggers * - rpm.RPMTRANS_FLAG_NODOCS - do not install files marked as %doc + * - rpm.RPMTRANS_FLAG_NOPLUGINS - do not run plugins + * - rpm.RPMTRANS_FLAG_NOFILEDIGEST - disable checking checksums * - rpm.RPMTRANS_FLAG_ALLFILES - create all files, even if a * file is marked %config(missingok) and an upgrade is * being performed. - * - rpm.RPMTRANS_FLAG_KEEPOBSOLETE - do not remove obsoleted - * packages. + * - rpm.RPMTRANS_FLAG_NOCONFIGS - skip config files + * - rpm.RPMTRANS_FLAG_DEPLOOPS - enable debugging for dependency loops * @return previous transFlags * * - ts.setProbFilter(ignoreSet) Set transaction set problem filter. @@ -164,7 +167,6 @@ static void die(PyObject *cb) } fprintf(stderr, "FATAL ERROR: python callback %s failed, aborting!\n", pyfn ? pyfn : "???"); - rpmdbCheckTerminate(1); exit(EXIT_FAILURE); } @@ -188,6 +190,24 @@ rpmts_AddInstall(rpmtsObject * s, PyObject * args) } static PyObject * +rpmts_AddReinstall(rpmtsObject * s, PyObject * args) +{ + Header h = NULL; + PyObject * key; + int rc; + + if (!PyArg_ParseTuple(args, "O&O:AddReinstall", + hdrFromPyObject, &h, &key)) + return NULL; + + rc = rpmtsAddReinstallElement(s->ts, h, key); + if (key && rc == 0) { + PyList_Append(s->keyList, key); + } + return PyBool_FromLong((rc == 0)); +} + +static PyObject * rpmts_AddErase(rpmtsObject * s, PyObject * args) { Header h; @@ -363,7 +383,6 @@ rpmts_HdrFromFdno(rpmtsObject * s, PyObject *arg) if (rpmrc == RPMRC_OK) { ho = hdr_Wrap(&hdr_Type, h); - h = headerFree(h); /* ref held by python object */ } else { Py_INCREF(Py_None); ho = Py_None; @@ -440,7 +459,7 @@ static PyObject *rpmts_setKeyring(rpmtsObject *s, PyObject *arg) if (arg == Py_None || rpmKeyringFromPyObject(arg, &keyring)) { return PyBool_FromLong(rpmtsSetKeyring(s->ts, keyring) == 0); } else { - PyErr_SetString(PyExc_TypeError, PYTHON_MODULENAME".keyring or None expected"); + PyErr_SetString(PyExc_TypeError, "rpm.keyring or None expected"); return NULL; } } @@ -609,6 +628,10 @@ rpmts_Match(rpmtsObject * s, PyObject * args, PyObject * kwds) lkey = PyInt_AsLong(Key); key = (char *)&lkey; len = sizeof(lkey); + } else if (PyLong_Check(Key)) { + lkey = PyLong_AsLong(Key); + key = (char *)&lkey; + len = sizeof(lkey); } else if (utf8FromPyObject(Key, &str)) { key = PyBytes_AsString(str); len = PyBytes_Size(str); @@ -669,13 +692,55 @@ exit: static struct PyMethodDef rpmts_methods[] = { {"addInstall", (PyCFunction) rpmts_AddInstall, METH_VARARGS, - NULL }, + "ts.addInstall(hdr, data, mode) -- Add transaction element(s)\n" + "representing an installation or update of a package.\n\n" + "Args:\n" + " hdr : the header to be added\n" + " data : user data that will be passed to the transaction callback\n\t\tduring transaction execution\n" + " mode : optional argument that specifies if this package should be\n\t\tinstalled ('i'), upgraded ('u')"}, + {"addReinstall", (PyCFunction) rpmts_AddReinstall, METH_VARARGS, + "ts.addReinstall(hdr, data) -- Adds transaction elements\nrepresenting a reinstall of an already installed package.\n\nSee addInstall for details."}, {"addErase", (PyCFunction) rpmts_AddErase, METH_VARARGS|METH_KEYWORDS, - NULL }, + "addErase(name) -- Add a transaction element representing an erase\nof an installed package.\n\n" + " name: the package name to be erased"}, {"check", (PyCFunction) rpmts_Check, METH_VARARGS|METH_KEYWORDS, - NULL }, + "ts.check( )-- Perform a dependency check on the transaction set.\n" + " After headers have been added to a transaction set,\n" + " a dependencycheck can be performed to make sure that\n" + " all package dependencies are satisfied.\n" + "Return None If there are no unresolved dependencies\n" + " Otherwise a list of complex tuples is returned,\n" + " one tuple per unresolved dependency, with\n" + "The format of the dependency tuple is:\n" + " ((packageName, packageVersion, packageRelease),\n" + " (reqName, reqVersion),\n" + " needsFlags,\n" + " suggestedPackage,\n" + " sense)\n" + " packageName, packageVersion, packageRelease are the name,\n" + " version, and release of the package that has the unresolved\n" + " dependency or conflict.\n" + " The reqName and reqVersion are the name and version of the\n" + " requirement or conflict.\n" + " The needsFlags is a bitfield that describes the versioned\n" + " nature of a requirement or conflict. The constants\n" + " rpm.RPMSENSE_LESS, rpm.RPMSENSE_GREATER, and\n" + " rpm.RPMSENSE_EQUAL can be logical ANDed with the needsFlags\n" + " to get versioned dependency information.\n" + " suggestedPackage is a tuple if the dependency check was aware\n" + " of a package that solves this dependency problem when the\n" + " dependency check was run. Packages that are added to the\n" + " transaction set as \"available\" are examined during the\n" + " dependency check as possible dependency solvers. The tuple\n" + " contains two values, (header, suggestedName). These are set to\n" + " the header of the suggested package and its name, respectively.\n" + " If there is no known package to solve the dependency problem,\n" + " suggestedPackage is None.\n" + " The constants rpm.RPMDEP_SENSE_CONFLICTS and\n" + " rpm.RPMDEP_SENSE_REQUIRES are set to show a dependency as a\n" + " requirement or a conflict.\n"}, {"order", (PyCFunction) rpmts_Order, METH_NOARGS, - NULL }, + "ts.order() Do a topological sort of added element relations." }, {"problems", (PyCFunction) rpmts_Problems, METH_NOARGS, "ts.problems() -> ps\n\ - Return current problem set.\n" }, @@ -684,18 +749,18 @@ static struct PyMethodDef rpmts_methods[] = { - Run a transaction set, returning list of problems found.\n\ Note: The callback may not be None.\n" }, {"clean", (PyCFunction) rpmts_Clean, METH_NOARGS, - NULL }, + "ts.clean()-- Free memory needed only for dependency checks\nand ordering. Should not be needed in normal operation." }, {"clear", (PyCFunction) rpmts_Clear, METH_NOARGS, "ts.clear() -> None\n\ Remove all elements from the transaction set\n" }, {"openDB", (PyCFunction) rpmts_OpenDB, METH_NOARGS, -"ts.openDB() -> None\n\ -- Open the default transaction rpmdb.\n\ - Note: The transaction rpmdb is lazily opened, so ts.openDB() is seldom needed.\n" }, +"ts.openDB() -> None -- Open the default transaction rpmdb.\n\n\ + Note: The transaction rpmdb is lazily opened,\n so ts.openDB() is seldom needed.\n" }, {"closeDB", (PyCFunction) rpmts_CloseDB, METH_NOARGS, "ts.closeDB() -> None\n\ - Close the default transaction rpmdb.\n\ - Note: ts.closeDB() disables lazy opens, and should hardly ever be used.\n" }, + Note: ts.closeDB() disables lazy opens,\n\ + and should hardly ever be used.\n" }, {"initDB", (PyCFunction) rpmts_InitDB, METH_NOARGS, "ts.initDB() -> None\n\ - Initialize the default transaction rpmdb.\n\ @@ -710,15 +775,21 @@ Remove all elements from the transaction set\n" }, "ts.hdrFromFdno(fdno) -> hdr\n\ - Read a package header from a file descriptor.\n" }, {"hdrCheck", (PyCFunction) rpmts_HdrCheck, METH_O, - NULL }, + "ts.hdrCheck(hdrblob) -- Check header consistency,\nperforming headerGetEntry() the hard way.\n\n" + "Sanity checks on the header are performed while looking for a\n" + "header-only digest or signature to verify the blob. If found,\n" + "the digest or signature is verified.\n\n" + "\thdrblob : unloaded header blob\n" + "Return tuple (int status, message string)"}, {"pgpPrtPkts", (PyCFunction) rpmts_PgpPrtPkts, METH_VARARGS|METH_KEYWORDS, - NULL }, + "pgpPrtPkts(octets) -- Print/parse a OpenPGP packet(s).\n\nReturn 0 on success." }, {"pgpImportPubkey", (PyCFunction) rpmts_PgpImportPubkey, METH_VARARGS|METH_KEYWORDS, - NULL }, + "pgpImportPubkey(pubkey) -- Import public key packet." }, {"getKeyring", (PyCFunction) rpmts_getKeyring, METH_VARARGS|METH_KEYWORDS, - NULL }, + "ts.getKeyring(autoload=False) -- Return key ring object." }, {"setKeyring", (PyCFunction) rpmts_setKeyring, METH_O, - NULL }, + "ts.setKeyring(keyring) -- Set key ring used for checking signatures\n\n" + "Pass None for an empty key ring." }, {"dbMatch", (PyCFunction) rpmts_Match, METH_VARARGS|METH_KEYWORDS, "ts.dbMatch([TagN, [key]]) -> mi\n\ - Create a match iterator for the default transaction rpmdb.\n" }, @@ -856,13 +927,38 @@ static PyObject *rpmts_get_vsflags(rpmtsObject *s, void *closure) } static char rpmts_doc[] = -""; + "A python rpm.ts object represents an RPM transaction set.\n" + "\n" + "The transaction set is the workhorse of RPM. It performs the\n" + "installation and upgrade of packages. The rpm.ts object is\n" + "instantiated by the TransactionSet function in the rpm module.\n" + "\n" + "The TransactionSet function takes two optional arguments. The first\n" + "argument is the root path. The second is the verify signature disable\n" + "flags, a set of the following bits:\n" + "\n" + "- rpm.RPMVSF_NOHDRCHK if set, don't check rpmdb headers\n" + "- rpm.RPMVSF_NEEDPAYLOAD if not set, check header+payload\n" + " (if possible)\n" + "- rpm.RPMVSF_NOSHA1HEADER if set, don't check header SHA1 digest\n" + "- rpm.RPMVSF_NODSAHEADER if set, don't check header DSA signature\n" + "- rpm.RPMVSF_NOMD5 if set, don't check header+payload MD5 digest\n" + "- rpm.RPMVSF_NODSA if set, don't check header+payload DSA signature\n" + "- rpm.RPMVSF_NORSA if set, don't check header+payload RSA signature\n" + "\n" + "For convenience, there are the following masks:\n" + "- rpm._RPMVSF_NODIGESTS if set, don't check digest(s).\n" + "- rpm._RPMVSF_NOSIGNATURES if set, don't check signature(s).\n\n" + "The transaction set offers an read only iterable interface for the\ntransaction elements added by the .addInstall(), .addErase() and\n.addReinstall() methods."; static PyGetSetDef rpmts_getseters[] = { /* only provide a setter until we have rpmfd wrappings */ - {"scriptFd", NULL, (setter)rpmts_set_scriptFd, NULL }, - {"tid", (getter)rpmts_get_tid, NULL, NULL }, - {"rootDir", (getter)rpmts_get_rootDir, NULL, NULL }, + {"scriptFd", NULL, (setter)rpmts_set_scriptFd, + "write only, file descriptor the output of script gets written to." }, + {"tid", (getter)rpmts_get_tid, NULL, + "read only, current transaction id, i.e. transaction time stamp."}, + {"rootDir", (getter)rpmts_get_rootDir, NULL, + "read only, directory rpm treats as root of the file system." }, {"_color", (getter)rpmts_get_color, (setter)rpmts_set_color, NULL}, {"_prefcolor", (getter)rpmts_get_prefcolor, (setter)rpmts_set_prefcolor, NULL}, {"_flags", (getter)rpmts_get_flags, (setter)rpmts_set_flags, NULL}, @@ -872,7 +968,7 @@ static PyGetSetDef rpmts_getseters[] = { PyTypeObject rpmts_Type = { PyVarObject_HEAD_INIT(&PyType_Type, 0) - PYTHON_MODULENAME".ts", /* tp_name */ + "rpm.ts", /* tp_name */ sizeof(rpmtsObject), /* tp_size */ 0, /* tp_itemsize */ (destructor) rpmts_dealloc, /* tp_dealloc */ diff --git a/python/setup.py.in b/python/setup.py.in index 14be973a3..dd56a47a9 100644 --- a/python/setup.py.in +++ b/python/setup.py.in @@ -2,7 +2,7 @@ from distutils.core import setup, Extension import subprocess -from glob import glob +import os def pkgconfig(what): out = [] @@ -12,37 +12,50 @@ def pkgconfig(what): out.append(token[2:]) return out -def mksources(names): - srcs = [] - for n in names: - srcs.extend(glob('%s*.c' % n)) - return srcs +cflags = ['-std=c99', '-Wno-strict-aliasing'] +additional_link_args = [] -cflags = ['-std=c99'] +# See if we're building in-tree +if os.access('Makefile.am', os.F_OK): + cflags.append('-I../include') + additional_link_args.extend(['-Wl,-L../rpmio/.libs', + '-Wl,-L../lib/.libs', + '-Wl,-L../build/.libs', + '-Wl,-L../sign/.libs']) + os.environ['PKG_CONFIG_PATH'] = '..' -rpmmod = Extension('@PYTHON_MODULENAME@._rpm', - sources = mksources([ - 'header', 'rpmds', 'rpmfd', 'rpmfi', 'rpmii', - 'rpmkeyring', 'rpmmacro', 'rpmmi', 'rpmps', - 'rpmtd', 'rpmte', 'rpmts', 'rpmmodule', - ]), + +rpmmod = Extension('rpm._rpm', + sources = [ 'header-py.c', 'rpmds-py.c', 'rpmfd-py.c', + 'rpmfi-py.c', 'rpmii-py.c', 'rpmkeyring-py.c', + 'rpmmacro-py.c', 'rpmmi-py.c', 'rpmps-py.c', + 'rpmstrpool-py.c', 'rpmfiles-py.c', + 'rpmarchive-py.c', 'rpmtd-py.c', + 'rpmte-py.c', 'rpmts-py.c', 'rpmmodule.c', + ], include_dirs = pkgconfig('--cflags'), - libraries = pkgconfig('--libs'), - extra_compile_args = cflags + library_dirs = pkgconfig('--libs-only-L'), + libraries = pkgconfig('--libs-only-l'), + extra_compile_args = cflags, + extra_link_args = additional_link_args ) -rpmbuild_mod = Extension('@PYTHON_MODULENAME@._rpmb', - sources = mksources(['rpmbmodule', 'spec']), +rpmbuild_mod = Extension('rpm._rpmb', + sources = ['rpmbmodule.c', 'spec-py.c'], include_dirs = pkgconfig('--cflags'), - libraries = pkgconfig('--libs') + ['rpmbuild'], - extra_compile_args = cflags + library_dirs = pkgconfig('--libs-only-L'), + libraries = pkgconfig('--libs-only-l') + ['rpmbuild'], + extra_compile_args = cflags, + extra_link_args = additional_link_args ) -rpmsign_mod = Extension('@PYTHON_MODULENAME@._rpms', - sources = mksources(['rpmbmodule']), +rpmsign_mod = Extension('rpm._rpms', + sources = ['rpmsmodule.c'], include_dirs = pkgconfig('--cflags'), - libraries = pkgconfig('--libs') + ['rpmsign'], - extra_compile_args = cflags + library_dirs = pkgconfig('--libs-only-L'), + libraries = pkgconfig('--libs-only-l') + ['rpmsign'], + extra_compile_args = cflags, + extra_link_args = additional_link_args ) setup(name='@PACKAGE_NAME@', diff --git a/python/spec-py.c b/python/spec-py.c index 82245200e..47c17400f 100644 --- a/python/spec-py.c +++ b/python/spec-py.c @@ -19,7 +19,7 @@ * For example * \code * import rpm - * rpm.addMacro("_topdir","/path/to/topdir") + * rpm.rpmPushMacro("_topdir","/path/to/topdir") * s=rpm.spec("foo.spec") * print s.prep() * \endcode @@ -31,10 +31,10 @@ /* Header objects are in another module, some hoop jumping required... */ static PyObject *makeHeader(Header h) { - PyObject *rpmmod = PyImport_ImportModuleNoBlock(PYTHON_MODULENAME); + PyObject *rpmmod = PyImport_ImportModuleNoBlock("rpm"); if (rpmmod == NULL) return NULL; - PyObject *ptr = CAPSULE_BUILD(h, PYTHON_MODULENAME"._C_Header"); + PyObject *ptr = CAPSULE_BUILD(h, "rpm._C_Header"); PyObject *hdr = PyObject_CallMethod(rpmmod, "hdr", "(O)", ptr); Py_XDECREF(ptr); Py_XDECREF(rpmmod); @@ -45,27 +45,63 @@ struct specPkgObject_s { PyObject_HEAD /*type specific fields */ rpmSpecPkg pkg; + specObject *source_spec; }; +static void specPkg_dealloc(specPkgObject * s) +{ + Py_DECREF(s->source_spec); +} + +static PyObject *pkgGetSection(rpmSpecPkg pkg, int section) +{ + char *sect = rpmSpecPkgGetSection(pkg, section); + if (sect != NULL) { + PyObject *ps = PyBytes_FromString(sect); + free(sect); + if (ps != NULL) + return ps; + } + Py_RETURN_NONE; +} + static char specPkg_doc[] = -""; +"Package data parsed from spec file."; static PyObject * specpkg_get_header(specPkgObject *s, void *closure) { return makeHeader(rpmSpecPkgHeader(s->pkg)); } +static PyObject * specpkg_get_fileFile(specPkgObject *s, void *closure) +{ + return pkgGetSection(s->pkg, RPMBUILD_FILE_FILE); +} + +static PyObject * specpkg_get_fileList(specPkgObject *s, void *closure) +{ + return pkgGetSection(s->pkg, RPMBUILD_FILE_LIST); +} + +static PyObject * specpkg_get_policyList(specPkgObject *s, void *closure) +{ + return pkgGetSection(s->pkg, RPMBUILD_POLICY); +} + static PyGetSetDef specpkg_getseters[] = { - { "header", (getter) specpkg_get_header, NULL, NULL }, - { NULL } /* sentinel */ + { "header", (getter) specpkg_get_header, NULL, NULL }, + { "fileFile", (getter) specpkg_get_fileFile, NULL, NULL }, + { "fileList", (getter) specpkg_get_fileList, NULL, NULL }, + { "policyList", (getter) specpkg_get_policyList, NULL, NULL }, + { NULL } /* sentinel */ }; PyTypeObject specPkg_Type = { PyVarObject_HEAD_INIT(&PyType_Type, 0) - PYTHON_MODULENAME".specpkg", /* tp_name */ + "rpm.specpkg", /* tp_name */ sizeof(specPkgObject), /* tp_size */ 0, /* tp_itemsize */ - 0, /* tp_dealloc */ + (destructor) specPkg_dealloc, /* tp_dealloc */ 0, /* tp_print */ 0, /* tp_getattr */ 0, /* tp_setattr */ @@ -127,6 +163,12 @@ static PyObject * getSection(rpmSpec spec, int section) Py_RETURN_NONE; } +static PyObject * +spec_get_parsed(specObject * s, void *closure) +{ + return getSection(s->spec, RPMBUILD_NONE); +} + static PyObject * spec_get_prep(specObject * s, void *closure) { @@ -144,6 +186,11 @@ static PyObject * spec_get_install(specObject * s, void *closure) return getSection(s->spec, RPMBUILD_INSTALL); } +static PyObject * spec_get_check(specObject * s, void *closure) +{ + return getSection(s->spec, RPMBUILD_CHECK); +} + static PyObject * spec_get_clean(specObject * s, void *closure) { return getSection(s->spec, RPMBUILD_CLEAN); @@ -192,7 +239,7 @@ static PyObject * spec_get_packages(specObject *s, void *closure) iter = rpmSpecPkgIterInit(s->spec); while ((pkg = rpmSpecPkgIterNext(iter)) != NULL) { - PyObject *po = specPkg_Wrap(&specPkg_Type, pkg); + PyObject *po = specPkg_Wrap(&specPkg_Type, pkg, s); if (!po) { rpmSpecPkgIterFree(iter); Py_DECREF(pkgList); @@ -214,9 +261,11 @@ static char spec_doc[] = "RPM Spec file object"; static PyGetSetDef spec_getseters[] = { {"sources", (getter) spec_get_sources, NULL, NULL }, + {"parsed", (getter) spec_get_parsed, NULL, NULL}, {"prep", (getter) spec_get_prep, NULL, NULL }, {"build", (getter) spec_get_build, NULL, NULL }, {"install", (getter) spec_get_install, NULL, NULL }, + {"check", (getter) spec_get_check, NULL, NULL }, {"clean", (getter) spec_get_clean, NULL, NULL }, {"packages", (getter) spec_get_packages, NULL, NULL }, {"sourceHeader", (getter) spec_get_source_header, NULL, NULL }, @@ -263,7 +312,7 @@ static struct PyMethodDef spec_methods[] = { PyTypeObject spec_Type = { PyVarObject_HEAD_INIT(&PyType_Type, 0) - PYTHON_MODULENAME".spec", /*tp_name*/ + "rpm.spec", /*tp_name*/ sizeof(specObject), /*tp_basicsize*/ 0, /*tp_itemsize*/ (destructor) spec_dealloc, /*tp_dealloc*/ @@ -314,12 +363,14 @@ spec_Wrap(PyTypeObject *subtype, rpmSpec spec) return (PyObject *) s; } -PyObject * specPkg_Wrap(PyTypeObject *subtype, rpmSpecPkg pkg) +PyObject * specPkg_Wrap(PyTypeObject *subtype, rpmSpecPkg pkg, specObject *source) { specPkgObject * s = (specPkgObject *)subtype->tp_alloc(subtype, 0); if (s == NULL) return NULL; s->pkg = pkg; + s->source_spec = source; + Py_INCREF(s->source_spec); return (PyObject *) s; } diff --git a/python/spec-py.h b/python/spec-py.h index 558fbf207..65b8dc3d7 100644 --- a/python/spec-py.h +++ b/python/spec-py.h @@ -13,6 +13,6 @@ extern PyTypeObject specPkg_Type; #define specPkgObject_Check(v) ((v)->ob_type == &specPkg_Type) PyObject * spec_Wrap(PyTypeObject *subtype, rpmSpec spec); -PyObject * specPkg_Wrap(PyTypeObject *subtype, rpmSpecPkg pkg); +PyObject * specPkg_Wrap(PyTypeObject *subtype, rpmSpecPkg pkg, specObject *source); #endif /* RPMPYTHON_SPEC */ |