Blame python/rpmts-py.c

2ff057
#include "rpmsystem-py.h"
2ff057
2ff057
#include <fcntl.h>
2ff057
2ff057
#include <rpm/rpmlib.h>	/* rpmReadPackageFile, headerCheck */
2ff057
#include <rpm/rpmtag.h>
2ff057
#include <rpm/rpmpgp.h>
2ff057
#include <rpm/rpmdb.h>
2ff057
#include <rpm/rpmbuild.h>
2ff057
2ff057
#include "header-py.h"
2ff057
#include "rpmds-py.h"	/* XXX for rpmdsNew */
2ff057
#include "rpmfd-py.h"
2ff057
#include "rpmkeyring-py.h"
2ff057
#include "rpmfi-py.h"	/* XXX for rpmfiNew */
2ff057
#include "rpmmi-py.h"
2ff057
#include "rpmii-py.h"
2ff057
#include "rpmps-py.h"
2ff057
#include "rpmte-py.h"
2ff057
#include "rpmts-py.h"
2ff057
2ff057
/** \ingroup python
2ff057
 * \name Class: Rpmts
2ff057
 * \class Rpmts
2ff057
 * \brief A python rpm.ts object represents an RPM transaction set.
2ff057
 *
2ff057
 * The transaction set is the workhorse of RPM.  It performs the
2ff057
 * installation and upgrade of packages.  The rpm.ts object is
2ff057
 * instantiated by the TransactionSet function in the rpm module.
2ff057
 *
2ff057
 * The TransactionSet function takes two optional arguments. The first
2ff057
 * argument is the root path. The second is the verify signature disable flags,
2ff057
 * a set of the following bits:
2ff057
 *
2ff057
 * -    rpm.RPMVSF_NOHDRCHK	if set, don't check rpmdb headers
2ff057
 * -    rpm.RPMVSF_NEEDPAYLOAD	if not set, check header+payload (if possible)
2ff057
 * -	rpm.RPMVSF_NOSHA1HEADER	if set, don't check header SHA1 digest
2ff057
 * -	rpm.RPMVSF_NODSAHEADER	if set, don't check header DSA signature
2ff057
 * -	rpm.RPMVSF_NOMD5	if set, don't check header+payload MD5 digest
2ff057
 * -	rpm.RPMVSF_NODSA	if set, don't check header+payload DSA signature
2ff057
 * -	rpm.RPMVSF_NORSA	if set, don't check header+payload RSA signature
2ff057
 *
2ff057
 * For convenience, there are the following masks:
2ff057
 * -    rpm.RPMVSF_MASK_NODIGESTS		if set, don't check digest(s).
2ff057
 * -    rpm.RPMVSF_MASK_NOSIGNATURES	if set, don't check signature(s).
2ff057
 *
2ff057
 * A rpm.ts object has the following methods:
2ff057
 *
2ff057
 * - addInstall(hdr,data,mode)  Add an install element to a transaction set.
2ff057
 * @param hdr	the header to be added
2ff057
 * @param data	user data that will be passed to the transaction callback
2ff057
 *		during transaction execution
2ff057
 * @param mode 	optional argument that specifies if this package should
2ff057
 *		be installed ('i'), upgraded ('u').
2ff057
 *
2ff057
 * - addErase(name) Add an erase element to a transaction set.
2ff057
 * @param name	the package name to be erased
2ff057
 *
2ff057
 * - check()	Perform a dependency check on the transaction set. After
2ff057
 *		headers have been added to a transaction set, a dependency
2ff057
 *		check can be performed to make sure that all package
2ff057
 *		dependencies are satisfied.
2ff057
 * @return	None If there are no unresolved dependencies
2ff057
 *		Otherwise a list of complex tuples is returned, one tuple per
2ff057
 *		unresolved dependency, with
2ff057
 * The format of the dependency tuple is:
2ff057
 *     ((packageName, packageVersion, packageRelease),
2ff057
 *      (reqName, reqVersion),
2ff057
 *      needsFlags,
2ff057
 *      suggestedPackage,
2ff057
 *      sense)
2ff057
 *     packageName, packageVersion, packageRelease are the name,
2ff057
 *     version, and release of the package that has the unresolved
2ff057
 *     dependency or conflict.
2ff057
 *     The reqName and reqVersion are the name and version of the
2ff057
 *     requirement or conflict.
2ff057
 *     The needsFlags is a bitfield that describes the versioned
2ff057
 *     nature of a requirement or conflict.  The constants
2ff057
 *     rpm.RPMSENSE_LESS, rpm.RPMSENSE_GREATER, and
2ff057
 *     rpm.RPMSENSE_EQUAL can be logical ANDed with the needsFlags
2ff057
 *     to get versioned dependency information.
2ff057
 *     suggestedPackage is a tuple if the dependency check was aware
2ff057
 *     of a package that solves this dependency problem when the
2ff057
 *     dependency check was run.  Packages that are added to the
2ff057
 *     transaction set as "available" are examined during the
2ff057
 *     dependency check as possible dependency solvers. The tuple
2ff057
 *     contains two values, (header, suggestedName).  These are set to
2ff057
 *     the header of the suggested package and its name, respectively.
2ff057
 *     If there is no known package to solve the dependency problem,
2ff057
 *     suggestedPackage is None.
2ff057
 *     The constants rpm.RPMDEP_SENSE_CONFLICTS and
2ff057
 *     rpm.RPMDEP_SENSE_REQUIRES are set to show a dependency as a
2ff057
 *     requirement or a conflict.
2ff057
 *
2ff057
 * - ts.order()	Do a topological sort of added element relations.
2ff057
 * @return	None
2ff057
 *
2ff057
 * - ts.setFlags(transFlags) Set transaction set flags.
2ff057
 * @param transFlags - bit(s) to control transaction operations. The
2ff057
 *		following values can be logically OR'ed together:
2ff057
 *	- rpm.RPMTRANS_FLAG_TEST - test mode, do not modify the RPM
2ff057
 *		database, change any files, or run any package scripts
2ff057
 *	- rpm.RPMTRANS_FLAG_BUILD_PROBS - only build a list of
2ff057
 *		problems encountered when attempting to run this transaction
2ff057
 *		set
2ff057
 *	- rpm.RPMTRANS_FLAG_JUSTDB - only make changes to the rpm
2ff057
 *		database, do not modify files.
2ff057
 *	- rpm.RPMTRANS_FLAG_NOSCRIPTS - do not execute package scripts
2ff057
 *	- rpm.RPMTRANS_FLAG_NOTRIGGERS - do not run trigger scripts
2ff057
 *	- rpm.RPMTRANS_FLAG_NO* - disable specific scripts and triggers
2ff057
 *	- rpm.RPMTRANS_FLAG_NODOCS - do not install files marked as %doc
2ff057
 *	- rpm.RPMTRANS_FLAG_NOPLUGINS - do not run plugins
2ff057
 *	- rpm.RPMTRANS_FLAG_NOFILEDIGEST - disable checking checksums
2ff057
 *	- rpm.RPMTRANS_FLAG_ALLFILES - create all files, even if a
2ff057
 *		file is marked %config(missingok) and an upgrade is
2ff057
 *		being performed.
2ff057
 *	- rpm.RPMTRANS_FLAG_NOCONFIGS - skip config files
2ff057
 *	- rpm.RPMTRANS_FLAG_DEPLOOPS - enable debugging for dependency loops
2ff057
 * @return	previous transFlags
2ff057
 *
2ff057
 * - ts.setProbFilter(ignoreSet) Set transaction set problem filter.
2ff057
 * @param problemSetFilter - control bit(s) to ignore classes of problems,
2ff057
 *		a logical or of one or more of the following bit(s):
2ff057
 *	- rpm.RPMPROB_FILTER_IGNOREOS -
2ff057
 *	- rpm.RPMPROB_FILTER_IGNOREARCH -
2ff057
 *	- rpm.RPMPROB_FILTER_REPLACEPKG -
2ff057
 *	- rpm.RPMPROB_FILTER_FORCERELOCATE -
2ff057
 *	- rpm.RPMPROB_FILTER_REPLACENEWFILES -
2ff057
 *	- rpm.RPMPROB_FILTER_REPLACEOLDFILES -
2ff057
 *	- rpm.RPMPROB_FILTER_OLDPACKAGE -
2ff057
 *	- rpm.RPMPROB_FILTER_DISKSPACE -
2ff057
 * @return	previous ignoreSet
2ff057
 *
2ff057
 * - ts.run(callback,data) Attempt to execute a transaction set.
2ff057
 *	After the transaction set has been populated with install/upgrade or
2ff057
 *	erase actions, the transaction set can be executed by invoking
2ff057
 *	the ts.run() method.
2ff057
 */
