1 #include "rpmsystem-py.h"
3 #include <rpm/rpmlib.h> /* rpmReadPackageFile, headerCheck */
4 #include <rpm/rpmtag.h>
5 #include <rpm/rpmpgp.h>
7 #include <rpm/rpmbuild.h>
10 #include "rpmds-py.h" /* XXX for rpmdsNew */
12 #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 */
141 PyObject * keyList; /* keeps reference counts correct */
144 rpmprobFilterFlags ignoreSet;
147 struct rpmtsCallbackType_s {
151 PyThreadState *_save;
155 static void die(PyObject *cb)
160 if (PyErr_Occurred()) {
163 if ((r = PyObject_Repr(cb)) != NULL) {
164 pyfn = PyString_AsString(r);
166 fprintf(stderr, _("error: python callback %s failed, aborting!\n"),
167 pyfn ? pyfn : "???");
168 rpmdbCheckTerminate(1);
173 rpmts_AddInstall(rpmtsObject * s, PyObject * args, PyObject * kwds)
177 char * how = "u"; /* XXX default to upgrade element if missing */
179 char * kwlist[] = {"header", "key", "how", NULL};
182 if (!PyArg_ParseTupleAndKeywords(args, kwds, "O&O|s:AddInstall", kwlist,
183 hdrFromPyObject, &h, &key, &how))
186 if (how && !rstreq(how, "u") && !rstreq(how, "i")) {
187 PyErr_SetString(PyExc_TypeError, "how argument must be \"u\" or \"i\"");
189 } else if (how && rstreq(how, "u"))
192 rc = rpmtsAddInstallElement(s->ts, h, key, isUpgrade, NULL);
194 PyErr_SetString(pyrpmError, "adding package to transaction failed");
199 /* This should increment the usage count for me */
201 PyList_Append(s->keyList, key);
206 /* TODO Permit finer control (i.e. not just --allmatches) of deleted elments.*/
208 rpmts_AddErase(rpmtsObject * s, PyObject * args, PyObject * kwds)
212 rpmdbMatchIterator mi = NULL;
214 char * kwlist[] = {"name", NULL};
216 if (!PyArg_ParseTupleAndKeywords(args, kwds, "O:AddErase", kwlist, &o))
219 if (PyString_Check(o)) {
220 char * name = PyString_AsString(o);
221 mi = rpmtsInitIterator(s->ts, RPMDBI_LABEL, name, 0);
222 } else if (PyInt_Check(o)) {
223 uint32_t recno = PyInt_AsLong(o);
224 mi = rpmtsInitIterator(s->ts, RPMDBI_PACKAGES, &recno, sizeof(recno));
226 PyErr_SetString(PyExc_TypeError, "string or integer expected");
230 while ((h = rpmdbNextIterator(mi)) != NULL) {
232 rpmtsAddEraseElement(s->ts, h, -1);
234 rpmdbFreeIterator(mi);
239 PyErr_SetString(pyrpmError, "package not installed");
245 rpmts_SolveCallback(rpmts ts, rpmds ds, const void * data)
247 struct rpmtsCallbackType_s * cbInfo = (struct rpmtsCallbackType_s *) data;
248 PyObject * args, * result;
251 if (cbInfo->tso == NULL) return res;
252 if (cbInfo->cb == Py_None) return res;
254 PyEval_RestoreThread(cbInfo->_save);
256 args = Py_BuildValue("(Oissi)", cbInfo->tso,
257 rpmdsTagN(ds), rpmdsN(ds), rpmdsEVR(ds), rpmdsFlags(ds));
258 result = PyEval_CallObject(cbInfo->cb, args);
264 if (PyInt_Check(result))
265 res = PyInt_AsLong(result);
269 cbInfo->_save = PyEval_SaveThread();
275 rpmts_Check(rpmtsObject * s, PyObject * args, PyObject * kwds)
279 PyObject * list, * cf;
280 struct rpmtsCallbackType_s cbInfo;
282 char * kwlist[] = {"callback", NULL};
284 memset(&cbInfo, 0, sizeof(cbInfo));
285 if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O:Check", kwlist,
289 if (cbInfo.cb != NULL) {
290 if (!PyCallable_Check(cbInfo.cb)) {
291 PyErr_SetString(PyExc_TypeError, "expected a callable");
294 xx = rpmtsSetSolveCallback(s->ts, rpmts_SolveCallback, (void *)&cbInfo);
298 cbInfo._save = PyEval_SaveThread();
300 xx = rpmtsCheck(s->ts);
301 ps = rpmtsProblems(s->ts);
303 PyEval_RestoreThread(cbInfo._save);
306 list = PyList_New(0);
307 rpmpsi psi = rpmpsInitIterator(ps);
309 /* XXX TODO: rpmlib >= 4.0.3 can return multiple suggested keys. */
310 while (rpmpsNextIterator(psi) >= 0) {
311 char * altNEVR, * needsName;
312 char * byName, * byVersion, * byRelease, *byArch;
313 char * needsOP, * needsVersion;
314 rpmsenseFlags needsFlags, sense;
317 p = rpmpsGetProblem(psi);
319 byName = xstrdup(rpmProblemGetPkgNEVR(p));
320 if ((byArch= strrchr(byName, '.')) != NULL)
322 if ((byRelease = strrchr(byName, '-')) != NULL)
324 if ((byVersion = strrchr(byName, '-')) != NULL)
327 key = rpmProblemGetKey(p);
329 altNEVR = needsName = xstrdup(rpmProblemGetAltNEVR(p));
330 if (needsName[1] == ' ') {
331 sense = (needsName[0] == 'C')
332 ? RPMDEP_SENSE_CONFLICTS : RPMDEP_SENSE_REQUIRES;
335 sense = RPMDEP_SENSE_REQUIRES;
336 if ((needsVersion = strrchr(needsName, ' ')) != NULL)
337 *needsVersion++ = '\0';
340 if ((needsOP = strrchr(needsName, ' ')) != NULL) {
341 for (*needsOP++ = '\0'; *needsOP != '\0'; needsOP++) {
342 if (*needsOP == '<') needsFlags |= RPMSENSE_LESS;
343 else if (*needsOP == '>') needsFlags |= RPMSENSE_GREATER;
344 else if (*needsOP == '=') needsFlags |= RPMSENSE_EQUAL;
348 cf = Py_BuildValue("((sss)(ss)iOi)", byName, byVersion, byRelease,
349 needsName, needsVersion, needsFlags,
350 (key != NULL ? key : Py_None),
352 PyList_Append(list, (PyObject *) cf);
358 psi = rpmpsFreeIterator(psi);
368 rpmts_Order(rpmtsObject * s)
372 Py_BEGIN_ALLOW_THREADS
373 rc = rpmtsOrder(s->ts);
376 return Py_BuildValue("i", rc);
380 rpmts_Clean(rpmtsObject * s)
388 rpmts_OpenDB(rpmtsObject * s)
392 dbmode = rpmtsGetDBMode(s->ts);
396 return Py_BuildValue("i", rpmtsOpenDB(s->ts, dbmode));
400 rpmts_CloseDB(rpmtsObject * s)
404 rc = rpmtsCloseDB(s->ts);
405 rpmtsSetDBMode(s->ts, -1); /* XXX disable lazy opens */
407 return Py_BuildValue("i", rc);
411 rpmts_InitDB(rpmtsObject * s)
415 rc = rpmtsInitDB(s->ts, O_RDONLY);
417 rc = rpmtsCloseDB(s->ts);
419 return Py_BuildValue("i", rc);
423 rpmts_RebuildDB(rpmtsObject * s)
427 Py_BEGIN_ALLOW_THREADS
428 rc = rpmtsRebuildDB(s->ts);
431 return Py_BuildValue("i", rc);
435 rpmts_VerifyDB(rpmtsObject * s)
439 Py_BEGIN_ALLOW_THREADS
440 rc = rpmtsVerifyDB(s->ts);
443 return Py_BuildValue("i", rc);
447 rpmts_HdrFromFdno(rpmtsObject * s, PyObject * args, PyObject * kwds)
449 PyObject * result = NULL;
453 char * kwlist[] = {"fd", NULL};
455 if (!PyArg_ParseTupleAndKeywords(args, kwds, "O&:HdrFromFdno", kwlist,
456 rpmFdFromPyObject, &fd))
459 rpmrc = rpmReadPackageFile(s->ts, fd, "rpmts_HdrFromFdno", &h);
465 result = Py_BuildValue("N", hdr_Wrap(&hdr_Type, h));
466 h = headerFree(h); /* XXX ref held by result */
470 PyErr_SetString(pyrpmError, "public key not available");
473 case RPMRC_NOTTRUSTED:
474 PyErr_SetString(pyrpmError, "public key not trusted");
480 PyErr_SetString(pyrpmError, "error reading package header");
488 rpmts_HdrCheck(rpmtsObject * s, PyObject * args, PyObject * kwds)
491 PyObject * result = NULL;
496 char * kwlist[] = {"headers", NULL};
498 if (!PyArg_ParseTupleAndKeywords(args, kwds, "S:HdrCheck", kwlist, &blob))
501 uh = PyString_AsString(blob);
502 uc = PyString_Size(blob);
504 rpmrc = headerCheck(s->ts, uh, uc, &msg);
513 PyErr_SetString(pyrpmError, "public key not availaiable");
516 case RPMRC_NOTTRUSTED:
517 PyErr_SetString(pyrpmError, "public key not trusted");
522 PyErr_SetString(pyrpmError, msg);
530 static PyObject * wrapSetGetOld(rpmtsObject *s, const char *name, PyObject *val)
532 PyObject *oval = PyObject_GetAttrString((PyObject *)s, name);
533 if (PyObject_SetAttrString((PyObject *)s, name, val) == -1) {
540 static PyObject * rpmts_SetVSFlags(rpmtsObject * s, PyObject * arg)
542 return wrapSetGetOld(s, "_vsflags", arg);
545 static PyObject * rpmts_GetVSFlags(rpmtsObject * s)
547 return PyObject_GetAttrString((PyObject *)s, "_vsflags");
550 static PyObject * rpmts_SetColor(rpmtsObject * s, PyObject * arg)
552 return wrapSetGetOld(s, "_color", arg);
556 rpmts_PgpPrtPkts(rpmtsObject * s, PyObject * args, PyObject * kwds)
562 char * kwlist[] = {"octets", NULL};
564 if (!PyArg_ParseTupleAndKeywords(args, kwds, "S:PgpPrtPkts", kwlist, &blob))
567 pkt = (unsigned char *)PyString_AsString(blob);
568 pktlen = PyString_Size(blob);
570 rc = pgpPrtPkts(pkt, pktlen, NULL, 1);
572 return Py_BuildValue("i", rc);
576 rpmts_PgpImportPubkey(rpmtsObject * s, PyObject * args, PyObject * kwds)
582 char * kwlist[] = {"pubkey", NULL};
584 if (!PyArg_ParseTupleAndKeywords(args, kwds, "S:PgpImportPubkey",
588 pkt = (unsigned char *)PyString_AsString(blob);
589 pktlen = PyString_Size(blob);
591 rc = rpmtsImportPubkey(s->ts, pkt, pktlen);
593 return Py_BuildValue("i", rc);
597 rpmts_GetKeys(rpmtsObject * s)
599 const void **data = NULL;
603 rpmtsGetKeys(s->ts, &data, &num);
604 if (data == NULL || num <= 0) {
609 tuple = PyTuple_New(num);
611 for (i = 0; i < num; i++) {
613 obj = (data[i] ? (PyObject *) data[i] : Py_None);
615 PyTuple_SetItem(tuple, i, obj);
624 rpmtsCallback(const void * hd, const rpmCallbackType what,
625 const rpm_loff_t amount, const rpm_loff_t total,
626 const void * pkgKey, rpmCallbackData data)
628 Header h = (Header) hd;
629 struct rpmtsCallbackType_s * cbInfo = data;
630 PyObject * pkgObj = (PyObject *) pkgKey;
631 PyObject * args, * result;
634 if (cbInfo->cb == Py_None) return NULL;
636 /* Synthesize a python object for callback (if necessary). */
637 if (pkgObj == NULL) {
639 pkgObj = Py_BuildValue("s", headerGetString(h, RPMTAG_NAME));
647 PyEval_RestoreThread(cbInfo->_save);
649 args = Py_BuildValue("(iLLOO)", what, amount, total, pkgObj, cbInfo->data);
650 result = PyEval_CallObject(cbInfo->cb, args);
658 if (what == RPMCALLBACK_INST_OPEN_FILE) {
661 if (!PyArg_Parse(result, "i", &fdno)) {
665 cbInfo->_save = PyEval_SaveThread();
668 fcntl(Fileno(fd), F_SETFD, FD_CLOEXEC);
672 if (what == RPMCALLBACK_INST_CLOSE_FILE) {
677 cbInfo->_save = PyEval_SaveThread();
682 static PyObject * rpmts_SetFlags(rpmtsObject * s, PyObject * arg)
684 return wrapSetGetOld(s, "_flags", arg);
687 static PyObject * rpmts_SetProbFilter(rpmtsObject * s, PyObject * arg)
689 return wrapSetGetOld(s, "_probFilter", arg);
693 rpmts_Problems(rpmtsObject * s)
695 return rpmps_Wrap(&rpmps_Type, rpmtsProblems(s->ts));
699 rpmts_Run(rpmtsObject * s, PyObject * args, PyObject * kwds)
705 struct rpmtsCallbackType_s cbInfo;
706 char * kwlist[] = {"callback", "data", NULL};
708 if (!PyArg_ParseTupleAndKeywords(args, kwds, "OO:Run", kwlist,
709 &cbInfo.cb, &cbInfo.data))
713 cbInfo._save = PyEval_SaveThread();
715 if (cbInfo.cb != NULL) {
716 if (!PyCallable_Check(cbInfo.cb)) {
717 PyErr_SetString(PyExc_TypeError, "expected a callable");
720 (void) rpmtsSetNotifyCallback(s->ts, rpmtsCallback, (void *) &cbInfo);
723 rc = rpmtsRun(s->ts, NULL, s->ignoreSet);
724 ps = rpmtsProblems(s->ts);
727 (void) rpmtsSetNotifyCallback(s->ts, NULL, NULL);
729 PyEval_RestoreThread(cbInfo._save);
732 list = PyList_New(0);
738 list = PyList_New(0);
739 psi = rpmpsInitIterator(ps);
740 while (rpmpsNextIterator(psi) >= 0) {
741 rpmProblem p = rpmpsGetProblem(psi);
742 char * ps = rpmProblemString(p);
743 PyObject * prob = Py_BuildValue("s(isN)", ps,
744 rpmProblemGetType(p),
746 PyLong_FromLongLong(rpmProblemGetDiskNeed(p)));
747 PyList_Append(list, prob);
752 psi = rpmpsFreeIterator(psi);
759 rpmts_iternext(rpmtsObject * s)
761 PyObject * result = NULL;
764 /* Reset iterator on 1st entry. */
765 if (s->tsi == NULL) {
766 s->tsi = rpmtsiInit(s->ts);
771 te = rpmtsiNext(s->tsi, 0);
773 result = rpmte_Wrap(&rpmte_Type, te);
775 s->tsi = rpmtsiFree(s->tsi);
782 spec_Parse(rpmtsObject * s, PyObject * args, PyObject * kwds)
784 DEPRECATED_METHOD("use 'spec = rpm.spec(<specfile>)' instead");
785 /* we could pass in the ts from here but hardly worth the trouble */
786 return PyObject_Call((PyObject *) &spec_Type, args, kwds);
790 rpmts_Match(rpmtsObject * s, PyObject * args, PyObject * kwds)
792 PyObject *Key = NULL;
794 /* XXX lkey *must* be a 32 bit integer, int "works" on all known platforms. */
797 rpmTag tag = RPMDBI_PACKAGES;
798 char * kwlist[] = {"tagNumber", "key", NULL};
800 if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O&O:Match", kwlist,
801 tagNumFromPyObject, &tag, &Key))
805 if (PyString_Check(Key)) {
806 key = PyString_AsString(Key);
807 len = PyString_Size(Key);
808 } else if (PyInt_Check(Key)) {
809 lkey = PyInt_AsLong(Key);
813 PyErr_SetString(PyExc_TypeError, "unknown key type");
816 /* One of the conversions above failed, exception is set already */
817 if (PyErr_Occurred()) {
822 /* XXX If not already opened, open the database O_RDONLY now. */
823 /* XXX FIXME: lazy default rdonly open also done by rpmtsInitIterator(). */
824 if (rpmtsGetRdb(s->ts) == NULL) {
825 int rc = rpmtsOpenDB(s->ts, O_RDONLY);
826 if (rc || rpmtsGetRdb(s->ts) == NULL) {
827 PyErr_SetString(PyExc_TypeError, "rpmdb open failed");
832 return rpmmi_Wrap(&rpmmi_Type, rpmtsInitIterator(s->ts, tag, key, len), (PyObject*)s);
835 static struct PyMethodDef rpmts_methods[] = {
836 {"addInstall", (PyCFunction) rpmts_AddInstall, METH_VARARGS|METH_KEYWORDS,
838 {"addErase", (PyCFunction) rpmts_AddErase, METH_VARARGS|METH_KEYWORDS,
840 {"check", (PyCFunction) rpmts_Check, METH_VARARGS|METH_KEYWORDS,
842 {"order", (PyCFunction) rpmts_Order, METH_NOARGS,
844 {"setFlags", (PyCFunction) rpmts_SetFlags, METH_O,
845 "ts.setFlags(transFlags) -> previous transFlags\n\
846 - Set control bit(s) for executing ts.run().\n\
847 Note: This method replaces the 1st argument to the old ts.run()\n" },
848 {"setProbFilter", (PyCFunction) rpmts_SetProbFilter, METH_O,
849 "ts.setProbFilter(ignoreSet) -> previous ignoreSet\n\
850 - Set control bit(s) for ignoring problems found by ts.run().\n\
851 Note: This method replaces the 2nd argument to the old ts.run()\n" },
852 {"problems", (PyCFunction) rpmts_Problems, METH_NOARGS,
853 "ts.problems() -> ps\n\
854 - Return current problem set.\n" },
855 {"run", (PyCFunction) rpmts_Run, METH_VARARGS|METH_KEYWORDS,
856 "ts.run(callback, data) -> (problems)\n\
857 - Run a transaction set, returning list of problems found.\n\
858 Note: The callback may not be None.\n" },
859 {"clean", (PyCFunction) rpmts_Clean, METH_NOARGS,
861 {"openDB", (PyCFunction) rpmts_OpenDB, METH_NOARGS,
862 "ts.openDB() -> None\n\
863 - Open the default transaction rpmdb.\n\
864 Note: The transaction rpmdb is lazily opened, so ts.openDB() is seldom needed.\n" },
865 {"closeDB", (PyCFunction) rpmts_CloseDB, METH_NOARGS,
866 "ts.closeDB() -> None\n\
867 - Close the default transaction rpmdb.\n\
868 Note: ts.closeDB() disables lazy opens, and should hardly ever be used.\n" },
869 {"initDB", (PyCFunction) rpmts_InitDB, METH_NOARGS,
870 "ts.initDB() -> None\n\
871 - Initialize the default transaction rpmdb.\n\
872 Note: ts.initDB() is seldom needed anymore.\n" },
873 {"rebuildDB", (PyCFunction) rpmts_RebuildDB, METH_NOARGS,
874 "ts.rebuildDB() -> None\n\
875 - Rebuild the default transaction rpmdb.\n" },
876 {"verifyDB", (PyCFunction) rpmts_VerifyDB, METH_NOARGS,
877 "ts.verifyDB() -> None\n\
878 - Verify the default transaction rpmdb.\n" },
879 {"hdrFromFdno",(PyCFunction) rpmts_HdrFromFdno,METH_VARARGS|METH_KEYWORDS,
880 "ts.hdrFromFdno(fdno) -> hdr\n\
881 - Read a package header from a file descriptor.\n" },
882 {"hdrCheck", (PyCFunction) rpmts_HdrCheck, METH_VARARGS|METH_KEYWORDS,
884 {"setVSFlags",(PyCFunction) rpmts_SetVSFlags, METH_O,
885 "ts.setVSFlags(vsflags) -> ovsflags\n\
886 - Set signature verification flags. Values for vsflags are:\n\
887 rpm.RPMVSF_NOHDRCHK if set, don't check rpmdb headers\n\
888 rpm.RPMVSF_NEEDPAYLOAD if not set, check header+payload (if possible)\n\
889 rpm.RPMVSF_NOSHA1HEADER if set, don't check header SHA1 digest\n\
890 rpm.RPMVSF_NODSAHEADER if set, don't check header DSA signature\n\
891 rpm.RPMVSF_NOMD5 if set, don't check header+payload MD5 digest\n\
892 rpm.RPMVSF_NODSA if set, don't check header+payload DSA signature\n\
893 rpm.RPMVSF_NORSA if set, don't check header+payload RSA signature\n\
894 rpm._RPMVSF_NODIGESTS if set, don't check digest(s)\n\
895 rpm._RPMVSF_NOSIGNATURES if set, don't check signature(s)\n" },
896 {"getVSFlags",(PyCFunction) rpmts_GetVSFlags, METH_NOARGS,
897 "ts.getVSFlags() -> vsflags\n\
898 - Retrieve current signature verification flags from transaction\n" },
899 {"setColor",(PyCFunction) rpmts_SetColor, METH_O,
901 {"pgpPrtPkts", (PyCFunction) rpmts_PgpPrtPkts, METH_VARARGS|METH_KEYWORDS,
903 {"pgpImportPubkey", (PyCFunction) rpmts_PgpImportPubkey, METH_VARARGS|METH_KEYWORDS,
905 {"getKeys", (PyCFunction) rpmts_GetKeys, METH_NOARGS,
907 {"parseSpec", (PyCFunction) spec_Parse, METH_VARARGS|METH_KEYWORDS,
908 "ts.parseSpec(\"/path/to/foo.spec\") -> spec\n\
909 - Parse a spec file.\n" },
910 {"dbMatch", (PyCFunction) rpmts_Match, METH_VARARGS|METH_KEYWORDS,
911 "ts.dbMatch([TagN, [key, [len]]]) -> mi\n\
912 - Create a match iterator for the default transaction rpmdb.\n" },
913 {NULL, NULL} /* sentinel */
916 static void rpmts_dealloc(rpmtsObject * s)
919 s->ts = rpmtsFree(s->ts);
921 if (s->scriptFd) Fclose(s->scriptFd);
922 /* this will free the keyList, and decrement the ref count of all
923 the items on the list as well :-) */
924 Py_DECREF(s->keyList);
925 s->ob_type->tp_free((PyObject *)s);
928 static PyObject * rpmts_new(PyTypeObject * subtype, PyObject *args, PyObject *kwds)
930 char * rootDir = "/";
931 rpmVSFlags vsflags = rpmExpandNumeric("%{?__vsflags}");
932 char * kwlist[] = {"rootdir", "vsflags", 0};
935 if (!PyArg_ParseTupleAndKeywords(args, kwds, "|si:rpmts_new", kwlist,
940 (void) rpmtsSetRootDir(ts, rootDir);
941 /* XXX: make this use common code with rpmts_SetVSFlags() to check the
943 (void) rpmtsSetVSFlags(ts, vsflags);
945 return rpmts_Wrap(subtype, ts);
948 static PyObject *rpmts_get_tid(rpmtsObject *s, void *closure)
950 return Py_BuildValue("i", rpmtsGetTid(s->ts));
953 static PyObject *rpmts_get_rootDir(rpmtsObject *s, void *closure)
955 return Py_BuildValue("s", rpmtsRootDir(s->ts));
958 static int rpmts_set_scriptFd(rpmtsObject *s, PyObject *value, void *closure)
961 if (PyArg_Parse(value, "O&", rpmFdFromPyObject, &s->scriptFd)) {
962 rpmtsSetScriptFd(s->ts, s->scriptFd);
963 } else if (value == Py_None) {
966 rpmtsSetScriptFd(s->ts, NULL);
973 static PyObject *rpmts_get_color(rpmtsObject *s, void *closure)
975 return Py_BuildValue("i", rpmtsColor(s->ts));
978 static PyObject *rpmts_get_prefcolor(rpmtsObject *s, void *closure)
980 return Py_BuildValue("i", rpmtsPrefColor(s->ts));
983 static int rpmts_set_color(rpmtsObject *s, PyObject *value, void *closure)
986 if (!PyArg_Parse(value, "i", &color)) return -1;
988 /* TODO: validate the bits */
989 rpmtsSetColor(s->ts, color);
993 static int rpmts_set_prefcolor(rpmtsObject *s, PyObject *value, void *closure)
996 if (!PyArg_Parse(value, "i", &color)) return -1;
998 /* TODO: validate the bits */
999 rpmtsSetPrefColor(s->ts, color);
1003 static int rpmts_set_flags(rpmtsObject *s, PyObject *value, void *closure)
1005 rpmtransFlags flags;
1006 if (!PyArg_Parse(value, "i", &flags)) return -1;
1008 /* TODO: validate the bits */
1009 rpmtsSetFlags(s->ts, flags);
1013 static int rpmts_set_vsflags(rpmtsObject *s, PyObject *value, void *closure)
1016 if (!PyArg_Parse(value, "i", &flags)) return -1;
1018 /* TODO: validate the bits */
1019 rpmtsSetVSFlags(s->ts, flags);
1023 static PyObject *rpmts_get_flags(rpmtsObject *s, void *closure)
1025 return Py_BuildValue("i", rpmtsFlags(s->ts));
1028 static PyObject *rpmts_get_vsflags(rpmtsObject *s, void *closure)
1030 return Py_BuildValue("i", rpmtsVSFlags(s->ts));
1033 static char rpmts_doc[] =
1036 static PyMemberDef rpmts_members[] = {
1037 {"_probFilter", T_INT, offsetof(rpmtsObject, ignoreSet), 0, NULL},
1041 static PyGetSetDef rpmts_getseters[] = {
1042 /* only provide a setter until we have rpmfd wrappings */
1043 {"scriptFd", NULL, (setter)rpmts_set_scriptFd, NULL },
1044 {"tid", (getter)rpmts_get_tid, NULL, NULL },
1045 {"rootDir", (getter)rpmts_get_rootDir, NULL, NULL },
1046 {"_color", (getter)rpmts_get_color, (setter)rpmts_set_color, NULL},
1047 {"_prefcolor", (getter)rpmts_get_prefcolor, (setter)rpmts_set_prefcolor, NULL},
1048 {"_flags", (getter)rpmts_get_flags, (setter)rpmts_set_flags, NULL},
1049 {"_vsflags", (getter)rpmts_get_vsflags, (setter)rpmts_set_vsflags, NULL},
1053 PyTypeObject rpmts_Type = {
1054 PyObject_HEAD_INIT(&PyType_Type)
1056 "rpm.ts", /* tp_name */
1057 sizeof(rpmtsObject), /* tp_size */
1058 0, /* tp_itemsize */
1059 (destructor) rpmts_dealloc, /* tp_dealloc */
1061 (getattrfunc)0, /* tp_getattr */
1062 (setattrfunc)0, /* tp_setattr */
1065 0, /* tp_as_number */
1066 0, /* tp_as_sequence */
1067 0, /* tp_as_mapping */
1071 PyObject_GenericGetAttr, /* tp_getattro */
1072 PyObject_GenericSetAttr, /* tp_setattro */
1073 0, /* tp_as_buffer */
1074 Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, /* tp_flags */
1075 rpmts_doc, /* tp_doc */
1076 0, /* tp_traverse */
1078 0, /* tp_richcompare */
1079 0, /* tp_weaklistoffset */
1080 PyObject_SelfIter, /* tp_iter */
1081 (iternextfunc) rpmts_iternext, /* tp_iternext */
1082 rpmts_methods, /* tp_methods */
1083 rpmts_members, /* tp_members */
1084 rpmts_getseters, /* tp_getset */
1087 0, /* tp_descr_get */
1088 0, /* tp_descr_set */
1089 0, /* tp_dictoffset */
1092 (newfunc) rpmts_new, /* tp_new */
1097 PyObject * rpmts_Wrap(PyTypeObject *subtype, rpmts ts)
1099 rpmtsObject * s = (rpmtsObject *)subtype->tp_alloc(subtype, 0);
1100 if (s == NULL) return PyErr_NoMemory();
1103 s->keyList = PyList_New(0);
1106 return (PyObject *) s;