[4.0] Use strip (instead of eu-strip) to support --strip-debug of *.so at build time
[platform/upstream/rpm.git] / python / rpmts-py.c
1 #include "rpmsystem-py.h"
2
3 #include <fcntl.h>
4
5 #include <rpm/rpmlib.h> /* rpmReadPackageFile, headerCheck */
6 #include <rpm/rpmtag.h>
7 #include <rpm/rpmpgp.h>
8 #include <rpm/rpmdb.h>
9 #include <rpm/rpmbuild.h>
10
11 #include "header-py.h"
12 #include "rpmds-py.h"   /* XXX for rpmdsNew */
13 #include "rpmfd-py.h"
14 #include "rpmkeyring-py.h"
15 #include "rpmfi-py.h"   /* XXX for rpmfiNew */
16 #include "rpmmi-py.h"
17 #include "rpmii-py.h"
18 #include "rpmps-py.h"
19 #include "rpmte-py.h"
20 #include "rpmts-py.h"
21
22 /** \ingroup python
23  * \name Class: Rpmts
24  * \class Rpmts
25  * \brief A python rpm.ts object represents an RPM transaction set.
26  *
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.
30  *
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:
34  *
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
42  *
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).
46  *
47  * A rpm.ts object has the following methods:
48  *
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').
55  *
56  * - addErase(name) Add an erase element to a transaction set.
57  * @param name  the package name to be erased
58  *
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),
69  *      needsFlags,
70  *      suggestedPackage,
71  *      sense)
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.
94  *
95  * - ts.order() Do a topological sort of added element relations.
96  * @return      None
97  *
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
105  *              set
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
113  *              being performed.
114  *      - rpm.RPMTRANS_FLAG_KEEPOBSOLETE - do not remove obsoleted
115  *              packages.
116  * @return      previous transFlags
117  *
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
130  *
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.
135  */
136
137 struct rpmtsObject_s {
138     PyObject_HEAD
139     PyObject *md_dict;          /*!< to look like PyModuleObject */
140     rpmfdObject *scriptFd;
141     PyObject *keyList;
142     rpmts       ts;
143     rpmtsi tsi;
144 };
145
146 struct rpmtsCallbackType_s {
147     PyObject * cb;
148     PyObject * data;
149     rpmtsObject * tso;
150     PyThreadState *_save;
151 };
152
153 RPM_GNUC_NORETURN
154 static void die(PyObject *cb)
155 {
156     char *pyfn = NULL;
157     PyObject *r;
158
159     if (PyErr_Occurred()) {
160         PyErr_Print();
161     }
162     if ((r = PyObject_Repr(cb)) != NULL) { 
163         pyfn = PyBytes_AsString(r);
164     }
165     fprintf(stderr, "FATAL ERROR: python callback %s failed, aborting!\n", 
166                       pyfn ? pyfn : "???");
167     rpmdbCheckTerminate(1);
168     exit(EXIT_FAILURE);
169 }
170
171 static PyObject *
172 rpmts_AddInstall(rpmtsObject * s, PyObject * args)
173 {
174     Header h = NULL;
175     PyObject * key;
176     int how = 0;
177     int rc;
178
179     if (!PyArg_ParseTuple(args, "O&Oi:AddInstall", 
180                           hdrFromPyObject, &h, &key, &how))
181         return NULL;
182
183     rc = rpmtsAddInstallElement(s->ts, h, key, how, NULL);
184     if (key && rc == 0) {
185         PyList_Append(s->keyList, key);
186     }
187     return PyBool_FromLong((rc == 0));
188 }
189
190 static PyObject *
191 rpmts_AddErase(rpmtsObject * s, PyObject * args)
192 {
193     Header h;
194
195     if (!PyArg_ParseTuple(args, "O&:AddErase", hdrFromPyObject, &h))
196         return NULL;
197
198     return PyBool_FromLong(rpmtsAddEraseElement(s->ts, h, -1) == 0);
199 }
200
201 static int
202 rpmts_SolveCallback(rpmts ts, rpmds ds, const void * data)
203 {
204     struct rpmtsCallbackType_s * cbInfo = (struct rpmtsCallbackType_s *) data;
205     PyObject * args, * result;
206     int res = 1;
207
208     if (cbInfo->tso == NULL) return res;
209     if (cbInfo->cb == Py_None) return res;
210
211     PyEval_RestoreThread(cbInfo->_save);
212
213     args = Py_BuildValue("(Oissi)", cbInfo->tso,
214                 rpmdsTagN(ds), rpmdsN(ds), rpmdsEVR(ds), rpmdsFlags(ds));
215     result = PyEval_CallObject(cbInfo->cb, args);
216     Py_DECREF(args);
217
218     if (!result) {
219         die(cbInfo->cb);
220     } else {
221         if (PyInt_Check(result))
222             res = PyInt_AsLong(result);
223         Py_DECREF(result);
224     }
225
226     cbInfo->_save = PyEval_SaveThread();
227
228     return res;
229 }
230
231 static PyObject *
232 rpmts_Check(rpmtsObject * s, PyObject * args, PyObject * kwds)
233 {
234     struct rpmtsCallbackType_s cbInfo;
235     int rc;
236     char * kwlist[] = {"callback", NULL};
237
238     memset(&cbInfo, 0, sizeof(cbInfo));
239     if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O:Check", kwlist,
240             &cbInfo.cb))
241         return NULL;
242
243     if (cbInfo.cb != NULL) {
244         if (!PyCallable_Check(cbInfo.cb)) {
245             PyErr_SetString(PyExc_TypeError, "expected a callable");
246             return NULL;
247         }
248         rc = rpmtsSetSolveCallback(s->ts, rpmts_SolveCallback, (void *)&cbInfo);
249     }
250
251     cbInfo.tso = s;
252     cbInfo._save = PyEval_SaveThread();
253
254     rc = rpmtsCheck(s->ts);
255
256     PyEval_RestoreThread(cbInfo._save);
257
258     return PyBool_FromLong((rc == 0));
259 }
260
261 static PyObject *
262 rpmts_Order(rpmtsObject * s)
263 {
264     int rc;
265
266     Py_BEGIN_ALLOW_THREADS
267     rc = rpmtsOrder(s->ts);
268     Py_END_ALLOW_THREADS
269
270     return Py_BuildValue("i", rc);
271 }
272
273 static PyObject *
274 rpmts_Clean(rpmtsObject * s)
275 {
276     rpmtsClean(s->ts);
277
278     Py_RETURN_NONE;
279 }
280
281 static PyObject *
282 rpmts_Clear(rpmtsObject * s)
283 {
284     rpmtsEmpty(s->ts);
285
286     Py_RETURN_NONE;
287 }
288
289 static PyObject *
290 rpmts_OpenDB(rpmtsObject * s)
291 {
292     int dbmode;
293
294     dbmode = rpmtsGetDBMode(s->ts);
295     if (dbmode == -1)
296         dbmode = O_RDONLY;
297
298     return Py_BuildValue("i", rpmtsOpenDB(s->ts, dbmode));
299 }
300
301 static PyObject *
302 rpmts_CloseDB(rpmtsObject * s)
303 {
304     int rc;
305
306     rc = rpmtsCloseDB(s->ts);
307     rpmtsSetDBMode(s->ts, -1);  /* XXX disable lazy opens */
308
309     return Py_BuildValue("i", rc);
310 }
311
312 static PyObject *
313 rpmts_InitDB(rpmtsObject * s)
314 {
315     int rc;
316
317     rc = rpmtsInitDB(s->ts, O_RDONLY);
318     if (rc == 0)
319         rc = rpmtsCloseDB(s->ts);
320
321     return Py_BuildValue("i", rc);
322 }
323
324 static PyObject *
325 rpmts_RebuildDB(rpmtsObject * s)
326 {
327     int rc;
328
329     Py_BEGIN_ALLOW_THREADS
330     rc = rpmtsRebuildDB(s->ts);
331     Py_END_ALLOW_THREADS
332
333     return Py_BuildValue("i", rc);
334 }
335
336 static PyObject *
337 rpmts_VerifyDB(rpmtsObject * s)
338 {
339     int rc;
340
341     Py_BEGIN_ALLOW_THREADS
342     rc = rpmtsVerifyDB(s->ts);
343     Py_END_ALLOW_THREADS
344
345     return Py_BuildValue("i", rc);
346 }
347
348 static PyObject *
349 rpmts_HdrFromFdno(rpmtsObject * s, PyObject *arg)
350 {
351     PyObject *ho = NULL;
352     rpmfdObject *fdo = NULL;
353     Header h;
354     rpmRC rpmrc;
355
356     if (!PyArg_Parse(arg, "O&:HdrFromFdno", rpmfdFromPyObject, &fdo))
357         return NULL;
358
359     Py_BEGIN_ALLOW_THREADS;
360     rpmrc = rpmReadPackageFile(s->ts, rpmfdGetFd(fdo), NULL, &h);
361     Py_END_ALLOW_THREADS;
362     Py_XDECREF(fdo);
363
364     if (rpmrc == RPMRC_OK) {
365         ho = hdr_Wrap(&hdr_Type, h);
366         h = headerFree(h); /* ref held by python object */
367     } else {
368         Py_INCREF(Py_None);
369         ho = Py_None;
370     }
371     return Py_BuildValue("(iN)", rpmrc, ho);
372 }
373
374 static PyObject *
375 rpmts_HdrCheck(rpmtsObject * s, PyObject *obj)
376 {
377     PyObject * blob;
378     char * msg = NULL;
379     const void * uh;
380     int uc;
381     rpmRC rpmrc;
382
383     if (!PyArg_Parse(obj, "S:HdrCheck", &blob))
384         return NULL;
385
386     uh = PyBytes_AsString(blob);
387     uc = PyBytes_Size(blob);
388
389     Py_BEGIN_ALLOW_THREADS;
390     rpmrc = headerCheck(s->ts, uh, uc, &msg);
391     Py_END_ALLOW_THREADS;
392
393     return Py_BuildValue("(is)", rpmrc, msg);
394 }
395
396 static PyObject *
397 rpmts_PgpPrtPkts(rpmtsObject * s, PyObject * args, PyObject * kwds)
398 {
399     PyObject * blob;
400     unsigned char * pkt;
401     unsigned int pktlen;
402     int rc;
403     char * kwlist[] = {"octets", NULL};
404
405     if (!PyArg_ParseTupleAndKeywords(args, kwds, "S:PgpPrtPkts", kwlist, &blob))
406         return NULL;
407
408     pkt = (unsigned char *)PyBytes_AsString(blob);
409     pktlen = PyBytes_Size(blob);
410
411     rc = pgpPrtPkts(pkt, pktlen, NULL, 1);
412
413     return Py_BuildValue("i", rc);
414 }
415
416 static PyObject *
417 rpmts_PgpImportPubkey(rpmtsObject * s, PyObject * args, PyObject * kwds)
418 {
419     PyObject * blob;
420     unsigned char * pkt;
421     unsigned int pktlen;
422     int rc;
423     char * kwlist[] = {"pubkey", NULL};
424
425     if (!PyArg_ParseTupleAndKeywords(args, kwds, "S:PgpImportPubkey",
426             kwlist, &blob))
427         return NULL;
428
429     pkt = (unsigned char *)PyBytes_AsString(blob);
430     pktlen = PyBytes_Size(blob);
431
432     rc = rpmtsImportPubkey(s->ts, pkt, pktlen);
433
434     return Py_BuildValue("i", rc);
435 }
436
437 static PyObject *rpmts_setKeyring(rpmtsObject *s, PyObject *arg)
438 {
439     rpmKeyring keyring = NULL;
440     if (arg == Py_None || rpmKeyringFromPyObject(arg, &keyring)) {
441         return PyBool_FromLong(rpmtsSetKeyring(s->ts, keyring) == 0);
442     } else {
443         PyErr_SetString(PyExc_TypeError, "rpm.keyring or None expected");
444         return NULL;
445     }
446 }
447
448 static PyObject *rpmts_getKeyring(rpmtsObject *s, PyObject *args, PyObject *kwds)
449 {
450     rpmKeyring keyring = NULL;
451     int autoload = 1;
452     char * kwlist[] = { "autoload", NULL };
453
454     if (!PyArg_ParseTupleAndKeywords(args, kwds, "|i:getKeyring",
455                                      kwlist, &autoload))
456         return NULL;
457
458     keyring = rpmtsGetKeyring(s->ts, autoload);
459     if (keyring) {
460         return rpmKeyring_Wrap(&rpmKeyring_Type, keyring);
461     } else {
462         Py_RETURN_NONE;
463     }
464 }
465
466 static void *
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)
470 {
471     Header h = (Header) hd;
472     struct rpmtsCallbackType_s * cbInfo = data;
473     PyObject * pkgObj = (PyObject *) pkgKey;
474     PyObject * args, * result;
475     static FD_t fd;
476
477     if (cbInfo->cb == Py_None) return NULL;
478
479     /* Synthesize a python object for callback (if necessary). */
480     if (pkgObj == NULL) {
481         if (h) {
482             pkgObj = Py_BuildValue("s", headerGetString(h, RPMTAG_NAME));
483         } else {
484             pkgObj = Py_None;
485             Py_INCREF(pkgObj);
486         }
487     } else
488         Py_INCREF(pkgObj);
489
490     PyEval_RestoreThread(cbInfo->_save);
491
492     args = Py_BuildValue("(iLLOO)", what, amount, total, pkgObj, cbInfo->data);
493     result = PyEval_CallObject(cbInfo->cb, args);
494     Py_DECREF(args);
495     Py_DECREF(pkgObj);
496
497     if (!result) {
498         die(cbInfo->cb);
499     }
500
501     if (what == RPMCALLBACK_INST_OPEN_FILE) {
502         int fdno;
503
504         if (!PyArg_Parse(result, "i", &fdno)) {
505             die(cbInfo->cb);
506         }
507         Py_DECREF(result);
508         cbInfo->_save = PyEval_SaveThread();
509
510         fd = fdDup(fdno);
511         fcntl(Fileno(fd), F_SETFD, FD_CLOEXEC);
512
513         return fd;
514     } else
515     if (what == RPMCALLBACK_INST_CLOSE_FILE) {
516         Fclose (fd);
517     }
518
519     Py_DECREF(result);
520     cbInfo->_save = PyEval_SaveThread();
521
522     return NULL;
523 }
524
525 static PyObject *
526 rpmts_Problems(rpmtsObject * s)
527 {
528     rpmps ps = rpmtsProblems(s->ts);
529     PyObject *problems = rpmps_AsList(ps);
530     rpmpsFree(ps);
531     return problems;
532 }
533
534 static PyObject *
535 rpmts_Run(rpmtsObject * s, PyObject * args, PyObject * kwds)
536 {
537     int rc;
538     struct rpmtsCallbackType_s cbInfo;
539     rpmprobFilterFlags ignoreSet;
540     char * kwlist[] = {"callback", "data", "ignoreSet", NULL};
541
542     if (!PyArg_ParseTupleAndKeywords(args, kwds, "OOi:Run", kwlist,
543             &cbInfo.cb, &cbInfo.data, &ignoreSet))
544         return NULL;
545
546     cbInfo.tso = s;
547     cbInfo._save = PyEval_SaveThread();
548
549     if (cbInfo.cb != NULL) {
550         if (!PyCallable_Check(cbInfo.cb)) {
551             PyErr_SetString(PyExc_TypeError, "expected a callable");
552             return NULL;
553         }
554         (void) rpmtsSetNotifyCallback(s->ts, rpmtsCallback, (void *) &cbInfo);
555     }
556
557     rc = rpmtsRun(s->ts, NULL, ignoreSet);
558
559     if (cbInfo.cb)
560         (void) rpmtsSetNotifyCallback(s->ts, NULL, NULL);
561
562     PyEval_RestoreThread(cbInfo._save);
563
564     return Py_BuildValue("i", rc);
565 }
566
567 static PyObject *
568 rpmts_iternext(rpmtsObject * s)
569 {
570     PyObject * result = NULL;
571     rpmte te;
572
573     /* Reset iterator on 1st entry. */
574     if (s->tsi == NULL) {
575         s->tsi = rpmtsiInit(s->ts);
576         if (s->tsi == NULL)
577             return NULL;
578     }
579
580     te = rpmtsiNext(s->tsi, 0);
581     if (te != NULL) {
582         result = rpmte_Wrap(&rpmte_Type, te);
583     } else {
584         s->tsi = rpmtsiFree(s->tsi);
585     }
586
587     return result;
588 }
589
590 static PyObject *
591 rpmts_Match(rpmtsObject * s, PyObject * args, PyObject * kwds)
592 {
593     PyObject *Key = NULL;
594     PyObject *str = NULL;
595     PyObject *mio = NULL;
596     char *key = NULL;
597 /* XXX lkey *must* be a 32 bit integer, int "works" on all known platforms. */
598     int lkey = 0;
599     int len = 0;
600     rpmDbiTagVal tag = RPMDBI_PACKAGES;
601     char * kwlist[] = {"tagNumber", "key", NULL};
602
603     if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O&O:Match", kwlist,
604             tagNumFromPyObject, &tag, &Key))
605         return NULL;
606
607     if (Key) {
608         if (PyInt_Check(Key)) {
609             lkey = PyInt_AsLong(Key);
610             key = (char *)&lkey;
611             len = sizeof(lkey);
612         } else if (utf8FromPyObject(Key, &str)) {
613             key = PyBytes_AsString(str);
614             len = PyBytes_Size(str);
615         } else {
616             PyErr_SetString(PyExc_TypeError, "unknown key type");
617             return NULL;
618         }
619         /* One of the conversions above failed, exception is set already */
620         if (PyErr_Occurred()) goto exit;
621     }
622
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");
629             goto exit;
630         }
631     }
632
633     mio = rpmmi_Wrap(&rpmmi_Type, rpmtsInitIterator(s->ts, tag, key, len), (PyObject*)s);
634
635 exit:
636     Py_XDECREF(str);
637     return mio;
638 }
639 static PyObject *
640 rpmts_index(rpmtsObject * s, PyObject * args, PyObject * kwds)
641 {
642     rpmDbiTagVal tag;
643     PyObject *mio = NULL;
644     char * kwlist[] = {"tag", NULL};
645
646     if (!PyArg_ParseTupleAndKeywords(args, kwds, "O&:Keys", kwlist,
647               tagNumFromPyObject, &tag))
648         return NULL;
649
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");
655             goto exit;
656         }
657     }
658
659     rpmdbIndexIterator ii = rpmdbIndexIteratorInit(rpmtsGetRdb(s->ts), tag);
660     if (ii == NULL) {
661         PyErr_SetString(PyExc_KeyError, "No index for this tag");
662         return NULL;
663     }
664     mio = rpmii_Wrap(&rpmii_Type, ii, (PyObject*)s);
665
666 exit:
667     return mio;
668 }
669
670 static struct PyMethodDef rpmts_methods[] = {
671  {"addInstall", (PyCFunction) rpmts_AddInstall, METH_VARARGS,
672         NULL },
673  {"addErase",   (PyCFunction) rpmts_AddErase,   METH_VARARGS|METH_KEYWORDS,
674         NULL },
675  {"check",      (PyCFunction) rpmts_Check,      METH_VARARGS|METH_KEYWORDS,
676         NULL },
677  {"order",      (PyCFunction) rpmts_Order,      METH_NOARGS,
678         NULL },
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,
687         NULL },
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,
713         NULL },
714  {"pgpPrtPkts", (PyCFunction) rpmts_PgpPrtPkts, METH_VARARGS|METH_KEYWORDS,
715         NULL },
716  {"pgpImportPubkey",    (PyCFunction) rpmts_PgpImportPubkey,    METH_VARARGS|METH_KEYWORDS,
717         NULL },
718  {"getKeyring", (PyCFunction) rpmts_getKeyring, METH_VARARGS|METH_KEYWORDS, 
719         NULL },
720  {"setKeyring", (PyCFunction) rpmts_setKeyring, METH_O, 
721         NULL },
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 */
729 };
730
731 static void rpmts_dealloc(rpmtsObject * s)
732 {
733
734     s->ts = rpmtsFree(s->ts);
735     Py_XDECREF(s->scriptFd);
736     Py_XDECREF(s->keyList);
737     Py_TYPE(s)->tp_free((PyObject *)s);
738 }
739
740 static PyObject * rpmts_new(PyTypeObject * subtype, PyObject *args, PyObject *kwds)
741 {
742     rpmtsObject * s = (rpmtsObject *)subtype->tp_alloc(subtype, 0);
743     if (s == NULL) return NULL;
744
745     s->ts = rpmtsCreate();
746     s->scriptFd = NULL;
747     s->tsi = NULL;
748     s->keyList = PyList_New(0);
749     return (PyObject *) s;
750 }
751
752 static int rpmts_init(rpmtsObject *s, PyObject *args, PyObject *kwds)
753 {
754     const char * rootDir = "/";
755     rpmVSFlags vsflags = rpmExpandNumeric("%{?__vsflags}");
756     char * kwlist[] = {"rootdir", "vsflags", 0};
757
758     if (!PyArg_ParseTupleAndKeywords(args, kwds, "|si:rpmts_new", kwlist,
759             &rootDir, &vsflags))
760         return -1;
761
762     (void) rpmtsSetRootDir(s->ts, rootDir);
763     /* XXX: make this use common code with rpmts_SetVSFlags() to check the
764      *      python objects */
765     (void) rpmtsSetVSFlags(s->ts, vsflags);
766
767     return 0;
768 }
769
770 static PyObject *rpmts_get_tid(rpmtsObject *s, void *closure)
771 {
772     return Py_BuildValue("i", rpmtsGetTid(s->ts));
773 }
774
775 static PyObject *rpmts_get_rootDir(rpmtsObject *s, void *closure)
776 {
777     return Py_BuildValue("s", rpmtsRootDir(s->ts));
778 }
779
780 static int rpmts_set_scriptFd(rpmtsObject *s, PyObject *value, void *closure)
781 {
782     rpmfdObject *fdo = NULL;
783     int rc = 0;
784     if (PyArg_Parse(value, "O&", rpmfdFromPyObject, &fdo)) {
785         Py_XDECREF(s->scriptFd);
786         s->scriptFd = fdo;
787         rpmtsSetScriptFd(s->ts, rpmfdGetFd(s->scriptFd));
788     } else if (value == Py_None) {
789         Py_XDECREF(s->scriptFd);
790         s->scriptFd = NULL;
791         rpmtsSetScriptFd(s->ts, NULL);
792     } else {
793         rc = -1;
794     }
795     return rc;
796 }
797
798 static PyObject *rpmts_get_color(rpmtsObject *s, void *closure)
799 {
800     return Py_BuildValue("i", rpmtsColor(s->ts));
801 }
802
803 static PyObject *rpmts_get_prefcolor(rpmtsObject *s, void *closure)
804 {
805     return Py_BuildValue("i", rpmtsPrefColor(s->ts));
806 }
807
808 static int rpmts_set_color(rpmtsObject *s, PyObject *value, void *closure)
809 {
810     rpm_color_t color;
811     if (!PyArg_Parse(value, "i", &color)) return -1;
812
813     /* TODO: validate the bits */
814     rpmtsSetColor(s->ts, color);
815     return 0;
816 }
817
818 static int rpmts_set_prefcolor(rpmtsObject *s, PyObject *value, void *closure)
819 {
820     rpm_color_t color;
821     if (!PyArg_Parse(value, "i", &color)) return -1;
822
823     /* TODO: validate the bits */
824     rpmtsSetPrefColor(s->ts, color);
825     return 0;
826 }
827
828 static int rpmts_set_flags(rpmtsObject *s, PyObject *value, void *closure)
829 {
830     rpmtransFlags flags;
831     if (!PyArg_Parse(value, "i", &flags)) return -1;
832
833     /* TODO: validate the bits */
834     rpmtsSetFlags(s->ts, flags);
835     return 0;
836 }
837
838 static int rpmts_set_vsflags(rpmtsObject *s, PyObject *value, void *closure)
839 {
840     rpmVSFlags flags;
841     if (!PyArg_Parse(value, "i", &flags)) return -1;
842
843     /* TODO: validate the bits */
844     rpmtsSetVSFlags(s->ts, flags);
845     return 0;
846 }
847
848 static PyObject *rpmts_get_flags(rpmtsObject *s, void *closure)
849 {
850     return Py_BuildValue("i", rpmtsFlags(s->ts));
851 }
852
853 static PyObject *rpmts_get_vsflags(rpmtsObject *s, void *closure)
854 {
855     return Py_BuildValue("i", rpmtsVSFlags(s->ts));
856 }
857
858 static char rpmts_doc[] =
859 "";
860
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},
870         { NULL }
871 };
872
873 PyTypeObject rpmts_Type = {
874         PyVarObject_HEAD_INIT(&PyType_Type, 0)
875         "rpm.ts",                       /* tp_name */
876         sizeof(rpmtsObject),            /* tp_size */
877         0,                              /* tp_itemsize */
878         (destructor) rpmts_dealloc,     /* tp_dealloc */
879         0,                              /* tp_print */
880         (getattrfunc)0,                 /* tp_getattr */
881         (setattrfunc)0,                 /* tp_setattr */
882         0,                              /* tp_compare */
883         0,                              /* tp_repr */
884         0,                              /* tp_as_number */
885         0,                              /* tp_as_sequence */
886         0,                              /* tp_as_mapping */
887         0,                              /* tp_hash */
888         0,                              /* tp_call */
889         0,                              /* tp_str */
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 */
895         0,                              /* tp_traverse */
896         0,                              /* tp_clear */
897         0,                              /* tp_richcompare */
898         0,                              /* tp_weaklistoffset */
899         PyObject_SelfIter,              /* tp_iter */
900         (iternextfunc) rpmts_iternext,  /* tp_iternext */
901         rpmts_methods,                  /* tp_methods */
902         0,                              /* tp_members */
903         rpmts_getseters,                /* tp_getset */
904         0,                              /* tp_base */
905         0,                              /* tp_dict */
906         0,                              /* tp_descr_get */
907         0,                              /* tp_descr_set */
908         0,                              /* tp_dictoffset */
909         (initproc) rpmts_init,          /* tp_init */
910         0,                              /* tp_alloc */
911         (newfunc) rpmts_new,            /* tp_new */
912         0,                              /* tp_free */
913         0,                              /* tp_is_gc */
914 };