2ff057
2ff057
struct rpmtsObject_s {
2ff057
    PyObject_HEAD
2ff057
    PyObject *md_dict;		/*!< to look like PyModuleObject */
2ff057
    rpmfdObject *scriptFd;
2ff057
    PyObject *keyList;
2ff057
    rpmts	ts;
2ff057
    rpmtsi tsi;
2ff057
};
2ff057
2ff057
struct rpmtsCallbackType_s {
2ff057
    PyObject * cb;
2ff057
    PyObject * data;
2ff057
    rpmtsObject * tso;
2ff057
    PyThreadState *_save;
2ff057
};
2ff057
2ff057
RPM_GNUC_NORETURN
2ff057
static void die(PyObject *cb)
2ff057
{
2ff057
    char *pyfn = NULL;
2ff057
    PyObject *r;
2ff057
2ff057
    if (PyErr_Occurred()) {
2ff057
	PyErr_Print();
2ff057
    }
2ff057
    if ((r = PyObject_Repr(cb)) != NULL) { 
2ff057
	pyfn = PyBytes_AsString(r);
2ff057
    }
2ff057
    fprintf(stderr, "FATAL ERROR: python callback %s failed, aborting!\n", 
2ff057
	    	      pyfn ? pyfn : "???");
2ff057
    exit(EXIT_FAILURE);
2ff057
}
2ff057
2ff057
static PyObject *
2ff057
rpmts_AddInstall(rpmtsObject * s, PyObject * args)
2ff057
{
2ff057
    Header h = NULL;
2ff057
    PyObject * key;
2ff057
    int how = 0;
2ff057
    int rc;
2ff057
2ff057
    if (!PyArg_ParseTuple(args, "O&Oi:AddInstall", 
2ff057
			  hdrFromPyObject, &h, &key, &how))
2ff057
	return NULL;
2ff057
2ff057
    rc = rpmtsAddInstallElement(s->ts, h, key, how, NULL);
2ff057
    if (key && rc == 0) {
2ff057
	PyList_Append(s->keyList, key);
2ff057
    }
2ff057
    return PyBool_FromLong((rc == 0));
2ff057
}
2ff057
2ff057
static PyObject *
2ff057
rpmts_AddReinstall(rpmtsObject * s, PyObject * args)
2ff057
{
2ff057
    Header h = NULL;
2ff057
    PyObject * key;
2ff057
    int rc;
2ff057
2ff057
    if (!PyArg_ParseTuple(args, "O&O:AddReinstall", 
2ff057
			  hdrFromPyObject, &h, &key))
2ff057
	return NULL;
2ff057
2ff057
    rc = rpmtsAddReinstallElement(s->ts, h, key);
2ff057
    if (key && rc == 0) {
2ff057
	PyList_Append(s->keyList, key);
2ff057
    }
2ff057
    return PyBool_FromLong((rc == 0));
2ff057
}
2ff057
2ff057
static PyObject *
2ff057
rpmts_AddErase(rpmtsObject * s, PyObject * args)
2ff057
{
2ff057
    Header h;
2ff057
2ff057
    if (!PyArg_ParseTuple(args, "O&:AddErase", hdrFromPyObject, &h))
2ff057
        return NULL;
2ff057
2ff057
    return PyBool_FromLong(rpmtsAddEraseElement(s->ts, h, -1) == 0);
2ff057
}
2ff057
2ff057
static int
2ff057
rpmts_SolveCallback(rpmts ts, rpmds ds, const void * data)
2ff057
{
2ff057
    struct rpmtsCallbackType_s * cbInfo = (struct rpmtsCallbackType_s *) data;
2ff057
    PyObject * args, * result;
2ff057
    int res = 1;
2ff057
2ff057
    if (cbInfo->tso == NULL) return res;
2ff057
    if (cbInfo->cb == Py_None) return res;
2ff057
2ff057
    PyEval_RestoreThread(cbInfo->_save);
2ff057
2ff057
    args = Py_BuildValue("(Oissi)", cbInfo->tso,
2ff057
		rpmdsTagN(ds), rpmdsN(ds), rpmdsEVR(ds), rpmdsFlags(ds));
2ff057
    result = PyEval_CallObject(cbInfo->cb, args);
2ff057
    Py_DECREF(args);
2ff057
2ff057
    if (!result) {
2ff057
	die(cbInfo->cb);
2ff057
    } else {
2ff057
	if (PyInt_Check(result))
2ff057
	    res = PyInt_AsLong(result);
2ff057
	Py_DECREF(result);
2ff057
    }
2ff057
2ff057
    cbInfo->_save = PyEval_SaveThread();
2ff057
2ff057
    return res;
2ff057
}
2ff057
2ff057
static PyObject *
2ff057
rpmts_Check(rpmtsObject * s, PyObject * args, PyObject * kwds)
2ff057
{
2ff057
    struct rpmtsCallbackType_s cbInfo;
2ff057
    int rc;
2ff057
    char * kwlist[] = {"callback", NULL};
2ff057
2ff057
    memset(&cbInfo, 0, sizeof(cbInfo));
2ff057
    if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O:Check", kwlist,
2ff057
	    &cbInfo.cb))
