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 control 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_JUSTDB - only make changes to the rpm
107 * database, do not modify files.
108 * - rpm.RPMTRANS_FLAG_NOSCRIPTS - do not execute package scripts
109 * - rpm.RPMTRANS_FLAG_NOTRIGGERS - do not run trigger scripts
110 * - rpm.RPMTRANS_FLAG_NO* - disable specific scripts and triggers
111 * - rpm.RPMTRANS_FLAG_NODOCS - do not install files marked as %doc
112 * - rpm.RPMTRANS_FLAG_NOPLUGINS - do not run plugins
113 * - rpm.RPMTRANS_FLAG_NOFILEDIGEST - disable checking checksums
114 * - rpm.RPMTRANS_FLAG_ALLFILES - create all files, even if a
115 * file is marked %config(missingok) and an upgrade is
117 * - rpm.RPMTRANS_FLAG_NOCONFIGS - skip config files
118 * - rpm.RPMTRANS_FLAG_DEPLOOPS - enable debugging for dependency loops
119 * @return previous transFlags
121 * - ts.setProbFilter(ignoreSet) Set transaction set problem filter.
122 * @param problemSetFilter - control bit(s) to ignore classes of problems,
123 * a logical or of one or more of the following bit(s):
124 * - rpm.RPMPROB_FILTER_IGNOREOS -
125 * - rpm.RPMPROB_FILTER_IGNOREARCH -
126 * - rpm.RPMPROB_FILTER_REPLACEPKG -
127 * - rpm.RPMPROB_FILTER_FORCERELOCATE -
128 * - rpm.RPMPROB_FILTER_REPLACENEWFILES -
129 * - rpm.RPMPROB_FILTER_REPLACEOLDFILES -
130 * - rpm.RPMPROB_FILTER_OLDPACKAGE -
131 * - rpm.RPMPROB_FILTER_DISKSPACE -
132 * @return previous ignoreSet
134 * - ts.run(callback,data) Attempt to execute a transaction set.
135 * After the transaction set has been populated with install/upgrade or
136 * erase actions, the transaction set can be executed by invoking
137 * the ts.run() method.
140 struct rpmtsObject_s {
142 PyObject *md_dict; /*!< to look like PyModuleObject */
143 rpmfdObject *scriptFd;
149 struct rpmtsCallbackType_s {
153 PyThreadState *_save;
157 static void die(PyObject *cb)
162 if (PyErr_Occurred()) {
165 if ((r = PyObject_Repr(cb)) != NULL) {
166 pyfn = PyBytes_AsString(r);
168 fprintf(stderr, "FATAL ERROR: python callback %s failed, aborting!\n",
169 pyfn ? pyfn : "???");
174 rpmts_AddInstall(rpmtsObject * s, PyObject * args)
181 if (!PyArg_ParseTuple(args, "O&Oi:AddInstall",
182 hdrFromPyObject, &h, &key, &how))
185 rc = rpmtsAddInstallElement(s->ts, h, key, how, NULL);
186 if (key && rc == 0) {
187 PyList_Append(s->keyList, key);
189 return PyBool_FromLong((rc == 0));
193 rpmts_AddReinstall(rpmtsObject * s, PyObject * args)
199 if (!PyArg_ParseTuple(args, "O&O:AddReinstall",
200 hdrFromPyObject, &h, &key))
203 rc = rpmtsAddReinstallElement(s->ts, h, key);
204 if (key && rc == 0) {
205 PyList_Append(s->keyList, key);
207 return PyBool_FromLong((rc == 0));
211 rpmts_AddErase(rpmtsObject * s, PyObject * args)
215 if (!PyArg_ParseTuple(args, "O&:AddErase", hdrFromPyObject, &h))
218 return PyBool_FromLong(rpmtsAddEraseElement(s->ts, h, -1) == 0);
222 rpmts_SolveCallback(rpmts ts, rpmds ds, const void * data)
224 struct rpmtsCallbackType_s * cbInfo = (struct rpmtsCallbackType_s *) data;
225 PyObject * args, * result;
228 if (cbInfo->tso == NULL) return res;
229 if (cbInfo->cb == Py_None) return res;
231 PyEval_RestoreThread(cbInfo->_save);
233 args = Py_BuildValue("(Oissi)", cbInfo->tso,
234 rpmdsTagN(ds), rpmdsN(ds), rpmdsEVR(ds), rpmdsFlags(ds));
235 result = PyEval_CallObject(cbInfo->cb, args);
241 if (PyInt_Check(result))
242 res = PyInt_AsLong(result);
246 cbInfo->_save = PyEval_SaveThread();
252 rpmts_Check(rpmtsObject * s, PyObject * args, PyObject * kwds)
254 struct rpmtsCallbackType_s cbInfo;
256 char * kwlist[] = {"callback", NULL};
258 memset(&cbInfo, 0, sizeof(cbInfo));
259 if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O:Check", kwlist,
263 if (cbInfo.cb != NULL) {
264 if (!PyCallable_Check(cbInfo.cb)) {
265 PyErr_SetString(PyExc_TypeError, "expected a callable");
268 rc = rpmtsSetSolveCallback(s->ts, rpmts_SolveCallback, (void *)&cbInfo);
272 cbInfo._save = PyEval_SaveThread();
274 rc = rpmtsCheck(s->ts);
276 PyEval_RestoreThread(cbInfo._save);
278 return PyBool_FromLong((rc == 0));
282 rpmts_Order(rpmtsObject * s)
286 Py_BEGIN_ALLOW_THREADS
287 rc = rpmtsOrder(s->ts);
290 return Py_BuildValue("i", rc);
294 rpmts_Clean(rpmtsObject * s)
302 rpmts_Clear(rpmtsObject * s)
310 rpmts_OpenDB(rpmtsObject * s)
314 dbmode = rpmtsGetDBMode(s->ts);
318 return Py_BuildValue("i", rpmtsOpenDB(s->ts, dbmode));
322 rpmts_CloseDB(rpmtsObject * s)
326 rc = rpmtsCloseDB(s->ts);
327 rpmtsSetDBMode(s->ts, -1); /* XXX disable lazy opens */
329 return Py_BuildValue("i", rc);
333 rpmts_InitDB(rpmtsObject * s)
337 rc = rpmtsInitDB(s->ts, O_RDONLY);
339 rc = rpmtsCloseDB(s->ts);
341 return Py_BuildValue("i", rc);
345 rpmts_RebuildDB(rpmtsObject * s)
349 Py_BEGIN_ALLOW_THREADS
350 rc = rpmtsRebuildDB(s->ts);
353 return Py_BuildValue("i", rc);
357 rpmts_VerifyDB(rpmtsObject * s)
361 Py_BEGIN_ALLOW_THREADS
362 rc = rpmtsVerifyDB(s->ts);
365 return Py_BuildValue("i", rc);
369 rpmts_HdrFromFdno(rpmtsObject * s, PyObject *arg)
372 rpmfdObject *fdo = NULL;
376 if (!PyArg_Parse(arg, "O&:HdrFromFdno", rpmfdFromPyObject, &fdo))
379 Py_BEGIN_ALLOW_THREADS;
380 rpmrc = rpmReadPackageFile(s->ts, rpmfdGetFd(fdo), NULL, &h);
381 Py_END_ALLOW_THREADS;
384 if (rpmrc == RPMRC_OK) {
385 ho = hdr_Wrap(&hdr_Type, h);
390 return Py_BuildValue("(iN)", rpmrc, ho);
394 rpmts_HdrCheck(rpmtsObject * s, PyObject *obj)
402 if (!PyArg_Parse(obj, "S:HdrCheck", &blob))
405 uh = PyBytes_AsString(blob);
406 uc = PyBytes_Size(blob);
408 Py_BEGIN_ALLOW_THREADS;
409 rpmrc = headerCheck(s->ts, uh, uc, &msg);
410 Py_END_ALLOW_THREADS;
412 return Py_BuildValue("(is)", rpmrc, msg);
416 rpmts_PgpPrtPkts(rpmtsObject * s, PyObject * args, PyObject * kwds)
422 char * kwlist[] = {"octets", NULL};
424 if (!PyArg_ParseTupleAndKeywords(args, kwds, "S:PgpPrtPkts", kwlist, &blob))
427 pkt = (unsigned char *)PyBytes_AsString(blob);
428 pktlen = PyBytes_Size(blob);
430 rc = pgpPrtPkts(pkt, pktlen, NULL, 1);
432 return Py_BuildValue("i", rc);
436 rpmts_PgpImportPubkey(rpmtsObject * s, PyObject * args, PyObject * kwds)
442 char * kwlist[] = {"pubkey", NULL};
444 if (!PyArg_ParseTupleAndKeywords(args, kwds, "S:PgpImportPubkey",
448 pkt = (unsigned char *)PyBytes_AsString(blob);
449 pktlen = PyBytes_Size(blob);
451 rc = rpmtsImportPubkey(s->ts, pkt, pktlen);
453 return Py_BuildValue("i", rc);
456 static PyObject *rpmts_setKeyring(rpmtsObject *s, PyObject *arg)
458 rpmKeyring keyring = NULL;
459 if (arg == Py_None || rpmKeyringFromPyObject(arg, &keyring)) {
460 return PyBool_FromLong(rpmtsSetKeyring(s->ts, keyring) == 0);
462 PyErr_SetString(PyExc_TypeError, "rpm.keyring or None expected");
467 static PyObject *rpmts_getKeyring(rpmtsObject *s, PyObject *args, PyObject *kwds)
469 rpmKeyring keyring = NULL;
471 char * kwlist[] = { "autoload", NULL };
473 if (!PyArg_ParseTupleAndKeywords(args, kwds, "|i:getKeyring",
477 keyring = rpmtsGetKeyring(s->ts, autoload);
479 return rpmKeyring_Wrap(&rpmKeyring_Type, keyring);
486 rpmtsCallback(const void * hd, const rpmCallbackType what,
487 const rpm_loff_t amount, const rpm_loff_t total,
488 const void * pkgKey, rpmCallbackData data)
490 Header h = (Header) hd;
491 struct rpmtsCallbackType_s * cbInfo = data;
492 PyObject * pkgObj = (PyObject *) pkgKey;
493 PyObject * args, * result;
496 if (cbInfo->cb == Py_None) return NULL;
498 /* Synthesize a python object for callback (if necessary). */
499 if (pkgObj == NULL) {
501 pkgObj = Py_BuildValue("s", headerGetString(h, RPMTAG_NAME));
509 PyEval_RestoreThread(cbInfo->_save);
511 args = Py_BuildValue("(iLLOO)", what, amount, total, pkgObj, cbInfo->data);
512 result = PyEval_CallObject(cbInfo->cb, args);
520 if (what == RPMCALLBACK_INST_OPEN_FILE) {
523 if (!PyArg_Parse(result, "i", &fdno)) {
527 cbInfo->_save = PyEval_SaveThread();
530 fcntl(Fileno(fd), F_SETFD, FD_CLOEXEC);
534 if (what == RPMCALLBACK_INST_CLOSE_FILE) {
539 cbInfo->_save = PyEval_SaveThread();
545 rpmts_Problems(rpmtsObject * s)
547 rpmps ps = rpmtsProblems(s->ts);
548 PyObject *problems = rpmps_AsList(ps);
554 rpmts_Run(rpmtsObject * s, PyObject * args, PyObject * kwds)
557 struct rpmtsCallbackType_s cbInfo;
558 rpmprobFilterFlags ignoreSet;
559 char * kwlist[] = {"callback", "data", "ignoreSet", NULL};
561 if (!PyArg_ParseTupleAndKeywords(args, kwds, "OOi:Run", kwlist,
562 &cbInfo.cb, &cbInfo.data, &ignoreSet))
566 cbInfo._save = PyEval_SaveThread();
568 if (cbInfo.cb != NULL) {
569 if (!PyCallable_Check(cbInfo.cb)) {
570 PyErr_SetString(PyExc_TypeError, "expected a callable");
573 (void) rpmtsSetNotifyCallback(s->ts, rpmtsCallback, (void *) &cbInfo);
576 rc = rpmtsRun(s->ts, NULL, ignoreSet);
579 (void) rpmtsSetNotifyCallback(s->ts, NULL, NULL);
581 PyEval_RestoreThread(cbInfo._save);
583 return Py_BuildValue("i", rc);
587 rpmts_iternext(rpmtsObject * s)
589 PyObject * result = NULL;
592 /* Reset iterator on 1st entry. */
593 if (s->tsi == NULL) {
594 s->tsi = rpmtsiInit(s->ts);
599 te = rpmtsiNext(s->tsi, 0);
601 result = rpmte_Wrap(&rpmte_Type, te);
603 s->tsi = rpmtsiFree(s->tsi);
610 rpmts_Match(rpmtsObject * s, PyObject * args, PyObject * kwds)
612 PyObject *Key = NULL;
613 PyObject *str = NULL;
614 PyObject *mio = NULL;
616 /* XXX lkey *must* be a 32 bit integer, int "works" on all known platforms. */
619 rpmDbiTagVal tag = RPMDBI_PACKAGES;
620 char * kwlist[] = {"tagNumber", "key", NULL};
622 if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O&O:Match", kwlist,
623 tagNumFromPyObject, &tag, &Key))
627 if (PyInt_Check(Key)) {
628 lkey = PyInt_AsLong(Key);
631 } else if (PyLong_Check(Key)) {
632 lkey = PyLong_AsLong(Key);
635 } else if (utf8FromPyObject(Key, &str)) {
636 key = PyBytes_AsString(str);
637 len = PyBytes_Size(str);
639 PyErr_SetString(PyExc_TypeError, "unknown key type");
642 /* One of the conversions above failed, exception is set already */
643 if (PyErr_Occurred()) goto exit;
646 /* XXX If not already opened, open the database O_RDONLY now. */
647 /* XXX FIXME: lazy default rdonly open also done by rpmtsInitIterator(). */
648 if (rpmtsGetRdb(s->ts) == NULL) {
649 int rc = rpmtsOpenDB(s->ts, O_RDONLY);
650 if (rc || rpmtsGetRdb(s->ts) == NULL) {
651 PyErr_SetString(pyrpmError, "rpmdb open failed");
656 mio = rpmmi_Wrap(&rpmmi_Type, rpmtsInitIterator(s->ts, tag, key, len), (PyObject*)s);
663 rpmts_index(rpmtsObject * s, PyObject * args, PyObject * kwds)
666 PyObject *mio = NULL;
667 char * kwlist[] = {"tag", NULL};
669 if (!PyArg_ParseTupleAndKeywords(args, kwds, "O&:Keys", kwlist,
670 tagNumFromPyObject, &tag))
673 /* XXX If not already opened, open the database O_RDONLY now. */
674 if (rpmtsGetRdb(s->ts) == NULL) {
675 int rc = rpmtsOpenDB(s->ts, O_RDONLY);
676 if (rc || rpmtsGetRdb(s->ts) == NULL) {
677 PyErr_SetString(pyrpmError, "rpmdb open failed");
682 rpmdbIndexIterator ii = rpmdbIndexIteratorInit(rpmtsGetRdb(s->ts), tag);
684 PyErr_SetString(PyExc_KeyError, "No index for this tag");
687 mio = rpmii_Wrap(&rpmii_Type, ii, (PyObject*)s);
693 static struct PyMethodDef rpmts_methods[] = {
694 {"addInstall", (PyCFunction) rpmts_AddInstall, METH_VARARGS,
695 "ts.addInstall(hdr, data, mode) -- Add transaction element(s)\n"
696 "representing an installation or update of a package.\n\n"
698 " hdr : the header to be added\n"
699 " data : user data that will be passed to the transaction callback\n\t\tduring transaction execution\n"
700 " mode : optional argument that specifies if this package should be\n\t\tinstalled ('i'), upgraded ('u')"},
701 {"addReinstall", (PyCFunction) rpmts_AddReinstall, METH_VARARGS,
702 "ts.addReinstall(hdr, data) -- Adds transaction elements\nrepresenting a reinstall of an already installed package.\n\nSee addInstall for details."},
703 {"addErase", (PyCFunction) rpmts_AddErase, METH_VARARGS|METH_KEYWORDS,
704 "addErase(name) -- Add a transaction element representing an erase\nof an installed package.\n\n"
705 " name: the package name to be erased"},
706 {"check", (PyCFunction) rpmts_Check, METH_VARARGS|METH_KEYWORDS,
707 "ts.check( )-- Perform a dependency check on the transaction set.\n"
708 " After headers have been added to a transaction set,\n"
709 " a dependencycheck can be performed to make sure that\n"
710 " all package dependencies are satisfied.\n"
711 "Return None If there are no unresolved dependencies\n"
712 " Otherwise a list of complex tuples is returned,\n"
713 " one tuple per unresolved dependency, with\n"
714 "The format of the dependency tuple is:\n"
715 " ((packageName, packageVersion, packageRelease),\n"
716 " (reqName, reqVersion),\n"
718 " suggestedPackage,\n"
720 " packageName, packageVersion, packageRelease are the name,\n"
721 " version, and release of the package that has the unresolved\n"
722 " dependency or conflict.\n"
723 " The reqName and reqVersion are the name and version of the\n"
724 " requirement or conflict.\n"
725 " The needsFlags is a bitfield that describes the versioned\n"
726 " nature of a requirement or conflict. The constants\n"
727 " rpm.RPMSENSE_LESS, rpm.RPMSENSE_GREATER, and\n"
728 " rpm.RPMSENSE_EQUAL can be logical ANDed with the needsFlags\n"
729 " to get versioned dependency information.\n"
730 " suggestedPackage is a tuple if the dependency check was aware\n"
731 " of a package that solves this dependency problem when the\n"
732 " dependency check was run. Packages that are added to the\n"
733 " transaction set as \"available\" are examined during the\n"
734 " dependency check as possible dependency solvers. The tuple\n"
735 " contains two values, (header, suggestedName). These are set to\n"
736 " the header of the suggested package and its name, respectively.\n"
737 " If there is no known package to solve the dependency problem,\n"
738 " suggestedPackage is None.\n"
739 " The constants rpm.RPMDEP_SENSE_CONFLICTS and\n"
740 " rpm.RPMDEP_SENSE_REQUIRES are set to show a dependency as a\n"
741 " requirement or a conflict.\n"},
742 {"order", (PyCFunction) rpmts_Order, METH_NOARGS,
743 "ts.order() Do a topological sort of added element relations." },
744 {"problems", (PyCFunction) rpmts_Problems, METH_NOARGS,
745 "ts.problems() -> ps\n\
746 - Return current problem set.\n" },
747 {"run", (PyCFunction) rpmts_Run, METH_VARARGS|METH_KEYWORDS,
748 "ts.run(callback, data) -> (problems)\n\
749 - Run a transaction set, returning list of problems found.\n\
750 Note: The callback may not be None.\n" },
751 {"clean", (PyCFunction) rpmts_Clean, METH_NOARGS,
752 "ts.clean()-- Free memory needed only for dependency checks\nand ordering. Should not be needed in normal operation." },
753 {"clear", (PyCFunction) rpmts_Clear, METH_NOARGS,
754 "ts.clear() -> None\n\
755 Remove all elements from the transaction set\n" },
756 {"openDB", (PyCFunction) rpmts_OpenDB, METH_NOARGS,
757 "ts.openDB() -> None -- Open the default transaction rpmdb.\n\n\
758 Note: The transaction rpmdb is lazily opened,\n so ts.openDB() is seldom needed.\n" },
759 {"closeDB", (PyCFunction) rpmts_CloseDB, METH_NOARGS,
760 "ts.closeDB() -> None\n\
761 - Close the default transaction rpmdb.\n\
762 Note: ts.closeDB() disables lazy opens,\n\
763 and should hardly ever be used.\n" },
764 {"initDB", (PyCFunction) rpmts_InitDB, METH_NOARGS,
765 "ts.initDB() -> None\n\
766 - Initialize the default transaction rpmdb.\n\
767 Note: ts.initDB() is seldom needed anymore.\n" },
768 {"rebuildDB", (PyCFunction) rpmts_RebuildDB, METH_NOARGS,
769 "ts.rebuildDB() -> None\n\
770 - Rebuild the default transaction rpmdb.\n" },
771 {"verifyDB", (PyCFunction) rpmts_VerifyDB, METH_NOARGS,
772 "ts.verifyDB() -> None\n\
773 - Verify the default transaction rpmdb.\n" },
774 {"hdrFromFdno",(PyCFunction) rpmts_HdrFromFdno,METH_O,
775 "ts.hdrFromFdno(fdno) -> hdr\n\
776 - Read a package header from a file descriptor.\n" },
777 {"hdrCheck", (PyCFunction) rpmts_HdrCheck, METH_O,
778 "ts.hdrCheck(hdrblob) -- Check header consistency,\nperforming headerGetEntry() the hard way.\n\n"
779 "Sanity checks on the header are performed while looking for a\n"
780 "header-only digest or signature to verify the blob. If found,\n"
781 "the digest or signature is verified.\n\n"
782 "\thdrblob : unloaded header blob\n"
783 "Return tuple (int status, message string)"},
784 {"pgpPrtPkts", (PyCFunction) rpmts_PgpPrtPkts, METH_VARARGS|METH_KEYWORDS,
785 "pgpPrtPkts(octets) -- Print/parse a OpenPGP packet(s).\n\nReturn 0 on success." },
786 {"pgpImportPubkey", (PyCFunction) rpmts_PgpImportPubkey, METH_VARARGS|METH_KEYWORDS,
787 "pgpImportPubkey(pubkey) -- Import public key packet." },
788 {"getKeyring", (PyCFunction) rpmts_getKeyring, METH_VARARGS|METH_KEYWORDS,
789 "ts.getKeyring(autoload=False) -- Return key ring object." },
790 {"setKeyring", (PyCFunction) rpmts_setKeyring, METH_O,
791 "ts.setKeyring(keyring) -- Set key ring used for checking signatures\n\n"
792 "Pass None for an empty key ring." },
793 {"dbMatch", (PyCFunction) rpmts_Match, METH_VARARGS|METH_KEYWORDS,
794 "ts.dbMatch([TagN, [key]]) -> mi\n\
795 - Create a match iterator for the default transaction rpmdb.\n" },
796 {"dbIndex", (PyCFunction) rpmts_index, METH_VARARGS|METH_KEYWORDS,
797 "ts.dbIndex(TagN) -> ii\n\
798 - Create a key iterator for the default transaction rpmdb.\n" },
799 {NULL, NULL} /* sentinel */
802 static void rpmts_dealloc(rpmtsObject * s)
805 s->ts = rpmtsFree(s->ts);
806 Py_XDECREF(s->scriptFd);
807 Py_XDECREF(s->keyList);
808 Py_TYPE(s)->tp_free((PyObject *)s);
811 static PyObject * rpmts_new(PyTypeObject * subtype, PyObject *args, PyObject *kwds)
813 rpmtsObject * s = (rpmtsObject *)subtype->tp_alloc(subtype, 0);
814 if (s == NULL) return NULL;
816 s->ts = rpmtsCreate();
819 s->keyList = PyList_New(0);
820 return (PyObject *) s;
823 static int rpmts_init(rpmtsObject *s, PyObject *args, PyObject *kwds)
825 const char * rootDir = "/";
826 rpmVSFlags vsflags = rpmExpandNumeric("%{?__vsflags}");
827 char * kwlist[] = {"rootdir", "vsflags", 0};
829 if (!PyArg_ParseTupleAndKeywords(args, kwds, "|si:rpmts_new", kwlist,
833 (void) rpmtsSetRootDir(s->ts, rootDir);
834 /* XXX: make this use common code with rpmts_SetVSFlags() to check the
836 (void) rpmtsSetVSFlags(s->ts, vsflags);
841 static PyObject *rpmts_get_tid(rpmtsObject *s, void *closure)
843 return Py_BuildValue("i", rpmtsGetTid(s->ts));
846 static PyObject *rpmts_get_rootDir(rpmtsObject *s, void *closure)
848 return Py_BuildValue("s", rpmtsRootDir(s->ts));
851 static int rpmts_set_scriptFd(rpmtsObject *s, PyObject *value, void *closure)
853 rpmfdObject *fdo = NULL;
855 if (PyArg_Parse(value, "O&", rpmfdFromPyObject, &fdo)) {
856 Py_XDECREF(s->scriptFd);
858 rpmtsSetScriptFd(s->ts, rpmfdGetFd(s->scriptFd));
859 } else if (value == Py_None) {
860 Py_XDECREF(s->scriptFd);
862 rpmtsSetScriptFd(s->ts, NULL);
869 static PyObject *rpmts_get_color(rpmtsObject *s, void *closure)
871 return Py_BuildValue("i", rpmtsColor(s->ts));
874 static PyObject *rpmts_get_prefcolor(rpmtsObject *s, void *closure)
876 return Py_BuildValue("i", rpmtsPrefColor(s->ts));
879 static int rpmts_set_color(rpmtsObject *s, PyObject *value, void *closure)
882 if (!PyArg_Parse(value, "i", &color)) return -1;
884 /* TODO: validate the bits */
885 rpmtsSetColor(s->ts, color);
889 static int rpmts_set_prefcolor(rpmtsObject *s, PyObject *value, void *closure)
892 if (!PyArg_Parse(value, "i", &color)) return -1;
894 /* TODO: validate the bits */
895 rpmtsSetPrefColor(s->ts, color);
899 static int rpmts_set_flags(rpmtsObject *s, PyObject *value, void *closure)
902 if (!PyArg_Parse(value, "i", &flags)) return -1;
904 /* TODO: validate the bits */
905 rpmtsSetFlags(s->ts, flags);
909 static int rpmts_set_vsflags(rpmtsObject *s, PyObject *value, void *closure)
912 if (!PyArg_Parse(value, "i", &flags)) return -1;
914 /* TODO: validate the bits */
915 rpmtsSetVSFlags(s->ts, flags);
919 static PyObject *rpmts_get_flags(rpmtsObject *s, void *closure)
921 return Py_BuildValue("i", rpmtsFlags(s->ts));
924 static PyObject *rpmts_get_vsflags(rpmtsObject *s, void *closure)
926 return Py_BuildValue("i", rpmtsVSFlags(s->ts));
929 static char rpmts_doc[] =
930 "A python rpm.ts object represents an RPM transaction set.\n"
932 "The transaction set is the workhorse of RPM. It performs the\n"
933 "installation and upgrade of packages. The rpm.ts object is\n"
934 "instantiated by the TransactionSet function in the rpm module.\n"
936 "The TransactionSet function takes two optional arguments. The first\n"
937 "argument is the root path. The second is the verify signature disable\n"
938 "flags, a set of the following bits:\n"
940 "- rpm.RPMVSF_NOHDRCHK if set, don't check rpmdb headers\n"
941 "- rpm.RPMVSF_NEEDPAYLOAD if not set, check header+payload\n"
943 "- rpm.RPMVSF_NOSHA1HEADER if set, don't check header SHA1 digest\n"
944 "- rpm.RPMVSF_NODSAHEADER if set, don't check header DSA signature\n"
945 "- rpm.RPMVSF_NOMD5 if set, don't check header+payload MD5 digest\n"
946 "- rpm.RPMVSF_NODSA if set, don't check header+payload DSA signature\n"
947 "- rpm.RPMVSF_NORSA if set, don't check header+payload RSA signature\n"
949 "For convenience, there are the following masks:\n"
950 "- rpm._RPMVSF_NODIGESTS if set, don't check digest(s).\n"
951 "- rpm._RPMVSF_NOSIGNATURES if set, don't check signature(s).\n\n"
952 "The transaction set offers an read only iterable interface for the\ntransaction elements added by the .addInstall(), .addErase() and\n.addReinstall() methods.";
954 static PyGetSetDef rpmts_getseters[] = {
955 /* only provide a setter until we have rpmfd wrappings */
956 {"scriptFd", NULL, (setter)rpmts_set_scriptFd,
957 "write only, file descriptor the output of script gets written to." },
958 {"tid", (getter)rpmts_get_tid, NULL,
959 "read only, current transaction id, i.e. transaction time stamp."},
960 {"rootDir", (getter)rpmts_get_rootDir, NULL,
961 "read only, directory rpm treats as root of the file system." },
962 {"_color", (getter)rpmts_get_color, (setter)rpmts_set_color, NULL},
963 {"_prefcolor", (getter)rpmts_get_prefcolor, (setter)rpmts_set_prefcolor, NULL},
964 {"_flags", (getter)rpmts_get_flags, (setter)rpmts_set_flags, NULL},
965 {"_vsflags", (getter)rpmts_get_vsflags, (setter)rpmts_set_vsflags, NULL},
969 PyTypeObject rpmts_Type = {
970 PyVarObject_HEAD_INIT(&PyType_Type, 0)
971 "rpm.ts", /* tp_name */
972 sizeof(rpmtsObject), /* tp_size */
974 (destructor) rpmts_dealloc, /* tp_dealloc */
976 (getattrfunc)0, /* tp_getattr */
977 (setattrfunc)0, /* tp_setattr */
980 0, /* tp_as_number */
981 0, /* tp_as_sequence */
982 0, /* tp_as_mapping */
986 PyObject_GenericGetAttr, /* tp_getattro */
987 PyObject_GenericSetAttr, /* tp_setattro */
988 0, /* tp_as_buffer */
989 Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, /* tp_flags */
990 rpmts_doc, /* tp_doc */
993 0, /* tp_richcompare */
994 0, /* tp_weaklistoffset */
995 PyObject_SelfIter, /* tp_iter */
996 (iternextfunc) rpmts_iternext, /* tp_iternext */
997 rpmts_methods, /* tp_methods */
999 rpmts_getseters, /* tp_getset */
1002 0, /* tp_descr_get */
1003 0, /* tp_descr_set */
1004 0, /* tp_dictoffset */
1005 (initproc) rpmts_init, /* tp_init */
1007 (newfunc) rpmts_new, /* tp_new */