1 #include "rpmsystem-py.h"
5 #include <rpm/rpmlib.h> /* rpmReadPackageFile, headerCheck */
6 #include <rpm/rpmtag.h>
7 #include <rpm/rpmpgp.h>
9 #include <rpm/rpmbuild.h>
11 #include "header-py.h"
12 #include "rpmds-py.h" /* XXX for rpmdsNew */
14 #include "rpmkeyring-py.h"
15 #include "rpmfi-py.h" /* XXX for rpmfiNew */
25 * \brief A python rpm.ts object represents an RPM transaction set.
27 * The transaction set is the workhorse of RPM. It performs the
28 * installation and upgrade of packages. The rpm.ts object is
29 * instantiated by the TransactionSet function in the rpm module.
31 * The TransactionSet function takes two optional arguments. The first
32 * argument is the root path. The second is the verify signature disable flags,
33 * a set of the following bits:
35 * - rpm.RPMVSF_NOHDRCHK if set, don't check rpmdb headers
36 * - rpm.RPMVSF_NEEDPAYLOAD if not set, check header+payload (if possible)
37 * - rpm.RPMVSF_NOSHA1HEADER if set, don't check header SHA1 digest
38 * - rpm.RPMVSF_NODSAHEADER if set, don't check header DSA signature
39 * - rpm.RPMVSF_NOMD5 if set, don't check header+payload MD5 digest
40 * - rpm.RPMVSF_NODSA if set, don't check header+payload DSA signature
41 * - rpm.RPMVSF_NORSA if set, don't check header+payload RSA signature
43 * For convenience, there are the following masks:
44 * - rpm._RPMVSF_NODIGESTS if set, don't check digest(s).
45 * - rpm._RPMVSF_NOSIGNATURES if set, don't check signature(s).
47 * A rpm.ts object has the following methods:
49 * - addInstall(hdr,data,mode) Add an install element to a transaction set.
50 * @param hdr the header to be added
51 * @param data user data that will be passed to the transaction callback
52 * during transaction execution
53 * @param mode optional argument that specifies if this package should
54 * be installed ('i'), upgraded ('u').
56 * - addErase(name) Add an erase element to a transaction set.
57 * @param name the package name to be erased
59 * - check() Perform a dependency check on the transaction set. After
60 * headers have been added to a transaction set, a dependency
61 * check can be performed to make sure that all package
62 * dependencies are satisfied.
63 * @return None If there are no unresolved dependencies
64 * Otherwise a list of complex tuples is returned, one tuple per
65 * unresolved dependency, with
66 * The format of the dependency tuple is:
67 * ((packageName, packageVersion, packageRelease),
68 * (reqName, reqVersion),
72 * packageName, packageVersion, packageRelease are the name,
73 * version, and release of the package that has the unresolved
74 * dependency or conflict.
75 * The reqName and reqVersion are the name and version of the
76 * requirement or conflict.
77 * The needsFlags is a bitfield that describes the versioned
78 * nature of a requirement or conflict. The constants
79 * rpm.RPMSENSE_LESS, rpm.RPMSENSE_GREATER, and
80 * rpm.RPMSENSE_EQUAL can be logical ANDed with the needsFlags
81 * to get versioned dependency information.
82 * suggestedPackage is a tuple if the dependency check was aware
83 * of a package that solves this dependency problem when the
84 * dependency check was run. Packages that are added to the
85 * transaction set as "available" are examined during the
86 * dependency check as possible dependency solvers. The tuple
87 * contains two values, (header, suggestedName). These are set to
88 * the header of the suggested package and its name, respectively.
89 * If there is no known package to solve the dependency problem,
90 * suggestedPackage is None.
91 * The constants rpm.RPMDEP_SENSE_CONFLICTS and
92 * rpm.RPMDEP_SENSE_REQUIRES are set to show a dependency as a
93 * requirement or a conflict.
95 * - ts.order() Do a topological sort of added element relations.
98 * - ts.setFlags(transFlags) Set transaction set flags.
99 * @param transFlags - bit(s) to controll transaction operations. The
100 * following values can be logically OR'ed together:
101 * - rpm.RPMTRANS_FLAG_TEST - test mode, do not modify the RPM
102 * database, change any files, or run any package scripts
103 * - rpm.RPMTRANS_FLAG_BUILD_PROBS - only build a list of
104 * problems encountered when attempting to run this transaction
106 * - rpm.RPMTRANS_FLAG_NOSCRIPTS - do not execute package scripts
107 * - rpm.RPMTRANS_FLAG_JUSTDB - only make changes to the rpm
108 * database, do not modify files.
109 * - rpm.RPMTRANS_FLAG_NOTRIGGERS - do not run trigger scripts
110 * - rpm.RPMTRANS_FLAG_NODOCS - do not install files marked as %doc
111 * - rpm.RPMTRANS_FLAG_ALLFILES - create all files, even if a
112 * file is marked %config(missingok) and an upgrade is
114 * - rpm.RPMTRANS_FLAG_KEEPOBSOLETE - do not remove obsoleted
116 * @return previous transFlags
118 * - ts.setProbFilter(ignoreSet) Set transaction set problem filter.
119 * @param problemSetFilter - control bit(s) to ignore classes of problems,
120 * a logical or of one or more of the following bit(s):
121 * - rpm.RPMPROB_FILTER_IGNOREOS -
122 * - rpm.RPMPROB_FILTER_IGNOREARCH -
123 * - rpm.RPMPROB_FILTER_REPLACEPKG -
124 * - rpm.RPMPROB_FILTER_FORCERELOCATE -
125 * - rpm.RPMPROB_FILTER_REPLACENEWFILES -
126 * - rpm.RPMPROB_FILTER_REPLACEOLDFILES -
127 * - rpm.RPMPROB_FILTER_OLDPACKAGE -
128 * - rpm.RPMPROB_FILTER_DISKSPACE -
129 * @return previous ignoreSet
131 * - ts.run(callback,data) Attempt to execute a transaction set.
132 * After the transaction set has been populated with install/upgrade or
133 * erase actions, the transaction set can be executed by invoking
134 * the ts.run() method.
137 struct rpmtsObject_s {
139 PyObject *md_dict; /*!< to look like PyModuleObject */
140 rpmfdObject *scriptFd;
146 struct rpmtsCallbackType_s {
150 PyThreadState *_save;
154 static void die(PyObject *cb)
159 if (PyErr_Occurred()) {
162 if ((r = PyObject_Repr(cb)) != NULL) {
163 pyfn = PyBytes_AsString(r);
165 fprintf(stderr, "FATAL ERROR: python callback %s failed, aborting!\n",
166 pyfn ? pyfn : "???");
167 rpmdbCheckTerminate(1);
172 rpmts_AddInstall(rpmtsObject * s, PyObject * args)
179 if (!PyArg_ParseTuple(args, "O&Oi:AddInstall",
180 hdrFromPyObject, &h, &key, &how))
183 rc = rpmtsAddInstallElement(s->ts, h, key, how, NULL);
184 if (key && rc == 0) {
185 PyList_Append(s->keyList, key);
187 return PyBool_FromLong((rc == 0));
191 rpmts_AddErase(rpmtsObject * s, PyObject * args)
195 if (!PyArg_ParseTuple(args, "O&:AddErase", hdrFromPyObject, &h))
198 return PyBool_FromLong(rpmtsAddEraseElement(s->ts, h, -1) == 0);
202 rpmts_SolveCallback(rpmts ts, rpmds ds, const void * data)
204 struct rpmtsCallbackType_s * cbInfo = (struct rpmtsCallbackType_s *) data;
205 PyObject * args, * result;
208 if (cbInfo->tso == NULL) return res;
209 if (cbInfo->cb == Py_None) return res;
211 PyEval_RestoreThread(cbInfo->_save);
213 args = Py_BuildValue("(Oissi)", cbInfo->tso,
214 rpmdsTagN(ds), rpmdsN(ds), rpmdsEVR(ds), rpmdsFlags(ds));
215 result = PyEval_CallObject(cbInfo->cb, args);
221 if (PyInt_Check(result))
222 res = PyInt_AsLong(result);
226 cbInfo->_save = PyEval_SaveThread();
232 rpmts_Check(rpmtsObject * s, PyObject * args, PyObject * kwds)
234 struct rpmtsCallbackType_s cbInfo;
236 char * kwlist[] = {"callback", NULL};
238 memset(&cbInfo, 0, sizeof(cbInfo));
239 if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O:Check", kwlist,
243 if (cbInfo.cb != NULL) {
244 if (!PyCallable_Check(cbInfo.cb)) {
245 PyErr_SetString(PyExc_TypeError, "expected a callable");
248 rc = rpmtsSetSolveCallback(s->ts, rpmts_SolveCallback, (void *)&cbInfo);
252 cbInfo._save = PyEval_SaveThread();
254 rc = rpmtsCheck(s->ts);
256 PyEval_RestoreThread(cbInfo._save);
258 return PyBool_FromLong((rc == 0));
262 rpmts_Order(rpmtsObject * s)
266 Py_BEGIN_ALLOW_THREADS
267 rc = rpmtsOrder(s->ts);
270 return Py_BuildValue("i", rc);
274 rpmts_Clean(rpmtsObject * s)
282 rpmts_Clear(rpmtsObject * s)
290 rpmts_OpenDB(rpmtsObject * s)
294 dbmode = rpmtsGetDBMode(s->ts);
298 return Py_BuildValue("i", rpmtsOpenDB(s->ts, dbmode));
302 rpmts_CloseDB(rpmtsObject * s)
306 rc = rpmtsCloseDB(s->ts);
307 rpmtsSetDBMode(s->ts, -1); /* XXX disable lazy opens */
309 return Py_BuildValue("i", rc);
313 rpmts_InitDB(rpmtsObject * s)
317 rc = rpmtsInitDB(s->ts, O_RDONLY);
319 rc = rpmtsCloseDB(s->ts);
321 return Py_BuildValue("i", rc);
325 rpmts_RebuildDB(rpmtsObject * s)
329 Py_BEGIN_ALLOW_THREADS
330 rc = rpmtsRebuildDB(s->ts);
333 return Py_BuildValue("i", rc);
337 rpmts_VerifyDB(rpmtsObject * s)
341 Py_BEGIN_ALLOW_THREADS
342 rc = rpmtsVerifyDB(s->ts);
345 return Py_BuildValue("i", rc);
349 rpmts_HdrFromFdno(rpmtsObject * s, PyObject *arg)
352 rpmfdObject *fdo = NULL;
356 if (!PyArg_Parse(arg, "O&:HdrFromFdno", rpmfdFromPyObject, &fdo))
359 Py_BEGIN_ALLOW_THREADS;
360 rpmrc = rpmReadPackageFile(s->ts, rpmfdGetFd(fdo), NULL, &h);
361 Py_END_ALLOW_THREADS;
364 if (rpmrc == RPMRC_OK) {
365 ho = hdr_Wrap(&hdr_Type, h);
366 h = headerFree(h); /* ref held by python object */
371 return Py_BuildValue("(iN)", rpmrc, ho);
375 rpmts_HdrCheck(rpmtsObject * s, PyObject *obj)
383 if (!PyArg_Parse(obj, "S:HdrCheck", &blob))
386 uh = PyBytes_AsString(blob);
387 uc = PyBytes_Size(blob);
389 Py_BEGIN_ALLOW_THREADS;
390 rpmrc = headerCheck(s->ts, uh, uc, &msg);
391 Py_END_ALLOW_THREADS;
393 return Py_BuildValue("(is)", rpmrc, msg);
397 rpmts_PgpPrtPkts(rpmtsObject * s, PyObject * args, PyObject * kwds)
403 char * kwlist[] = {"octets", NULL};
405 if (!PyArg_ParseTupleAndKeywords(args, kwds, "S:PgpPrtPkts", kwlist, &blob))
408 pkt = (unsigned char *)PyBytes_AsString(blob);
409 pktlen = PyBytes_Size(blob);
411 rc = pgpPrtPkts(pkt, pktlen, NULL, 1);
413 return Py_BuildValue("i", rc);
417 rpmts_PgpImportPubkey(rpmtsObject * s, PyObject * args, PyObject * kwds)
423 char * kwlist[] = {"pubkey", NULL};
425 if (!PyArg_ParseTupleAndKeywords(args, kwds, "S:PgpImportPubkey",
429 pkt = (unsigned char *)PyBytes_AsString(blob);
430 pktlen = PyBytes_Size(blob);
432 rc = rpmtsImportPubkey(s->ts, pkt, pktlen);
434 return Py_BuildValue("i", rc);
437 static PyObject *rpmts_setKeyring(rpmtsObject *s, PyObject *arg)
439 rpmKeyring keyring = NULL;
440 if (arg == Py_None || rpmKeyringFromPyObject(arg, &keyring)) {
441 return PyBool_FromLong(rpmtsSetKeyring(s->ts, keyring) == 0);
443 PyErr_SetString(PyExc_TypeError, "rpm.keyring or None expected");
448 static PyObject *rpmts_getKeyring(rpmtsObject *s, PyObject *args, PyObject *kwds)
450 rpmKeyring keyring = NULL;
452 char * kwlist[] = { "autoload", NULL };
454 if (!PyArg_ParseTupleAndKeywords(args, kwds, "|i:getKeyring",
458 keyring = rpmtsGetKeyring(s->ts, autoload);
460 return rpmKeyring_Wrap(&rpmKeyring_Type, keyring);
467 rpmtsCallback(const void * hd, const rpmCallbackType what,
468 const rpm_loff_t amount, const rpm_loff_t total,
469 const void * pkgKey, rpmCallbackData data)
471 Header h = (Header) hd;
472 struct rpmtsCallbackType_s * cbInfo = data;
473 PyObject * pkgObj = (PyObject *) pkgKey;
474 PyObject * args, * result;
477 if (cbInfo->cb == Py_None) return NULL;
479 /* Synthesize a python object for callback (if necessary). */
480 if (pkgObj == NULL) {
482 pkgObj = Py_BuildValue("s", headerGetString(h, RPMTAG_NAME));
490 PyEval_RestoreThread(cbInfo->_save);
492 args = Py_BuildValue("(iLLOO)", what, amount, total, pkgObj, cbInfo->data);
493 result = PyEval_CallObject(cbInfo->cb, args);
501 if (what == RPMCALLBACK_INST_OPEN_FILE) {
504 if (!PyArg_Parse(result, "i", &fdno)) {
508 cbInfo->_save = PyEval_SaveThread();
511 fcntl(Fileno(fd), F_SETFD, FD_CLOEXEC);
515 if (what == RPMCALLBACK_INST_CLOSE_FILE) {
520 cbInfo->_save = PyEval_SaveThread();
526 rpmts_Problems(rpmtsObject * s)
528 rpmps ps = rpmtsProblems(s->ts);
529 PyObject *problems = rpmps_AsList(ps);
535 rpmts_Run(rpmtsObject * s, PyObject * args, PyObject * kwds)
538 struct rpmtsCallbackType_s cbInfo;
539 rpmprobFilterFlags ignoreSet;
540 char * kwlist[] = {"callback", "data", "ignoreSet", NULL};
542 if (!PyArg_ParseTupleAndKeywords(args, kwds, "OOi:Run", kwlist,
543 &cbInfo.cb, &cbInfo.data, &ignoreSet))
547 cbInfo._save = PyEval_SaveThread();
549 if (cbInfo.cb != NULL) {
550 if (!PyCallable_Check(cbInfo.cb)) {
551 PyErr_SetString(PyExc_TypeError, "expected a callable");
554 (void) rpmtsSetNotifyCallback(s->ts, rpmtsCallback, (void *) &cbInfo);
557 rc = rpmtsRun(s->ts, NULL, ignoreSet);
560 (void) rpmtsSetNotifyCallback(s->ts, NULL, NULL);
562 PyEval_RestoreThread(cbInfo._save);
564 return Py_BuildValue("i", rc);
568 rpmts_iternext(rpmtsObject * s)
570 PyObject * result = NULL;
573 /* Reset iterator on 1st entry. */
574 if (s->tsi == NULL) {
575 s->tsi = rpmtsiInit(s->ts);
580 te = rpmtsiNext(s->tsi, 0);
582 result = rpmte_Wrap(&rpmte_Type, te);
584 s->tsi = rpmtsiFree(s->tsi);
591 rpmts_Match(rpmtsObject * s, PyObject * args, PyObject * kwds)
593 PyObject *Key = NULL;
594 PyObject *str = NULL;
595 PyObject *mio = NULL;
597 /* XXX lkey *must* be a 32 bit integer, int "works" on all known platforms. */
600 rpmDbiTagVal tag = RPMDBI_PACKAGES;
601 char * kwlist[] = {"tagNumber", "key", NULL};
603 if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O&O:Match", kwlist,
604 tagNumFromPyObject, &tag, &Key))
608 if (PyInt_Check(Key)) {
609 lkey = PyInt_AsLong(Key);
612 } else if (utf8FromPyObject(Key, &str)) {
613 key = PyBytes_AsString(str);
614 len = PyBytes_Size(str);
616 PyErr_SetString(PyExc_TypeError, "unknown key type");
619 /* One of the conversions above failed, exception is set already */
620 if (PyErr_Occurred()) goto exit;
623 /* XXX If not already opened, open the database O_RDONLY now. */
624 /* XXX FIXME: lazy default rdonly open also done by rpmtsInitIterator(). */
625 if (rpmtsGetRdb(s->ts) == NULL) {
626 int rc = rpmtsOpenDB(s->ts, O_RDONLY);
627 if (rc || rpmtsGetRdb(s->ts) == NULL) {
628 PyErr_SetString(pyrpmError, "rpmdb open failed");
633 mio = rpmmi_Wrap(&rpmmi_Type, rpmtsInitIterator(s->ts, tag, key, len), (PyObject*)s);
640 rpmts_index(rpmtsObject * s, PyObject * args, PyObject * kwds)
643 PyObject *mio = NULL;
644 char * kwlist[] = {"tag", NULL};
646 if (!PyArg_ParseTupleAndKeywords(args, kwds, "O&:Keys", kwlist,
647 tagNumFromPyObject, &tag))
650 /* XXX If not already opened, open the database O_RDONLY now. */
651 if (rpmtsGetRdb(s->ts) == NULL) {
652 int rc = rpmtsOpenDB(s->ts, O_RDONLY);
653 if (rc || rpmtsGetRdb(s->ts) == NULL) {
654 PyErr_SetString(pyrpmError, "rpmdb open failed");
659 rpmdbIndexIterator ii = rpmdbIndexIteratorInit(rpmtsGetRdb(s->ts), tag);
661 PyErr_SetString(PyExc_KeyError, "No index for this tag");
664 mio = rpmii_Wrap(&rpmii_Type, ii, (PyObject*)s);
670 static struct PyMethodDef rpmts_methods[] = {
671 {"addInstall", (PyCFunction) rpmts_AddInstall, METH_VARARGS,
673 {"addErase", (PyCFunction) rpmts_AddErase, METH_VARARGS|METH_KEYWORDS,
675 {"check", (PyCFunction) rpmts_Check, METH_VARARGS|METH_KEYWORDS,
677 {"order", (PyCFunction) rpmts_Order, METH_NOARGS,
679 {"problems", (PyCFunction) rpmts_Problems, METH_NOARGS,
680 "ts.problems() -> ps\n\
681 - Return current problem set.\n" },
682 {"run", (PyCFunction) rpmts_Run, METH_VARARGS|METH_KEYWORDS,
683 "ts.run(callback, data) -> (problems)\n\
684 - Run a transaction set, returning list of problems found.\n\
685 Note: The callback may not be None.\n" },
686 {"clean", (PyCFunction) rpmts_Clean, METH_NOARGS,
688 {"clear", (PyCFunction) rpmts_Clear, METH_NOARGS,
689 "ts.clear() -> None\n\
690 Remove all elements from the transaction set\n" },
691 {"openDB", (PyCFunction) rpmts_OpenDB, METH_NOARGS,
692 "ts.openDB() -> None\n\
693 - Open the default transaction rpmdb.\n\
694 Note: The transaction rpmdb is lazily opened, so ts.openDB() is seldom needed.\n" },
695 {"closeDB", (PyCFunction) rpmts_CloseDB, METH_NOARGS,
696 "ts.closeDB() -> None\n\
697 - Close the default transaction rpmdb.\n\
698 Note: ts.closeDB() disables lazy opens, and should hardly ever be used.\n" },
699 {"initDB", (PyCFunction) rpmts_InitDB, METH_NOARGS,
700 "ts.initDB() -> None\n\
701 - Initialize the default transaction rpmdb.\n\
702 Note: ts.initDB() is seldom needed anymore.\n" },
703 {"rebuildDB", (PyCFunction) rpmts_RebuildDB, METH_NOARGS,
704 "ts.rebuildDB() -> None\n\
705 - Rebuild the default transaction rpmdb.\n" },
706 {"verifyDB", (PyCFunction) rpmts_VerifyDB, METH_NOARGS,
707 "ts.verifyDB() -> None\n\
708 - Verify the default transaction rpmdb.\n" },
709 {"hdrFromFdno",(PyCFunction) rpmts_HdrFromFdno,METH_O,
710 "ts.hdrFromFdno(fdno) -> hdr\n\
711 - Read a package header from a file descriptor.\n" },
712 {"hdrCheck", (PyCFunction) rpmts_HdrCheck, METH_O,
714 {"pgpPrtPkts", (PyCFunction) rpmts_PgpPrtPkts, METH_VARARGS|METH_KEYWORDS,
716 {"pgpImportPubkey", (PyCFunction) rpmts_PgpImportPubkey, METH_VARARGS|METH_KEYWORDS,
718 {"getKeyring", (PyCFunction) rpmts_getKeyring, METH_VARARGS|METH_KEYWORDS,
720 {"setKeyring", (PyCFunction) rpmts_setKeyring, METH_O,
722 {"dbMatch", (PyCFunction) rpmts_Match, METH_VARARGS|METH_KEYWORDS,
723 "ts.dbMatch([TagN, [key]]) -> mi\n\
724 - Create a match iterator for the default transaction rpmdb.\n" },
725 {"dbIndex", (PyCFunction) rpmts_index, METH_VARARGS|METH_KEYWORDS,
726 "ts.dbIndex(TagN) -> ii\n\
727 - Create a key iterator for the default transaction rpmdb.\n" },
728 {NULL, NULL} /* sentinel */
731 static void rpmts_dealloc(rpmtsObject * s)
734 s->ts = rpmtsFree(s->ts);
735 Py_XDECREF(s->scriptFd);
736 Py_XDECREF(s->keyList);
737 Py_TYPE(s)->tp_free((PyObject *)s);
740 static PyObject * rpmts_new(PyTypeObject * subtype, PyObject *args, PyObject *kwds)
742 rpmtsObject * s = (rpmtsObject *)subtype->tp_alloc(subtype, 0);
743 if (s == NULL) return NULL;
745 s->ts = rpmtsCreate();
748 s->keyList = PyList_New(0);
749 return (PyObject *) s;
752 static int rpmts_init(rpmtsObject *s, PyObject *args, PyObject *kwds)
754 const char * rootDir = "/";
755 rpmVSFlags vsflags = rpmExpandNumeric("%{?__vsflags}");
756 char * kwlist[] = {"rootdir", "vsflags", 0};
758 if (!PyArg_ParseTupleAndKeywords(args, kwds, "|si:rpmts_new", kwlist,
762 (void) rpmtsSetRootDir(s->ts, rootDir);
763 /* XXX: make this use common code with rpmts_SetVSFlags() to check the
765 (void) rpmtsSetVSFlags(s->ts, vsflags);
770 static PyObject *rpmts_get_tid(rpmtsObject *s, void *closure)
772 return Py_BuildValue("i", rpmtsGetTid(s->ts));
775 static PyObject *rpmts_get_rootDir(rpmtsObject *s, void *closure)
777 return Py_BuildValue("s", rpmtsRootDir(s->ts));
780 static int rpmts_set_scriptFd(rpmtsObject *s, PyObject *value, void *closure)
782 rpmfdObject *fdo = NULL;
784 if (PyArg_Parse(value, "O&", rpmfdFromPyObject, &fdo)) {
785 Py_XDECREF(s->scriptFd);
787 rpmtsSetScriptFd(s->ts, rpmfdGetFd(s->scriptFd));
788 } else if (value == Py_None) {
789 Py_XDECREF(s->scriptFd);
791 rpmtsSetScriptFd(s->ts, NULL);
798 static PyObject *rpmts_get_color(rpmtsObject *s, void *closure)
800 return Py_BuildValue("i", rpmtsColor(s->ts));
803 static PyObject *rpmts_get_prefcolor(rpmtsObject *s, void *closure)
805 return Py_BuildValue("i", rpmtsPrefColor(s->ts));
808 static int rpmts_set_color(rpmtsObject *s, PyObject *value, void *closure)
811 if (!PyArg_Parse(value, "i", &color)) return -1;
813 /* TODO: validate the bits */
814 rpmtsSetColor(s->ts, color);
818 static int rpmts_set_prefcolor(rpmtsObject *s, PyObject *value, void *closure)
821 if (!PyArg_Parse(value, "i", &color)) return -1;
823 /* TODO: validate the bits */
824 rpmtsSetPrefColor(s->ts, color);
828 static int rpmts_set_flags(rpmtsObject *s, PyObject *value, void *closure)
831 if (!PyArg_Parse(value, "i", &flags)) return -1;
833 /* TODO: validate the bits */
834 rpmtsSetFlags(s->ts, flags);
838 static int rpmts_set_vsflags(rpmtsObject *s, PyObject *value, void *closure)
841 if (!PyArg_Parse(value, "i", &flags)) return -1;
843 /* TODO: validate the bits */
844 rpmtsSetVSFlags(s->ts, flags);
848 static PyObject *rpmts_get_flags(rpmtsObject *s, void *closure)
850 return Py_BuildValue("i", rpmtsFlags(s->ts));
853 static PyObject *rpmts_get_vsflags(rpmtsObject *s, void *closure)
855 return Py_BuildValue("i", rpmtsVSFlags(s->ts));
858 static char rpmts_doc[] =
861 static PyGetSetDef rpmts_getseters[] = {
862 /* only provide a setter until we have rpmfd wrappings */
863 {"scriptFd", NULL, (setter)rpmts_set_scriptFd, NULL },
864 {"tid", (getter)rpmts_get_tid, NULL, NULL },
865 {"rootDir", (getter)rpmts_get_rootDir, NULL, NULL },
866 {"_color", (getter)rpmts_get_color, (setter)rpmts_set_color, NULL},
867 {"_prefcolor", (getter)rpmts_get_prefcolor, (setter)rpmts_set_prefcolor, NULL},
868 {"_flags", (getter)rpmts_get_flags, (setter)rpmts_set_flags, NULL},
869 {"_vsflags", (getter)rpmts_get_vsflags, (setter)rpmts_set_vsflags, NULL},
873 PyTypeObject rpmts_Type = {
874 PyVarObject_HEAD_INIT(&PyType_Type, 0)
875 "rpm.ts", /* tp_name */
876 sizeof(rpmtsObject), /* tp_size */
878 (destructor) rpmts_dealloc, /* tp_dealloc */
880 (getattrfunc)0, /* tp_getattr */
881 (setattrfunc)0, /* tp_setattr */
884 0, /* tp_as_number */
885 0, /* tp_as_sequence */
886 0, /* tp_as_mapping */
890 PyObject_GenericGetAttr, /* tp_getattro */
891 PyObject_GenericSetAttr, /* tp_setattro */
892 0, /* tp_as_buffer */
893 Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, /* tp_flags */
894 rpmts_doc, /* tp_doc */
897 0, /* tp_richcompare */
898 0, /* tp_weaklistoffset */
899 PyObject_SelfIter, /* tp_iter */
900 (iternextfunc) rpmts_iternext, /* tp_iternext */
901 rpmts_methods, /* tp_methods */
903 rpmts_getseters, /* tp_getset */
906 0, /* tp_descr_get */
907 0, /* tp_descr_set */
908 0, /* tp_dictoffset */
909 (initproc) rpmts_init, /* tp_init */
911 (newfunc) rpmts_new, /* tp_new */