2ff057
	return NULL;
2ff057
2ff057
    if (cbInfo.cb != NULL) {
2ff057
	if (!PyCallable_Check(cbInfo.cb)) {
2ff057
	    PyErr_SetString(PyExc_TypeError, "expected a callable");
2ff057
	    return NULL;
2ff057
	}
2ff057
	rc = rpmtsSetSolveCallback(s->ts, rpmts_SolveCallback, (void *)&cbInfo);
2ff057
    }
2ff057
2ff057
    cbInfo.tso = s;
2ff057
    cbInfo._save = PyEval_SaveThread();
2ff057
2ff057
    rc = rpmtsCheck(s->ts);
2ff057
2ff057
    PyEval_RestoreThread(cbInfo._save);
2ff057
2ff057
    return PyBool_FromLong((rc == 0));
2ff057
}
2ff057
2ff057
static PyObject *
2ff057
rpmts_Order(rpmtsObject * s)
2ff057
{
2ff057
    int rc;
2ff057
2ff057
    Py_BEGIN_ALLOW_THREADS
2ff057
    rc = rpmtsOrder(s->ts);
2ff057
    Py_END_ALLOW_THREADS
2ff057
2ff057
    return Py_BuildValue("i", rc);
2ff057
}
2ff057
2ff057
static PyObject *
2ff057
rpmts_Clean(rpmtsObject * s)
2ff057
{
2ff057
    rpmtsClean(s->ts);
2ff057
2ff057
    Py_RETURN_NONE;
2ff057
}
2ff057
2ff057
static PyObject *
2ff057
rpmts_Clear(rpmtsObject * s)
2ff057
{
2ff057
    rpmtsEmpty(s->ts);
2ff057
2ff057
    Py_RETURN_NONE;
2ff057
}
2ff057
2ff057
static PyObject *
2ff057
rpmts_OpenDB(rpmtsObject * s)
2ff057
{
2ff057
    int dbmode;
2ff057
2ff057
    dbmode = rpmtsGetDBMode(s->ts);
2ff057
    if (dbmode == -1)
2ff057
	dbmode = O_RDONLY;
2ff057
2ff057
    return Py_BuildValue("i", rpmtsOpenDB(s->ts, dbmode));
2ff057
}
2ff057
2ff057
static PyObject *
2ff057
rpmts_CloseDB(rpmtsObject * s)
2ff057
{
2ff057
    int rc;
2ff057
2ff057
    rc = rpmtsCloseDB(s->ts);
2ff057
    rpmtsSetDBMode(s->ts, -1);	/* XXX disable lazy opens */
2ff057
2ff057
    return Py_BuildValue("i", rc);
2ff057
}
2ff057
2ff057
static PyObject *
2ff057
rpmts_InitDB(rpmtsObject * s)
2ff057
{
2ff057
    int rc;
2ff057
2ff057
    rc = rpmtsInitDB(s->ts, O_RDONLY);
2ff057
    if (rc == 0)
2ff057
	rc = rpmtsCloseDB(s->ts);
2ff057
2ff057
    return Py_BuildValue("i", rc);
2ff057
}
2ff057
2ff057
static PyObject *
2ff057
rpmts_RebuildDB(rpmtsObject * s)
2ff057
{
2ff057
    int rc;
2ff057
2ff057
    Py_BEGIN_ALLOW_THREADS
2ff057
    rc = rpmtsRebuildDB(s->ts);
2ff057
    Py_END_ALLOW_THREADS
2ff057
2ff057
    return Py_BuildValue("i", rc);
2ff057
}
2ff057
2ff057
static PyObject *
2ff057
rpmts_VerifyDB(rpmtsObject * s)
2ff057
{
2ff057
    int rc;
2ff057
2ff057
    Py_BEGIN_ALLOW_THREADS
2ff057
    rc = rpmtsVerifyDB(s->ts);
2ff057
    Py_END_ALLOW_THREADS
2ff057
2ff057
    return Py_BuildValue("i", rc);
2ff057
}
2ff057
2ff057
static PyObject *
2ff057
rpmts_HdrFromFdno(rpmtsObject * s, PyObject *arg)
2ff057
{
2ff057
    PyObject *ho = NULL;
2ff057
    rpmfdObject *fdo = NULL;
2ff057
    Header h;
2ff057
    rpmRC rpmrc;
2ff057
2ff057
    if (!PyArg_Parse(arg, "O&:HdrFromFdno", rpmfdFromPyObject, &fdo))
2ff057
    	return NULL;
2ff057
2ff057
    Py_BEGIN_ALLOW_THREADS;
2ff057
    rpmrc = rpmReadPackageFile(s->ts, rpmfdGetFd(fdo), NULL, &h);
2ff057
    Py_END_ALLOW_THREADS;
2ff057
    Py_XDECREF(fdo);
2ff057
2ff057
    if (rpmrc == RPMRC_OK) {
2ff057
	ho = hdr_Wrap(&hdr_Type, h);
2ff057
    } else {
2ff057
	Py_INCREF(Py_None);
2ff057
	ho = Py_None;
2ff057
    }
2ff057
    return Py_BuildValue("(iN)", rpmrc, ho);
2ff057
}
2ff057
2ff057
static PyObject *
2ff057
rpmts_HdrCheck(rpmtsObject * s, PyObject *obj)
2ff057
{
2ff057
    PyObject * blob;
2ff057
    char * msg = NULL;
2ff057
    const void * uh;
2ff057
    int uc;
2ff057
    rpmRC rpmrc;
2ff057
2ff057
    if (!PyArg_Parse(obj, "S:HdrCheck", &blob))
2ff057
    	return NULL;
2ff057
2ff057
    uh = PyBytes_AsString(blob);
2ff057
    uc = PyBytes_Size(blob);
2ff057
2ff057
    Py_BEGIN_ALLOW_THREADS;
2ff057
    rpmrc = headerCheck(s->ts, uh, uc, &msg;;
2ff057
    Py_END_ALLOW_THREADS;
2ff057
2ff057
    return Py_BuildValue("(is)", rpmrc, msg);
2ff057
}
2ff057
2ff057
static PyObject *
2ff057
rpmts_PgpPrtPkts(rpmtsObject * s, PyObject * args, PyObject * kwds)
2ff057
{
2ff057
    PyObject * blob;
2ff057
    unsigned char * pkt;
2ff057
    unsigned int pktlen;
2ff057
    int rc;
2ff057
    char * kwlist[] = {"octets", NULL};
2ff057
2ff057
    if (!PyArg_ParseTupleAndKeywords(args, kwds, "S:PgpPrtPkts", kwlist, &blob))
2ff057
    	return NULL;
2ff057
2ff057
    pkt = (unsigned char *)PyBytes_AsString(blob);
2ff057
    pktlen = PyBytes_Size(blob);
2ff057
2ff057
    rc = pgpPrtPkts(pkt, pktlen, NULL, 1);
2ff057
2ff057
    return Py_BuildValue("i", rc);
2ff057
}
2ff057
2ff057
static PyObject *
2ff057
rpmts_PgpImportPubkey(rpmtsObject * s, PyObject * args, PyObject * kwds)
2ff057
{
2ff057
    PyObject * blob;
2ff057
    unsigned char * pkt;
2ff057
    unsigned int pktlen;
2ff057
    int rc;
2ff057
    char * kwlist[] = {"pubkey", NULL};
2ff057
2ff057
    if (!PyArg_ParseTupleAndKeywords(args, kwds, "S:PgpImportPubkey",
2ff057
    	    kwlist, &blob))
2ff057
	return NULL;
2ff057
2ff057
    pkt = (unsigned char *)PyBytes_AsString(blob);
2ff057
    pktlen = PyBytes_Size(blob);
2ff057
2ff057
    rc = rpmtsImportPubkey(s->ts, pkt, pktlen);
2ff057
2ff057
    return Py_BuildValue("i", rc);
2ff057
}
2ff057
2ff057
static PyObject *rpmts_setKeyring(rpmtsObject *s, PyObject *arg)
2ff057
{
2ff057
    rpmKeyring keyring = NULL;
2ff057
    if (arg == Py_None || rpmKeyringFromPyObject(arg, &keyring)) {
2ff057
	return PyBool_FromLong(rpmtsSetKeyring(s->ts, keyring) == 0);
2ff057
    } else {
2ff057
	PyErr_SetString(PyExc_TypeError, "rpm.keyring or None expected");
2ff057
	return NULL;
2ff057
    }
2ff057
}
2ff057
2ff057
static PyObject *rpmts_getKeyring(rpmtsObject *s, PyObject *args, PyObject *kwds)
2ff057
{
2ff057
    rpmKeyring keyring = NULL;
2ff057
    int autoload = 1;
2ff057
    char * kwlist[] = { "autoload", NULL };
2ff057
2ff057
    if (!PyArg_ParseTupleAndKeywords(args, kwds, "|i:getKeyring",
2ff057
				     kwlist, &autoload))
2ff057
	return NULL;
2ff057
2ff057
    keyring = rpmtsGetKeyring(s->ts, autoload);
2ff057
    if (keyring) {
2ff057
	return rpmKeyring_Wrap(&rpmKeyring_Type, keyring);
2ff057
    } else {
2ff057
	Py_RETURN_NONE;
2ff057
    }
2ff057
}
2ff057
2ff057
static void *
2ff057
rpmtsCallback(const void * hd, const rpmCallbackType what,
2ff057
		         const rpm_loff_t amount, const rpm_loff_t total,
2ff057
	                 const void * pkgKey, rpmCallbackData data)
2ff057
{
2ff057
    Header h = (Header) hd;
2ff057
    struct rpmtsCallbackType_s * cbInfo = data;
2ff057
    PyObject * pkgObj = (PyObject *) pkgKey;
2ff057
    PyObject * args, * result;
2ff057
    static FD_t fd;
2ff057
2ff057
    if (cbInfo->cb == Py_None) return NULL;
2ff057
Panu Matilainen 0cd6d7
    PyEval_RestoreThread(cbInfo->_save);
Panu Matilainen 0cd6d7
2ff057
    /* Synthesize a python object for callback (if necessary). */
2ff057
    if (pkgObj == NULL) {
2ff057
	if (h) {
2ff057
	    pkgObj = Py_BuildValue("s", headerGetString(h, RPMTAG_NAME));
2ff057
	} else {
2ff057
	    pkgObj = Py_None;
2ff057
	    Py_INCREF(pkgObj);
2ff057
	}
2ff057
    } else
2ff057
	Py_INCREF(pkgObj);
2ff057
2ff057
    args = Py_BuildValue("(iLLOO)", what, amount, total, pkgObj, cbInfo->data);
2ff057
    result = PyEval_CallObject(cbInfo->cb, args);
2ff057
    Py_DECREF(args);
2ff057
    Py_DECREF(pkgObj);
2ff057
2ff057
    if (!result) {
2ff057
	die(cbInfo->cb);
2ff057
    }
2ff057
2ff057
    if (what == RPMCALLBACK_INST_OPEN_FILE) {
2ff057
	int fdno;
2ff057
2ff057
        if (!PyArg_Parse(result, "i", &fdno)) {
2ff057
	    die(cbInfo->cb);
2ff057
	}
2ff057
	Py_DECREF(result);
2ff057
	cbInfo->_save = PyEval_SaveThread();
2ff057
2ff057
	fd = fdDup(fdno);
2ff057
	fcntl(Fileno(fd), F_SETFD, FD_CLOEXEC);
2ff057
2ff057
	return fd;
2ff057
    } else
2ff057
    if (what == RPMCALLBACK_INST_CLOSE_FILE) {
2ff057
	Fclose (fd);
2ff057
    }
2ff057
2ff057
    Py_DECREF(result);
2ff057
    cbInfo->_save = PyEval_SaveThread();
2ff057
2ff057
    return NULL;
2ff057
}
2ff057
2ff057
static PyObject *
2ff057
rpmts_Problems(rpmtsObject * s)
2ff057
{
2ff057
    rpmps ps = rpmtsProblems(s->ts);
2ff057
    PyObject *problems = rpmps_AsList(ps);
2ff057
    rpmpsFree(ps);
2ff057
    return problems;
2ff057
}
2ff057
2ff057
static PyObject *
2ff057
rpmts_Run(rpmtsObject * s, PyObject * args, PyObject * kwds)
2ff057
{
2ff057
    int rc;
2ff057
    struct rpmtsCallbackType_s cbInfo;
2ff057
    rpmprobFilterFlags ignoreSet;
2ff057
    char * kwlist[] = {"callback", "data", "ignoreSet", NULL};
2ff057
2ff057
    if (!PyArg_ParseTupleAndKeywords(args, kwds, "OOi:Run", kwlist,
2ff057
	    &cbInfo.cb, &cbInfo.data, &ignoreSet))
2ff057
	return NULL;
2ff057
2ff057
    cbInfo.tso = s;
2ff057
    cbInfo._save = PyEval_SaveThread();
2ff057
2ff057
    if (cbInfo.cb != NULL) {
2ff057
	if (!PyCallable_Check(cbInfo.cb)) {
2ff057
	    PyErr_SetString(PyExc_TypeError, "expected a callable");
2ff057
	    return NULL;
2ff057
	}
2ff057
	(void) rpmtsSetNotifyCallback(s->ts, rpmtsCallback, (void *) &cbInfo);
2ff057
    }
2ff057
2ff057
    rc = rpmtsRun(s->ts, NULL, ignoreSet);
2ff057
2ff057
    if (cbInfo.cb)
2ff057
	(void) rpmtsSetNotifyCallback(s->ts, NULL, NULL);
2ff057
2ff057
    PyEval_RestoreThread(cbInfo._save);
2ff057
2ff057
    return Py_BuildValue("i", rc);
2ff057
}
2ff057
2ff057
static PyObject *
2ff057
rpmts_iternext(rpmtsObject * s)
2ff057
{
2ff057
    PyObject * result = NULL;
2ff057
    rpmte te;
2ff057
2ff057
    /* Reset iterator on 1st entry. */
2ff057
    if (s->tsi == NULL) {
2ff057
	s->tsi = rpmtsiInit(s->ts);
2ff057
	if (s->tsi == NULL)
2ff057
	    return NULL;
2ff057
    }
2ff057
2ff057
    te = rpmtsiNext(s->tsi, 0);
2ff057
    if (te != NULL) {
2ff057
	result = rpmte_Wrap(&rpmte_Type, te);
2ff057
    } else {
2ff057
	s->tsi = rpmtsiFree(s->tsi);
2ff057
    }
2ff057
2ff057
    return result;
2ff057
}
2ff057
2ff057
static PyObject *
2ff057
rpmts_Match(rpmtsObject * s, PyObject * args, PyObject * kwds)
2ff057
{
2ff057
    PyObject *Key = NULL;
2ff057
    PyObject *str = NULL;
2ff057
    PyObject *mio = NULL;
2ff057
    char *key = NULL;
2ff057
/* XXX lkey *must* be a 32 bit integer, int "works" on all known platforms. */
2ff057
    int lkey = 0;
2ff057
    int len = 0;
2ff057
    rpmDbiTagVal tag = RPMDBI_PACKAGES;
2ff057
    char * kwlist[] = {"tagNumber", "key", NULL};
2ff057
2ff057
    if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O&O:Match", kwlist,
2ff057
	    tagNumFromPyObject, &tag, &Key))
2ff057
	return NULL;
2ff057
2ff057
    if (Key) {
2ff057
	if (PyInt_Check(Key)) {
2ff057
	    lkey = PyInt_AsLong(Key);
2ff057
	    key = (char *)&lkey;
2ff057
	    len = sizeof(lkey);
2ff057
	} else if (PyLong_Check(Key)) {
2ff057
	    lkey = PyLong_AsLong(Key);
2ff057
	    key = (char *)&lkey;
2ff057
	    len = sizeof(lkey);
2ff057
	} else if (utf8FromPyObject(Key, &str)) {
2ff057
	    key = PyBytes_AsString(str);
2ff057
	    len = PyBytes_Size(str);
2ff057
	} else {
2ff057
	    PyErr_SetString(PyExc_TypeError, "unknown key type");
2ff057
	    return NULL;
2ff057
	}
2ff057
	/* One of the conversions above failed, exception is set already */
2ff057
	if (PyErr_Occurred()) goto exit;
2ff057
    }
2ff057
2ff057
    /* XXX If not already opened, open the database O_RDONLY now. */
2ff057
    /* XXX FIXME: lazy default rdonly open also done by rpmtsInitIterator(). */
2ff057
    if (rpmtsGetRdb(s->ts) == NULL) {
2ff057
	int rc = rpmtsOpenDB(s->ts, O_RDONLY);
2ff057
	if (rc || rpmtsGetRdb(s->ts) == NULL) {
2ff057
	    PyErr_SetString(pyrpmError, "rpmdb open failed");
2ff057
	    goto exit;
2ff057
	}
2ff057
    }
2ff057
2ff057
    mio = rpmmi_Wrap(&rpmmi_Type, rpmtsInitIterator(s->ts, tag, key, len), (PyObject*)s);
2ff057
2ff057
exit:
2ff057
    Py_XDECREF(str);
2ff057
    return mio;
2ff057
}
2ff057
static PyObject *
2ff057
rpmts_index(rpmtsObject * s, PyObject * args, PyObject * kwds)
2ff057
{
2ff057
    rpmDbiTagVal tag;
2ff057
    PyObject *mio = NULL;
2ff057
    char * kwlist[] = {"tag", NULL};
2ff057
2ff057
    if (!PyArg_ParseTupleAndKeywords(args, kwds, "O&:Keys", kwlist,
2ff057
              tagNumFromPyObject, &tag))
2ff057
	return NULL;
2ff057
2ff057
    /* XXX If not already opened, open the database O_RDONLY now. */
2ff057
    if (rpmtsGetRdb(s->ts) == NULL) {
2ff057
	int rc = rpmtsOpenDB(s->ts, O_RDONLY);
2ff057
	if (rc || rpmtsGetRdb(s->ts) == NULL) {
2ff057
	    PyErr_SetString(pyrpmError, "rpmdb open failed");
2ff057
	    goto exit;
2ff057
	}
2ff057
    }
2ff057
2ff057
    rpmdbIndexIterator ii = rpmdbIndexIteratorInit(rpmtsGetRdb(s->ts), tag);
2ff057
    if (ii == NULL) {
2ff057
        PyErr_SetString(PyExc_KeyError, "No index for this tag");
2ff057
        return NULL;
2ff057
    }
2ff057
    mio = rpmii_Wrap(&rpmii_Type, ii, (PyObject*)s);
2ff057
2ff057
exit:
2ff057
    return mio;
2ff057
}
2ff057
2ff057
static struct PyMethodDef rpmts_methods[] = {
2ff057
 {"addInstall",	(PyCFunction) rpmts_AddInstall,	METH_VARARGS,
2ff057
  "ts.addInstall(hdr, data, mode) --  Add transaction element(s)\n"
2ff057
  "representing an installation or update of a package.\n\n"
2ff057
  "Args:\n"
2ff057
  "  hdr : the header to be added\n"
2ff057
  "  data : user data that will be passed to the transaction callback\n\t\tduring transaction execution\n"
2ff057
  "  mode : optional argument that specifies if this package should be\n\t\tinstalled ('i'), upgraded ('u')"},
2ff057
 {"addReinstall",	(PyCFunction) rpmts_AddReinstall,	METH_VARARGS,
2ff057
  "ts.addReinstall(hdr, data) -- Adds transaction elements\nrepresenting a reinstall of an already installed package.\n\nSee addInstall for details."},
2ff057
 {"addErase",	(PyCFunction) rpmts_AddErase,	METH_VARARGS|METH_KEYWORDS,
2ff057
  "addErase(name) -- Add a transaction element representing an erase\nof an installed package.\n\n"
2ff057
  "  name: the package name to be erased"},
2ff057
 {"check",	(PyCFunction) rpmts_Check,	METH_VARARGS|METH_KEYWORDS,
2ff057
  "ts.check( )-- Perform a dependency check on the transaction set.\n"
2ff057
  "		After headers have been added to a transaction set,\n"
2ff057
  "		a dependencycheck can be performed to make sure that\n"
2ff057
  "		all package dependencies are satisfied.\n"
2ff057
  "Return	None If there are no unresolved dependencies\n"
2ff057
  "		Otherwise a list of complex tuples is returned,\n"
2ff057
  "		one tuple per unresolved dependency, with\n"
2ff057
  "The format of the dependency tuple is:\n"
2ff057
  "    ((packageName, packageVersion, packageRelease),\n"
2ff057
  "     (reqName, reqVersion),\n"
2ff057
  "     needsFlags,\n"
2ff057
  "     suggestedPackage,\n"
2ff057
  "     sense)\n"
2ff057
  "  packageName, packageVersion, packageRelease are the name,\n"
2ff057
  "    version, and release of the package that has the unresolved\n"
2ff057
  "    dependency or conflict.\n"
2ff057
  "  The reqName and reqVersion are the name and version of the\n"
2ff057
  "    requirement or conflict.\n"
2ff057
  "  The needsFlags is a bitfield that describes the versioned\n"
2ff057
  "    nature of a requirement or conflict.  The constants\n"
2ff057
  "    rpm.RPMSENSE_LESS, rpm.RPMSENSE_GREATER, and\n"
2ff057
  "    rpm.RPMSENSE_EQUAL can be logical ANDed with the needsFlags\n"
2ff057
  "    to get versioned dependency information.\n"
2ff057
  "  suggestedPackage is a tuple if the dependency check was aware\n"
2ff057
  "    of a package that solves this dependency problem when the\n"
2ff057
  "    dependency check was run.  Packages that are added to the\n"
2ff057
  "    transaction set as \"available\" are examined during the\n"
2ff057
  "    dependency check as possible dependency solvers. The tuple\n"
2ff057
  "    contains two values, (header, suggestedName).  These are set to\n"
2ff057
  "    the header of the suggested package and its name, respectively.\n"
2ff057
  "    If there is no known package to solve the dependency problem,\n"
2ff057
  "    suggestedPackage is None.\n"
2ff057
  "  The constants rpm.RPMDEP_SENSE_CONFLICTS and\n"
2ff057
  "    rpm.RPMDEP_SENSE_REQUIRES are set to show a dependency as a\n"
2ff057
  "    requirement or a conflict.\n"},
2ff057
 {"order",	(PyCFunction) rpmts_Order,	METH_NOARGS,
2ff057
  "ts.order() Do a topological sort of added element relations." },
2ff057
 {"problems",	(PyCFunction) rpmts_Problems,	METH_NOARGS,
2ff057
"ts.problems() -> ps\n\
2ff057
- Return current problem set.\n" },
2ff057
 {"run",	(PyCFunction) rpmts_Run,	METH_VARARGS|METH_KEYWORDS,
2ff057
"ts.run(callback, data) -> (problems)\n\
2ff057
- Run a transaction set, returning list of problems found.\n\
2ff057
  Note: The callback may not be None.\n" },
2ff057
 {"clean",	(PyCFunction) rpmts_Clean,	METH_NOARGS,
2ff057
  "ts.clean()-- Free memory needed only for dependency checks\nand ordering. Should not be needed in normal operation." },
2ff057
 {"clear",	(PyCFunction) rpmts_Clear,	METH_NOARGS,
2ff057
"ts.clear() -> None\n\
2ff057
Remove all elements from the transaction set\n" },
2ff057
 {"openDB",	(PyCFunction) rpmts_OpenDB,	METH_NOARGS,
2ff057
"ts.openDB() -> None -- Open the default transaction rpmdb.\n\n\
2ff057
  Note: The transaction rpmdb is lazily opened,\n  so ts.openDB() is seldom needed.\n" },
2ff057
 {"closeDB",	(PyCFunction) rpmts_CloseDB,	METH_NOARGS,
2ff057
"ts.closeDB() -> None\n\
2ff057
- Close the default transaction rpmdb.\n\
2ff057
  Note: ts.closeDB() disables lazy opens,\n\
2ff057
  and should hardly ever be used.\n" },
2ff057
 {"initDB",	(PyCFunction) rpmts_InitDB,	METH_NOARGS,
2ff057
"ts.initDB() -> None\n\
2ff057
- Initialize the default transaction rpmdb.\n\
2ff057
 Note: ts.initDB() is seldom needed anymore.\n" },
2ff057
 {"rebuildDB",	(PyCFunction) rpmts_RebuildDB,	METH_NOARGS,
2ff057
"ts.rebuildDB() -> None\n\
2ff057
- Rebuild the default transaction rpmdb.\n" },
2ff057
 {"verifyDB",	(PyCFunction) rpmts_VerifyDB,	METH_NOARGS,
2ff057
"ts.verifyDB() -> None\n\
2ff057
- Verify the default transaction rpmdb.\n" },
2ff057
 {"hdrFromFdno",(PyCFunction) rpmts_HdrFromFdno,METH_O,
2ff057
"ts.hdrFromFdno(fdno) -> hdr\n\
2ff057
- Read a package header from a file descriptor.\n" },
2ff057
 {"hdrCheck",	(PyCFunction) rpmts_HdrCheck,	METH_O,
2ff057
  "ts.hdrCheck(hdrblob) -- Check header consistency,\nperforming headerGetEntry() the hard way.\n\n"
2ff057
  "Sanity checks on the header are performed while looking for a\n"
2ff057
  "header-only digest or signature to verify the blob. If found,\n"
2ff057
  "the digest or signature is verified.\n\n"
2ff057
  "\thdrblob : unloaded header blob\n"
2ff057
  "Return tuple (int status, message string)"},
2ff057
 {"pgpPrtPkts",	(PyCFunction) rpmts_PgpPrtPkts,	METH_VARARGS|METH_KEYWORDS,
2ff057
  "pgpPrtPkts(octets) -- Print/parse a OpenPGP packet(s).\n\nReturn 0 on success." },
2ff057
 {"pgpImportPubkey",	(PyCFunction) rpmts_PgpImportPubkey,	METH_VARARGS|METH_KEYWORDS,
2ff057
  "pgpImportPubkey(pubkey) -- Import public key packet." },
2ff057
 {"getKeyring",	(PyCFunction) rpmts_getKeyring,	METH_VARARGS|METH_KEYWORDS, 
2ff057
  "ts.getKeyring(autoload=False) -- Return key ring object." },
2ff057
 {"setKeyring",	(PyCFunction) rpmts_setKeyring,	METH_O, 
2ff057
  "ts.setKeyring(keyring) -- Set key ring used for checking signatures\n\n"
2ff057
  "Pass None for an empty key ring." },
2ff057
 {"dbMatch",	(PyCFunction) rpmts_Match,	METH_VARARGS|METH_KEYWORDS,
2ff057
"ts.dbMatch([TagN, [key]]) -> mi\n\
2ff057
- Create a match iterator for the default transaction rpmdb.\n" },
2ff057
 {"dbIndex",     (PyCFunction) rpmts_index,	METH_VARARGS|METH_KEYWORDS,
2ff057
"ts.dbIndex(TagN) -> ii\n\
2ff057
- Create a key iterator for the default transaction rpmdb.\n" },
2ff057
    {NULL,		NULL}		/* sentinel */
2ff057
};
2ff057
2ff057
static void rpmts_dealloc(rpmtsObject * s)
2ff057
{
2ff057
2ff057
    s->ts = rpmtsFree(s->ts);
2ff057
    Py_XDECREF(s->scriptFd);
2ff057
    Py_XDECREF(s->keyList);
2ff057
    Py_TYPE(s)->tp_free((PyObject *)s);
2ff057
}
2ff057
2ff057
static PyObject * rpmts_new(PyTypeObject * subtype, PyObject *args, PyObject *kwds)
2ff057
{
2ff057
    rpmtsObject * s = (rpmtsObject *)subtype->tp_alloc(subtype, 0);
2ff057
    if (s == NULL) return NULL;
2ff057
2ff057
    s->ts = rpmtsCreate();
2ff057
    s->scriptFd = NULL;
2ff057
    s->tsi = NULL;
2ff057
    s->keyList = PyList_New(0);
2ff057
    return (PyObject *) s;
2ff057
}
2ff057
2ff057
static int rpmts_init(rpmtsObject *s, PyObject *args, PyObject *kwds)
2ff057
{
2ff057
    const char * rootDir = "/";
2ff057
    rpmVSFlags vsflags = rpmExpandNumeric("%{?__vsflags}");
2ff057
    char * kwlist[] = {"rootdir", "vsflags", 0};
2ff057
2ff057
    if (!PyArg_ParseTupleAndKeywords(args, kwds, "|si:rpmts_new", kwlist,
2ff057
	    &rootDir, &vsflags))
2ff057
	return -1;
2ff057
2ff057
    (void) rpmtsSetRootDir(s->ts, rootDir);
2ff057
    /* XXX: make this use common code with rpmts_SetVSFlags() to check the
2ff057
     *      python objects */
2ff057
    (void) rpmtsSetVSFlags(s->ts, vsflags);
2ff057
2ff057
    return 0;
2ff057
}
2ff057
2ff057
static PyObject *rpmts_get_tid(rpmtsObject *s, void *closure)
2ff057
{
2ff057
    return Py_BuildValue("i", rpmtsGetTid(s->ts));
2ff057
}
2ff057
2ff057
static PyObject *rpmts_get_rootDir(rpmtsObject *s, void *closure)
2ff057
{
2ff057
    return Py_BuildValue("s", rpmtsRootDir(s->ts));
2ff057
}
2ff057
2ff057
static int rpmts_set_scriptFd(rpmtsObject *s, PyObject *value, void *closure)
2ff057
{
2ff057
    rpmfdObject *fdo = NULL;
2ff057
    int rc = 0;
2ff057
    if (PyArg_Parse(value, "O&", rpmfdFromPyObject, &fdo)) {
2ff057
	Py_XDECREF(s->scriptFd);
2ff057
	s->scriptFd = fdo;
2ff057
	rpmtsSetScriptFd(s->ts, rpmfdGetFd(s->scriptFd));
2ff057
    } else if (value == Py_None) {
2ff057
	Py_XDECREF(s->scriptFd);
2ff057
	s->scriptFd = NULL;
2ff057
	rpmtsSetScriptFd(s->ts, NULL);
2ff057
    } else {
2ff057
	rc = -1;
2ff057
    }
2ff057
    return rc;
2ff057
}
2ff057
2ff057
static PyObject *rpmts_get_color(rpmtsObject *s, void *closure)
2ff057
{
2ff057
    return Py_BuildValue("i", rpmtsColor(s->ts));
2ff057
}
2ff057
2ff057
static PyObject *rpmts_get_prefcolor(rpmtsObject *s, void *closure)
2ff057
{
2ff057
    return Py_BuildValue("i", rpmtsPrefColor(s->ts));
2ff057
}
2ff057
2ff057
static int rpmts_set_color(rpmtsObject *s, PyObject *value, void *closure)
2ff057
{
2ff057
    rpm_color_t color;
2ff057
    if (!PyArg_Parse(value, "i", &color)) return -1;
2ff057
2ff057
    /* TODO: validate the bits */
2ff057
    rpmtsSetColor(s->ts, color);
2ff057
    return 0;
2ff057
}
2ff057
2ff057
static int rpmts_set_prefcolor(rpmtsObject *s, PyObject *value, void *closure)
2ff057
{
2ff057
    rpm_color_t color;
2ff057
    if (!PyArg_Parse(value, "i", &color)) return -1;
2ff057
2ff057
    /* TODO: validate the bits */
2ff057
    rpmtsSetPrefColor(s->ts, color);
2ff057
    return 0;
2ff057
}
2ff057
2ff057
static int rpmts_set_flags(rpmtsObject *s, PyObject *value, void *closure)
2ff057
{
2ff057
    rpmtransFlags flags;
2ff057
    if (!PyArg_Parse(value, "i", &flags)) return -1;
2ff057
2ff057
    /* TODO: validate the bits */
2ff057
    rpmtsSetFlags(s->ts, flags);
2ff057
    return 0;
2ff057
}
2ff057
2ff057
static int rpmts_set_vsflags(rpmtsObject *s, PyObject *value, void *closure)
2ff057
{
2ff057
    rpmVSFlags flags;
2ff057
    if (!PyArg_Parse(value, "i", &flags)) return -1;
2ff057
2ff057
    /* TODO: validate the bits */
2ff057
    rpmtsSetVSFlags(s->ts, flags);
2ff057
    return 0;
2ff057
}
2ff057
2ff057
static int rpmts_set_vfyflags(rpmtsObject *s, PyObject *value, void *closure)
2ff057
{
2ff057
    rpmVSFlags flags;
2ff057
    if (!PyArg_Parse(value, "i", &flags)) return -1;
2ff057
2ff057
    /* TODO: validate the bits */
2ff057
    rpmtsSetVfyFlags(s->ts, flags);
2ff057
    return 0;
2ff057
}
2ff057
2ff057
static int rpmts_set_vfylevel(rpmtsObject *s, PyObject *value, void *closure)
2ff057
{
2ff057
    int vfylevel;
2ff057
    if (!PyArg_Parse(value, "i", &vfylevel)) return -1;
2ff057
    rpmtsSetVfyLevel(s->ts, vfylevel);
2ff057
    return 0;
2ff057
}
2ff057
2ff057
static PyObject *rpmts_get_flags(rpmtsObject *s, void *closure)
2ff057
{
2ff057
    return Py_BuildValue("i", rpmtsFlags(s->ts));
2ff057
}
2ff057
2ff057
static PyObject *rpmts_get_vsflags(rpmtsObject *s, void *closure)
2ff057
{
2ff057
    return Py_BuildValue("i", rpmtsVSFlags(s->ts));
2ff057
}
2ff057
2ff057
static PyObject *rpmts_get_vfyflags(rpmtsObject *s, void *closure)
2ff057
{
2ff057
    return Py_BuildValue("i", rpmtsVfyFlags(s->ts));
2ff057
}
2ff057
2ff057
static PyObject *rpmts_get_vfylevel(rpmtsObject *s, void *closure)
2ff057
{
2ff057
    return Py_BuildValue("i", rpmtsVfyLevel(s->ts));
2ff057
}
2ff057
2ff057
static char rpmts_doc[] =
2ff057
  "A python rpm.ts object represents an RPM transaction set.\n"
2ff057
  "\n"
2ff057
  "The transaction set is the workhorse of RPM. It performs the\n"
2ff057
  "installation and upgrade of packages. The rpm.ts object is\n"
2ff057
  "instantiated by the TransactionSet function in the rpm module.\n"
2ff057
  "\n"
2ff057
  "The TransactionSet function takes two optional arguments. The first\n"
2ff057
  "argument is the root path. The second is the verify signature disable\n"
2ff057
  "flags, a set of the following bits:\n"
2ff057
  "\n"
2ff057
  "-    rpm.RPMVSF_NOHDRCHK	if set, don't check rpmdb headers\n"
2ff057
  "-    rpm.RPMVSF_NEEDPAYLOAD	if not set, check header+payload\n"
2ff057
  "				(if possible)\n"
2ff057
  "-    rpm.RPMVSF_NOSHA1HEADER	if set, don't check header SHA1 digest\n"
2ff057
  "-    rpm.RPMVSF_NODSAHEADER	if set, don't check header DSA signature\n"
2ff057
  "-    rpm.RPMVSF_NOMD5	if set, don't check header+payload MD5 digest\n"
2ff057
  "-    rpm.RPMVSF_NODSA	if set, don't check header+payload DSA signature\n"
2ff057
  "-    rpm.RPMVSF_NORSA	if set, don't check header+payload RSA signature\n"
2ff057
  "\n"
2ff057
  "For convenience, there are the following masks:\n"
2ff057
  "-    rpm.RPMVSF_MASK_NODIGESTS	if set, don't check digest(s).\n"
2ff057
  "-    rpm.RPMVSF_MASK_NOSIGNATURES	if set, don't check signature(s).\n\n"
2ff057
  "The transaction set offers an read only iterable interface for the\ntransaction elements added by the .addInstall(), .addErase() and\n.addReinstall() methods.";
2ff057
2ff057
static PyGetSetDef rpmts_getseters[] = {
2ff057
	/* only provide a setter until we have rpmfd wrappings */
2ff057
	{"scriptFd",	NULL,	(setter)rpmts_set_scriptFd,
2ff057
	 "write only, file descriptor the output of script gets written to." },
2ff057
	{"tid",		(getter)rpmts_get_tid, NULL,
2ff057
	 "read only, current transaction id, i.e. transaction time stamp."},
2ff057
	{"rootDir",	(getter)rpmts_get_rootDir, NULL,
2ff057
	 "read only, directory rpm treats as root of the file system." },
2ff057
	{"_color",	(getter)rpmts_get_color, (setter)rpmts_set_color, NULL},
2ff057
	{"_prefcolor",	(getter)rpmts_get_prefcolor, (setter)rpmts_set_prefcolor, NULL},
2ff057
	{"_flags",	(getter)rpmts_get_flags, (setter)rpmts_set_flags, NULL},
2ff057
	{"_vsflags",	(getter)rpmts_get_vsflags, (setter)rpmts_set_vsflags, NULL},
2ff057
	{"_vfyflags",	(getter)rpmts_get_vfyflags, (setter)rpmts_set_vfyflags, NULL},
2ff057
	{"_vfylevel",	(getter)rpmts_get_vfylevel, (setter)rpmts_set_vfylevel, NULL},
2ff057
	{ NULL }
2ff057
};
2ff057
2ff057
PyTypeObject rpmts_Type = {
2ff057
	PyVarObject_HEAD_INIT(&PyType_Type, 0)
2ff057
	"rpm.ts",			/* tp_name */
2ff057
	sizeof(rpmtsObject),		/* tp_size */
2ff057
	0,				/* tp_itemsize */
2ff057
	(destructor) rpmts_dealloc, 	/* tp_dealloc */
2ff057
	0,				/* tp_print */
2ff057
	(getattrfunc)0, 		/* tp_getattr */
2ff057
	(setattrfunc)0,			/* tp_setattr */
2ff057
	0,				/* tp_compare */
2ff057
	0,				/* tp_repr */
2ff057
	0,				/* tp_as_number */
2ff057
	0,				/* tp_as_sequence */
2ff057
	0,				/* tp_as_mapping */
2ff057
	0,				/* tp_hash */
2ff057
	0,				/* tp_call */
2ff057
	0,				/* tp_str */
2ff057
	PyObject_GenericGetAttr, 	/* tp_getattro */
2ff057
	PyObject_GenericSetAttr,	/* tp_setattro */
2ff057
	0,				/* tp_as_buffer */
2ff057
	Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE,	/* tp_flags */
2ff057
	rpmts_doc,			/* tp_doc */
2ff057
	0,				/* tp_traverse */
2ff057
	0,				/* tp_clear */
2ff057
	0,				/* tp_richcompare */
2ff057
	0,				/* tp_weaklistoffset */
2ff057
	PyObject_SelfIter,		/* tp_iter */
2ff057
	(iternextfunc) rpmts_iternext,	/* tp_iternext */
2ff057
	rpmts_methods,			/* tp_methods */
2ff057
	0,				/* tp_members */
2ff057
	rpmts_getseters,		/* tp_getset */
2ff057
	0,				/* tp_base */
2ff057
	0,				/* tp_dict */
2ff057
	0,				/* tp_descr_get */
2ff057
	0,				/* tp_descr_set */
2ff057
	0,				/* tp_dictoffset */
2ff057
	(initproc) rpmts_init,		/* tp_init */
2ff057
	0,				/* tp_alloc */
2ff057
	(newfunc) rpmts_new,		/* tp_new */
2ff057
	0,				/* tp_free */
2ff057
	0,				/* tp_is_gc */
2ff057
};