2 * \file python/rpmts-py.c
7 #include <rpm/rpmlib.h> /* rpmReadPackageFile, headerCheck */
8 #include <rpm/rpmtag.h>
9 #include <rpm/rpmpgp.h>
10 #include <rpm/rpmdb.h>
11 #include <rpm/rpmbuild.h>
13 #include "header-py.h"
14 #include "rpmds-py.h" /* XXX for rpmdsNew */
15 #include "rpmfi-py.h" /* XXX for rpmfiNew */
25 extern int _rpmts_debug;
31 * \brief A python rpm.ts object represents an RPM transaction set.
33 * The transaction set is the workhorse of RPM. It performs the
34 * installation and upgrade of packages. The rpm.ts object is
35 * instantiated by the TransactionSet function in the rpm module.
37 * The TransactionSet function takes two optional arguments. The first
38 * argument is the root path. The second is the verify signature disable flags,
39 * a set of the following bits:
41 * - rpm.RPMVSF_NOHDRCHK if set, don't check rpmdb headers
42 * - rpm.RPMVSF_NEEDPAYLOAD if not set, check header+payload (if possible)
43 * - rpm.RPMVSF_NOSHA1HEADER if set, don't check header SHA1 digest
44 * - rpm.RPMVSF_NODSAHEADER if set, don't check header DSA signature
45 * - rpm.RPMVSF_NOMD5 if set, don't check header+payload MD5 digest
46 * - rpm.RPMVSF_NODSA if set, don't check header+payload DSA signature
47 * - rpm.RPMVSF_NORSA if set, don't check header+payload RSA signature
49 * For convenience, there are the following masks:
50 * - rpm._RPMVSF_NODIGESTS if set, don't check digest(s).
51 * - rpm._RPMVSF_NOSIGNATURES if set, don't check signature(s).
53 * A rpm.ts object has the following methods:
55 * - addInstall(hdr,data,mode) Add an install element to a transaction set.
56 * @param hdr the header to be added
57 * @param data user data that will be passed to the transaction callback
58 * during transaction execution
59 * @param mode optional argument that specifies if this package should
60 * be installed ('i'), upgraded ('u').
62 * - addErase(name) Add an erase element to a transaction set.
63 * @param name the package name to be erased
65 * - check() Perform a dependency check on the transaction set. After
66 * headers have been added to a transaction set, a dependency
67 * check can be performed to make sure that all package
68 * dependencies are satisfied.
69 * @return None If there are no unresolved dependencies
70 * Otherwise a list of complex tuples is returned, one tuple per
71 * unresolved dependency, with
72 * The format of the dependency tuple is:
73 * ((packageName, packageVersion, packageRelease),
74 * (reqName, reqVersion),
78 * packageName, packageVersion, packageRelease are the name,
79 * version, and release of the package that has the unresolved
80 * dependency or conflict.
81 * The reqName and reqVersion are the name and version of the
82 * requirement or conflict.
83 * The needsFlags is a bitfield that describes the versioned
84 * nature of a requirement or conflict. The constants
85 * rpm.RPMSENSE_LESS, rpm.RPMSENSE_GREATER, and
86 * rpm.RPMSENSE_EQUAL can be logical ANDed with the needsFlags
87 * to get versioned dependency information.
88 * suggestedPackage is a tuple if the dependency check was aware
89 * of a package that solves this dependency problem when the
90 * dependency check was run. Packages that are added to the
91 * transaction set as "available" are examined during the
92 * dependency check as possible dependency solvers. The tuple
93 * contains two values, (header, suggestedName). These are set to
94 * the header of the suggested package and its name, respectively.
95 * If there is no known package to solve the dependency problem,
96 * suggestedPackage is None.
97 * The constants rpm.RPMDEP_SENSE_CONFLICTS and
98 * rpm.RPMDEP_SENSE_REQUIRES are set to show a dependency as a
99 * requirement or a conflict.
101 * - ts.order() Do a topological sort of added element relations.
104 * - ts.setFlags(transFlags) Set transaction set flags.
105 * @param transFlags - bit(s) to controll transaction operations. The
106 * following values can be logically OR'ed together:
107 * - rpm.RPMTRANS_FLAG_TEST - test mode, do not modify the RPM
108 * database, change any files, or run any package scripts
109 * - rpm.RPMTRANS_FLAG_BUILD_PROBS - only build a list of
110 * problems encountered when attempting to run this transaction
112 * - rpm.RPMTRANS_FLAG_NOSCRIPTS - do not execute package scripts
113 * - rpm.RPMTRANS_FLAG_JUSTDB - only make changes to the rpm
114 * database, do not modify files.
115 * - rpm.RPMTRANS_FLAG_NOTRIGGERS - do not run trigger scripts
116 * - rpm.RPMTRANS_FLAG_NODOCS - do not install files marked as %doc
117 * - rpm.RPMTRANS_FLAG_ALLFILES - create all files, even if a
118 * file is marked %config(missingok) and an upgrade is
120 * - rpm.RPMTRANS_FLAG_KEEPOBSOLETE - do not remove obsoleted
122 * @return previous transFlags
124 * - ts.setProbFilter(ignoreSet) Set transaction set problem filter.
125 * @param problemSetFilter - control bit(s) to ignore classes of problems,
126 * a logical or of one or more of the following bit(s):
127 * - rpm.RPMPROB_FILTER_IGNOREOS -
128 * - rpm.RPMPROB_FILTER_IGNOREARCH -
129 * - rpm.RPMPROB_FILTER_REPLACEPKG -
130 * - rpm.RPMPROB_FILTER_FORCERELOCATE -
131 * - rpm.RPMPROB_FILTER_REPLACENEWFILES -
132 * - rpm.RPMPROB_FILTER_REPLACEOLDFILES -
133 * - rpm.RPMPROB_FILTER_OLDPACKAGE -
134 * - rpm.RPMPROB_FILTER_DISKSPACE -
135 * @return previous ignoreSet
137 * - ts.run(callback,data) Attempt to execute a transaction set.
138 * After the transaction set has been populated with install/upgrade or
139 * erase actions, the transaction set can be executed by invoking
140 * the ts.run() method.
145 struct rpmtsCallbackType_s {
149 PyThreadState *_save;
155 rpmts_Debug(rpmtsObject * s, PyObject * args, PyObject * kwds)
157 char * kwlist[] = {"debugLevel", NULL};
159 if (!PyArg_ParseTupleAndKeywords(args, kwds, "i:Debug", kwlist,
163 if (_rpmts_debug < 0)
164 fprintf(stderr, "*** rpmts_Debug(%p) ts %p\n", s, s->ts);
170 static void die(PyObject *cb)
175 if (PyErr_Occurred()) {
178 if ((r = PyObject_Repr(cb)) != NULL) {
179 pyfn = PyString_AsString(r);
181 fprintf(stderr, _("error: python callback %s failed, aborting!\n"),
182 pyfn ? pyfn : "???");
183 rpmdbCheckTerminate(1);
190 rpmts_AddInstall(rpmtsObject * s, PyObject * args, PyObject * kwds)
194 char * how = "u"; /* XXX default to upgrade element if missing */
196 char * kwlist[] = {"header", "key", "how", NULL};
199 if (!PyArg_ParseTupleAndKeywords(args, kwds, "O!O|s:AddInstall", kwlist,
200 &hdr_Type, &h, &key, &how))
203 { PyObject * hObj = (PyObject *) h;
204 if (hObj->ob_type != &hdr_Type) {
205 PyErr_SetString(PyExc_TypeError, "bad type for header argument");
210 if (_rpmts_debug < 0 || (_rpmts_debug > 0))
211 fprintf(stderr, "*** rpmts_AddInstall(%p,%p,%p,%s) ts %p\n", s, h, key, how, s->ts);
213 if (how && strcmp(how, "a") && strcmp(how, "u") && strcmp(how, "i")) {
214 PyErr_SetString(PyExc_TypeError, "how argument must be \"u\" or \"i\"");
216 } else if (how && !strcmp(how, "u"))
219 rc = rpmtsAddInstallElement(s->ts, hdrGetHeader(h), key, isUpgrade, NULL);
221 PyErr_SetString(pyrpmError, "adding package to transaction failed");
226 /* This should increment the usage count for me */
228 PyList_Append(s->keyList, key);
235 * @todo Permit finer control (i.e. not just --allmatches) of deleted elments.
238 rpmts_AddErase(rpmtsObject * s, PyObject * args, PyObject * kwds)
242 rpmdbMatchIterator mi;
243 char * kwlist[] = {"name", NULL};
246 fprintf(stderr, "*** rpmts_AddErase(%p) ts %p\n", s, s->ts);
248 if (!PyArg_ParseTupleAndKeywords(args, kwds, "O:AddErase", kwlist, &o))
251 if (PyString_Check(o)) {
252 char * name = PyString_AsString(o);
254 mi = rpmtsInitIterator(s->ts, RPMDBI_LABEL, name, 0);
255 count = rpmdbGetIteratorCount(mi);
257 mi = rpmdbFreeIterator(mi);
258 PyErr_SetString(pyrpmError, "package not installed");
260 } else { /* XXX: Note that we automatically choose to remove all matches */
262 while ((h = rpmdbNextIterator(mi)) != NULL) {
263 rpmtsAddEraseElement(s->ts, h, -1);
266 mi = rpmdbFreeIterator(mi);
268 if (PyInt_Check(o)) {
269 uint32_t instance = PyInt_AsLong(o);
271 mi = rpmtsInitIterator(s->ts, RPMDBI_PACKAGES, &instance, sizeof(instance));
272 if (instance == 0 || mi == NULL) {
273 mi = rpmdbFreeIterator(mi);
274 PyErr_SetString(pyrpmError, "package not installed");
278 while ((h = rpmdbNextIterator(mi)) != NULL) {
279 rpmtsAddEraseElement(s->ts, h, -1);
283 mi = rpmdbFreeIterator(mi);
293 rpmts_SolveCallback(rpmts ts, rpmds ds, const void * data)
295 struct rpmtsCallbackType_s * cbInfo = (struct rpmtsCallbackType_s *) data;
296 PyObject * args, * result;
300 fprintf(stderr, "*** rpmts_SolveCallback(%p,%p,%p) \"%s\"\n", ts, ds, data, rpmdsDNEVR(ds));
302 if (cbInfo->tso == NULL) return res;
303 if (cbInfo->cb == Py_None) return res;
305 PyEval_RestoreThread(cbInfo->_save);
307 args = Py_BuildValue("(Oissi)", cbInfo->tso,
308 rpmdsTagN(ds), rpmdsN(ds), rpmdsEVR(ds), rpmdsFlags(ds));
309 result = PyEval_CallObject(cbInfo->cb, args);
315 if (PyInt_Check(result))
316 res = PyInt_AsLong(result);
320 cbInfo->_save = PyEval_SaveThread();
328 rpmts_Check(rpmtsObject * s, PyObject * args, PyObject * kwds)
332 PyObject * list, * cf;
333 struct rpmtsCallbackType_s cbInfo;
336 char * kwlist[] = {"callback", NULL};
338 memset(&cbInfo, 0, sizeof(cbInfo));
339 if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O:Check", kwlist,
343 if (cbInfo.cb != NULL) {
344 if (!PyCallable_Check(cbInfo.cb)) {
345 PyErr_SetString(PyExc_TypeError, "expected a callable");
348 xx = rpmtsSetSolveCallback(s->ts, rpmts_SolveCallback, (void *)&cbInfo);
352 fprintf(stderr, "*** rpmts_Check(%p) ts %p cb %p\n", s, s->ts, cbInfo.cb);
355 cbInfo._save = PyEval_SaveThread();
357 xx = rpmtsCheck(s->ts);
358 ps = rpmtsProblems(s->ts);
360 PyEval_RestoreThread(cbInfo._save);
363 list = PyList_New(0);
364 rpmpsi psi = rpmpsInitIterator(ps);
366 /* XXX TODO: rpmlib >= 4.0.3 can return multiple suggested keys. */
367 while ((i = rpmpsNextIterator(psi)) >= 0) {
368 const char * needsName;
369 char * byName, * byVersion, * byRelease, *byArch;
370 char * needsOP, * needsVersion;
371 rpmsenseFlags needsFlags, sense;
374 p = rpmpsGetProblem(psi);
376 byName = xstrdup(rpmProblemGetPkgNEVR(p));
377 if ((byArch= strrchr(byName, '.')) != NULL)
379 if ((byRelease = strrchr(byName, '-')) != NULL)
381 if ((byVersion = strrchr(byName, '-')) != NULL)
384 key = rpmProblemGetKey(p);
386 needsName = rpmProblemGetAltNEVR(p);
387 if (needsName[1] == ' ') {
388 sense = (needsName[0] == 'C')
389 ? RPMDEP_SENSE_CONFLICTS : RPMDEP_SENSE_REQUIRES;
392 sense = RPMDEP_SENSE_REQUIRES;
393 if ((needsVersion = strrchr(needsName, ' ')) != NULL)
394 *needsVersion++ = '\0';
397 if ((needsOP = strrchr(needsName, ' ')) != NULL) {
398 for (*needsOP++ = '\0'; *needsOP != '\0'; needsOP++) {
399 if (*needsOP == '<') needsFlags |= RPMSENSE_LESS;
400 else if (*needsOP == '>') needsFlags |= RPMSENSE_GREATER;
401 else if (*needsOP == '=') needsFlags |= RPMSENSE_EQUAL;
405 cf = Py_BuildValue("((sss)(ss)iOi)", byName, byVersion, byRelease,
406 needsName, needsVersion, needsFlags,
407 (key != NULL ? key : Py_None),
409 PyList_Append(list, (PyObject *) cf);
414 psi = rpmpsFreeIterator(psi);
427 rpmts_Order(rpmtsObject * s)
432 fprintf(stderr, "*** rpmts_Order(%p) ts %p\n", s, s->ts);
434 Py_BEGIN_ALLOW_THREADS
435 rc = rpmtsOrder(s->ts);
438 return Py_BuildValue("i", rc);
444 rpmts_Clean(rpmtsObject * s)
447 fprintf(stderr, "*** rpmts_Clean(%p) ts %p\n", s, s->ts);
458 rpmts_OpenDB(rpmtsObject * s)
463 fprintf(stderr, "*** rpmts_OpenDB(%p) ts %p\n", s, s->ts);
465 dbmode = rpmtsGetDBMode(s->ts);
469 return Py_BuildValue("i", rpmtsOpenDB(s->ts, dbmode));
475 rpmts_CloseDB(rpmtsObject * s)
480 fprintf(stderr, "*** rpmts_CloseDB(%p) ts %p\n", s, s->ts);
482 rc = rpmtsCloseDB(s->ts);
483 rpmtsSetDBMode(s->ts, -1); /* XXX disable lazy opens */
485 return Py_BuildValue("i", rc);
491 rpmts_InitDB(rpmtsObject * s)
496 fprintf(stderr, "*** rpmts_InitDB(%p) ts %p\n", s, s->ts);
498 rc = rpmtsInitDB(s->ts, O_RDONLY);
500 rc = rpmtsCloseDB(s->ts);
502 return Py_BuildValue("i", rc);
508 rpmts_RebuildDB(rpmtsObject * s)
513 fprintf(stderr, "*** rpmts_RebuildDB(%p) ts %p\n", s, s->ts);
515 Py_BEGIN_ALLOW_THREADS
516 rc = rpmtsRebuildDB(s->ts);
519 return Py_BuildValue("i", rc);
525 rpmts_VerifyDB(rpmtsObject * s)
530 fprintf(stderr, "*** rpmts_VerifyDB(%p) ts %p\n", s, s->ts);
532 Py_BEGIN_ALLOW_THREADS
533 rc = rpmtsVerifyDB(s->ts);
536 return Py_BuildValue("i", rc);
542 rpmts_HdrFromFdno(rpmtsObject * s, PyObject * args, PyObject * kwds)
544 PyObject * result = NULL;
549 char * kwlist[] = {"fd", NULL};
551 if (!PyArg_ParseTupleAndKeywords(args, kwds, "i:HdrFromFdno", kwlist,
556 rpmrc = rpmReadPackageFile(s->ts, fd, "rpmts_HdrFromFdno", &h);
560 fprintf(stderr, "*** rpmts_HdrFromFdno(%p) ts %p rc %d\n", s, s->ts, rpmrc);
565 result = Py_BuildValue("N", hdr_Wrap(h));
566 h = headerFree(h); /* XXX ref held by result */
570 PyErr_SetString(pyrpmError, "public key not available");
573 case RPMRC_NOTTRUSTED:
574 PyErr_SetString(pyrpmError, "public key not trusted");
580 PyErr_SetString(pyrpmError, "error reading package header");
590 rpmts_HdrCheck(rpmtsObject * s, PyObject * args, PyObject * kwds)
593 PyObject * result = NULL;
598 char * kwlist[] = {"headers", NULL};
601 fprintf(stderr, "*** rpmts_HdrCheck(%p) ts %p\n", s, s->ts);
603 if (!PyArg_ParseTupleAndKeywords(args, kwds, "O:HdrCheck", kwlist, &blob))
606 if (blob == Py_None) {
610 if (!PyString_Check(blob)) {
611 PyErr_SetString(pyrpmError, "hdrCheck takes a string of octets");
614 uh = PyString_AsString(blob);
615 uc = PyString_Size(blob);
617 rpmrc = headerCheck(s->ts, uh, uc, &msg);
626 PyErr_SetString(pyrpmError, "public key not availaiable");
629 case RPMRC_NOTTRUSTED:
630 PyErr_SetString(pyrpmError, "public key not trusted");
635 PyErr_SetString(pyrpmError, msg);
646 rpmts_SetVSFlags(rpmtsObject * s, PyObject * args, PyObject * kwds)
649 char * kwlist[] = {"flags", NULL};
652 fprintf(stderr, "*** rpmts_SetVSFlags(%p) ts %p\n", s, s->ts);
654 if (!PyArg_ParseTupleAndKeywords(args, kwds, "i:SetVSFlags", kwlist,
658 /* XXX FIXME: value check on vsflags, or build pure python object
659 * for it, and require an object of that type */
661 return Py_BuildValue("i", rpmtsSetVSFlags(s->ts, vsflags));
667 rpmts_GetVSFlags(rpmtsObject * s)
669 return Py_BuildValue("i", rpmtsVSFlags(s->ts));
675 rpmts_SetColor(rpmtsObject * s, PyObject * args, PyObject * kwds)
678 char * kwlist[] = {"color", NULL};
681 fprintf(stderr, "*** rpmts_SetColor(%p) ts %p\n", s, s->ts);
683 if (!PyArg_ParseTupleAndKeywords(args, kwds, "i:Color", kwlist, &tscolor))
686 /* XXX FIXME: value check on tscolor, or build pure python object
687 * for it, and require an object of that type */
689 return Py_BuildValue("i", rpmtsSetColor(s->ts, tscolor));
695 rpmts_PgpPrtPkts(rpmtsObject * s, PyObject * args, PyObject * kwds)
701 char * kwlist[] = {"octets", NULL};
704 fprintf(stderr, "*** rpmts_PgpPrtPkts(%p) ts %p\n", s, s->ts);
706 if (!PyArg_ParseTupleAndKeywords(args, kwds, "O:PgpPrtPkts", kwlist, &blob))
709 if (blob == Py_None) {
713 if (!PyString_Check(blob)) {
714 PyErr_SetString(pyrpmError, "pgpPrtPkts takes a string of octets");
717 pkt = (unsigned char *)PyString_AsString(blob);
718 pktlen = PyString_Size(blob);
720 rc = pgpPrtPkts(pkt, pktlen, NULL, 1);
722 return Py_BuildValue("i", rc);
728 rpmts_PgpImportPubkey(rpmtsObject * s, PyObject * args, PyObject * kwds)
734 char * kwlist[] = {"pubkey", NULL};
737 fprintf(stderr, "*** rpmts_PgpImportPubkey(%p) ts %p\n", s, s->ts);
739 if (!PyArg_ParseTupleAndKeywords(args, kwds, "O:PgpImportPubkey",
743 if (blob == Py_None) {
747 if (!PyString_Check(blob)) {
748 PyErr_SetString(pyrpmError, "PgpImportPubkey takes a string of octets");
751 pkt = (unsigned char *)PyString_AsString(blob);
752 pktlen = PyString_Size(blob);
754 rc = rpmtsImportPubkey(s->ts, pkt, pktlen);
756 return Py_BuildValue("i", rc);
762 rpmts_GetKeys(rpmtsObject * s)
764 const void **data = NULL;
769 fprintf(stderr, "*** rpmts_GetKeys(%p) ts %p\n", s, s->ts);
771 rpmtsGetKeys(s->ts, &data, &num);
772 if (data == NULL || num <= 0) {
778 tuple = PyTuple_New(num);
780 for (i = 0; i < num; i++) {
782 obj = (data[i] ? (PyObject *) data[i] : Py_None);
784 PyTuple_SetItem(tuple, i, obj);
795 rpmtsCallback(const void * hd, const rpmCallbackType what,
796 const rpm_loff_t amount, const rpm_loff_t total,
797 const void * pkgKey, rpmCallbackData data)
799 Header h = (Header) hd;
800 struct rpmtsCallbackType_s * cbInfo = data;
801 PyObject * pkgObj = (PyObject *) pkgKey;
802 PyObject * args, * result;
805 if (cbInfo->cb == Py_None) return NULL;
807 /* Synthesize a python object for callback (if necessary). */
808 if (pkgObj == NULL) {
810 const char * n = NULL;
811 (void) headerNVR(h, &n, NULL, NULL);
812 pkgObj = Py_BuildValue("s", n);
820 PyEval_RestoreThread(cbInfo->_save);
822 args = Py_BuildValue("(iLLOO)", what, amount, total, pkgObj, cbInfo->data);
823 result = PyEval_CallObject(cbInfo->cb, args);
831 if (what == RPMCALLBACK_INST_OPEN_FILE) {
834 if (!PyArg_Parse(result, "i", &fdno)) {
838 cbInfo->_save = PyEval_SaveThread();
842 fprintf(stderr, "\t%p = fdDup(%d)\n", fd, fdno);
844 fcntl(Fileno(fd), F_SETFD, FD_CLOEXEC);
848 if (what == RPMCALLBACK_INST_CLOSE_FILE) {
850 fprintf(stderr, "\tFclose(%p)\n", fd);
854 fprintf(stderr, "\t%llu:%llu key %p\n", (long long) amount, (long long) total, pkgKey);
858 cbInfo->_save = PyEval_SaveThread();
866 rpmts_SetFlags(rpmtsObject * s, PyObject * args, PyObject * kwds)
868 rpmtransFlags transFlags = 0;
869 char * kwlist[] = {"flags", NULL};
871 if (!PyArg_ParseTupleAndKeywords(args, kwds, "i:SetFlags", kwlist,
876 fprintf(stderr, "*** rpmts_SetFlags(%p) ts %p transFlags %x\n", s, s->ts, transFlags);
878 /* XXX FIXME: value check on flags, or build pure python object
879 * for it, and require an object of that type */
881 return Py_BuildValue("i", rpmtsSetFlags(s->ts, transFlags));
887 rpmts_SetProbFilter(rpmtsObject * s, PyObject * args, PyObject * kwds)
889 rpmprobFilterFlags ignoreSet = 0;
890 rpmprobFilterFlags oignoreSet;
891 char * kwlist[] = {"ignoreSet", NULL};
893 if (!PyArg_ParseTupleAndKeywords(args, kwds, "i:ProbFilter", kwlist,
898 fprintf(stderr, "*** rpmts_SetProbFilter(%p) ts %p ignoreSet %x\n", s, s->ts, ignoreSet);
900 oignoreSet = s->ignoreSet;
901 s->ignoreSet = ignoreSet;
903 return Py_BuildValue("i", oignoreSet);
909 rpmts_Problems(rpmtsObject * s)
913 fprintf(stderr, "*** rpmts_Problems(%p) ts %p\n", s, s->ts);
915 return rpmps_Wrap( rpmtsProblems(s->ts) );
921 rpmts_Run(rpmtsObject * s, PyObject * args, PyObject * kwds)
927 struct rpmtsCallbackType_s cbInfo;
928 char * kwlist[] = {"callback", "data", NULL};
930 if (!PyArg_ParseTupleAndKeywords(args, kwds, "OO:Run", kwlist,
931 &cbInfo.cb, &cbInfo.data))
935 cbInfo._save = PyEval_SaveThread();
937 if (cbInfo.cb != NULL) {
938 if (!PyCallable_Check(cbInfo.cb)) {
939 PyErr_SetString(PyExc_TypeError, "expected a callable");
942 (void) rpmtsSetNotifyCallback(s->ts, rpmtsCallback, (void *) &cbInfo);
946 fprintf(stderr, "*** rpmts_Run(%p) ts %p ignore %x\n", s, s->ts, s->ignoreSet);
948 rc = rpmtsRun(s->ts, NULL, s->ignoreSet);
949 ps = rpmtsProblems(s->ts);
952 (void) rpmtsSetNotifyCallback(s->ts, NULL, NULL);
954 PyEval_RestoreThread(cbInfo._save);
957 list = PyList_New(0);
964 list = PyList_New(0);
965 psi = rpmpsInitIterator(ps);
966 while (rpmpsNextIterator(psi) >= 0) {
967 rpmProblem p = rpmpsGetProblem(psi);
968 char * ps = rpmProblemString(p);
969 PyObject * prob = Py_BuildValue("s(isN)", ps,
970 rpmProblemGetType(p),
972 PyLong_FromLongLong(rpmProblemGetDiskNeed(p)));
973 PyList_Append(list, prob);
978 psi = rpmpsFreeIterator(psi);
984 #if Py_TPFLAGS_HAVE_ITER
986 rpmts_iter(rpmtsObject * s)
989 fprintf(stderr, "*** rpmts_iter(%p) ts %p\n", s, s->ts);
992 return (PyObject *)s;
997 * @todo Add TR_ADDED filter to iterator.
1000 rpmts_iternext(rpmtsObject * s)
1002 PyObject * result = NULL;
1006 fprintf(stderr, "*** rpmts_iternext(%p) ts %p tsi %p %d\n", s, s->ts, s->tsi, s->tsiFilter);
1008 /* Reset iterator on 1st entry. */
1009 if (s->tsi == NULL) {
1010 s->tsi = rpmtsiInit(s->ts);
1016 te = rpmtsiNext(s->tsi, s->tsiFilter);
1018 result = (PyObject *) rpmte_Wrap(te);
1020 s->tsi = rpmtsiFree(s->tsi);
1028 * @todo Add TR_ADDED filter to iterator.
1031 rpmts_Next(rpmtsObject * s)
1036 fprintf(stderr, "*** rpmts_Next(%p) ts %p\n", s, s->ts);
1038 result = rpmts_iternext(s);
1040 if (result == NULL) {
1051 spec_Parse(rpmtsObject * s, PyObject * args, PyObject * kwds)
1053 const char * specfile;
1055 char * buildRoot = NULL;
1057 char * passPhrase = "";
1058 char *cookie = NULL;
1061 char * kwlist[] = {"specfile", NULL};
1063 if (!PyArg_ParseTupleAndKeywords(args, kwds, "s:Parse", kwlist, &specfile))
1066 if (parseSpec(s->ts, specfile,"/", buildRoot,recursing, passPhrase,
1067 cookie, anyarch, force)!=0) {
1068 PyErr_SetString(pyrpmError, "can't parse specfile\n");
1072 spec = rpmtsSpec(s->ts);
1073 return spec_Wrap(spec);
1078 static rpmmiObject *
1079 rpmts_Match(rpmtsObject * s, PyObject * args, PyObject * kwds)
1081 PyObject *TagN = NULL;
1082 PyObject *Key = NULL;
1084 /* XXX lkey *must* be a 32 bit integer, int "works" on all known platforms. */
1087 rpmTag tag = RPMDBI_PACKAGES;
1088 char * kwlist[] = {"tagNumber", "key", NULL};
1091 fprintf(stderr, "*** rpmts_Match(%p) ts %p\n", s, s->ts);
1093 if (!PyArg_ParseTupleAndKeywords(args, kwds, "|OO:Match", kwlist,
1097 if (TagN && (tag = tagNumFromPyObject (TagN)) == -1) {
1098 PyErr_SetString(PyExc_TypeError, "unknown tag type");
1103 if (PyString_Check(Key)) {
1104 key = PyString_AsString(Key);
1105 len = PyString_Size(Key);
1106 } else if (PyInt_Check(Key)) {
1107 lkey = PyInt_AsLong(Key);
1108 key = (char *)&lkey;
1111 PyErr_SetString(PyExc_TypeError, "unknown key type");
1114 /* One of the conversions above failed, exception is set already */
1115 if (PyErr_Occurred()) {
1120 /* XXX If not already opened, open the database O_RDONLY now. */
1121 /* XXX FIXME: lazy default rdonly open also done by rpmtsInitIterator(). */
1122 if (rpmtsGetRdb(s->ts) == NULL) {
1123 int rc = rpmtsOpenDB(s->ts, O_RDONLY);
1124 if (rc || rpmtsGetRdb(s->ts) == NULL) {
1125 PyErr_SetString(PyExc_TypeError, "rpmdb open failed");
1130 return rpmmi_Wrap( rpmtsInitIterator(s->ts, tag, key, len), (PyObject*)s);
1135 static struct PyMethodDef rpmts_methods[] = {
1136 {"Debug", (PyCFunction)rpmts_Debug, METH_VARARGS|METH_KEYWORDS,
1139 {"addInstall", (PyCFunction) rpmts_AddInstall, METH_VARARGS|METH_KEYWORDS,
1141 {"addErase", (PyCFunction) rpmts_AddErase, METH_VARARGS|METH_KEYWORDS,
1143 {"check", (PyCFunction) rpmts_Check, METH_VARARGS|METH_KEYWORDS,
1145 {"order", (PyCFunction) rpmts_Order, METH_NOARGS,
1147 {"setFlags", (PyCFunction) rpmts_SetFlags, METH_VARARGS|METH_KEYWORDS,
1148 "ts.setFlags(transFlags) -> previous transFlags\n\
1149 - Set control bit(s) for executing ts.run().\n\
1150 Note: This method replaces the 1st argument to the old ts.run()\n" },
1151 {"setProbFilter", (PyCFunction) rpmts_SetProbFilter, METH_VARARGS|METH_KEYWORDS,
1152 "ts.setProbFilter(ignoreSet) -> previous ignoreSet\n\
1153 - Set control bit(s) for ignoring problems found by ts.run().\n\
1154 Note: This method replaces the 2nd argument to the old ts.run()\n" },
1155 {"problems", (PyCFunction) rpmts_Problems, METH_NOARGS,
1156 "ts.problems() -> ps\n\
1157 - Return current problem set.\n" },
1158 {"run", (PyCFunction) rpmts_Run, METH_VARARGS|METH_KEYWORDS,
1159 "ts.run(callback, data) -> (problems)\n\
1160 - Run a transaction set, returning list of problems found.\n\
1161 Note: The callback may not be None.\n" },
1162 {"clean", (PyCFunction) rpmts_Clean, METH_NOARGS,
1164 {"openDB", (PyCFunction) rpmts_OpenDB, METH_NOARGS,
1165 "ts.openDB() -> None\n\
1166 - Open the default transaction rpmdb.\n\
1167 Note: The transaction rpmdb is lazily opened, so ts.openDB() is seldom needed.\n" },
1168 {"closeDB", (PyCFunction) rpmts_CloseDB, METH_NOARGS,
1169 "ts.closeDB() -> None\n\
1170 - Close the default transaction rpmdb.\n\
1171 Note: ts.closeDB() disables lazy opens, and should hardly ever be used.\n" },
1172 {"initDB", (PyCFunction) rpmts_InitDB, METH_NOARGS,
1173 "ts.initDB() -> None\n\
1174 - Initialize the default transaction rpmdb.\n\
1175 Note: ts.initDB() is seldom needed anymore.\n" },
1176 {"rebuildDB", (PyCFunction) rpmts_RebuildDB, METH_NOARGS,
1177 "ts.rebuildDB() -> None\n\
1178 - Rebuild the default transaction rpmdb.\n" },
1179 {"verifyDB", (PyCFunction) rpmts_VerifyDB, METH_NOARGS,
1180 "ts.verifyDB() -> None\n\
1181 - Verify the default transaction rpmdb.\n" },
1182 {"hdrFromFdno",(PyCFunction) rpmts_HdrFromFdno,METH_VARARGS|METH_KEYWORDS,
1183 "ts.hdrFromFdno(fdno) -> hdr\n\
1184 - Read a package header from a file descriptor.\n" },
1185 {"hdrCheck", (PyCFunction) rpmts_HdrCheck, METH_VARARGS|METH_KEYWORDS,
1187 {"setVSFlags",(PyCFunction) rpmts_SetVSFlags, METH_VARARGS|METH_KEYWORDS,
1188 "ts.setVSFlags(vsflags) -> ovsflags\n\
1189 - Set signature verification flags. Values for vsflags are:\n\
1190 rpm.RPMVSF_NOHDRCHK if set, don't check rpmdb headers\n\
1191 rpm.RPMVSF_NEEDPAYLOAD if not set, check header+payload (if possible)\n\
1192 rpm.RPMVSF_NOSHA1HEADER if set, don't check header SHA1 digest\n\
1193 rpm.RPMVSF_NODSAHEADER if set, don't check header DSA signature\n\
1194 rpm.RPMVSF_NOMD5 if set, don't check header+payload MD5 digest\n\
1195 rpm.RPMVSF_NODSA if set, don't check header+payload DSA signature\n\
1196 rpm.RPMVSF_NORSA if set, don't check header+payload RSA signature\n\
1197 rpm._RPMVSF_NODIGESTS if set, don't check digest(s)\n\
1198 rpm._RPMVSF_NOSIGNATURES if set, don't check signature(s)\n" },
1199 {"getVSFlags",(PyCFunction) rpmts_GetVSFlags, METH_NOARGS,
1200 "ts.getVSFlags() -> vsflags\n\
1201 - Retrieve current signature verification flags from transaction\n" },
1202 {"setColor",(PyCFunction) rpmts_SetColor, METH_VARARGS|METH_KEYWORDS,
1204 {"pgpPrtPkts", (PyCFunction) rpmts_PgpPrtPkts, METH_VARARGS|METH_KEYWORDS,
1206 {"pgpImportPubkey", (PyCFunction) rpmts_PgpImportPubkey, METH_VARARGS|METH_KEYWORDS,
1208 {"getKeys", (PyCFunction) rpmts_GetKeys, METH_NOARGS,
1210 {"parseSpec", (PyCFunction) spec_Parse, METH_VARARGS|METH_KEYWORDS,
1211 "ts.parseSpec(\"/path/to/foo.spec\") -> spec\n\
1212 - Parse a spec file.\n" },
1213 {"dbMatch", (PyCFunction) rpmts_Match, METH_VARARGS|METH_KEYWORDS,
1214 "ts.dbMatch([TagN, [key, [len]]]) -> mi\n\
1215 - Create a match iterator for the default transaction rpmdb.\n" },
1216 {"next", (PyCFunction)rpmts_Next, METH_NOARGS,
1218 - Retrieve next transaction set element.\n" },
1219 {NULL, NULL} /* sentinel */
1224 static void rpmts_dealloc(rpmtsObject * s)
1228 fprintf(stderr, "%p -- ts %p db %p\n", s, s->ts, rpmtsGetRdb(s->ts));
1229 s->ts = rpmtsFree(s->ts);
1231 if (s->scriptFd) Fclose(s->scriptFd);
1232 /* this will free the keyList, and decrement the ref count of all
1233 the items on the list as well :-) */
1234 Py_DECREF(s->keyList);
1235 PyObject_Del((PyObject *)s);
1238 static PyObject * rpmts_getattro(PyObject * o, PyObject * n)
1240 return PyObject_GenericGetAttr(o, n);
1245 static int rpmts_setattro(PyObject * o, PyObject * n, PyObject * v)
1247 rpmtsObject *s = (rpmtsObject *)o;
1248 char * name = PyString_AsString(n);
1251 if (!strcmp(name, "scriptFd")) {
1252 if (!PyArg_Parse(v, "i", &fdno)) return 0;
1254 PyErr_SetString(PyExc_TypeError, "bad file descriptor");
1257 s->scriptFd = fdDup(fdno);
1258 rpmtsSetScriptFd(s->ts, s->scriptFd);
1261 PyErr_SetString(PyExc_AttributeError, name);
1270 static int rpmts_init(rpmtsObject * s, PyObject *args, PyObject *kwds)
1272 /* nothing to do atm... */
1278 static void rpmts_free(rpmtsObject * s)
1281 fprintf(stderr, "%p -- ts %p db %p\n", s, s->ts, rpmtsGetRdb(s->ts));
1282 s->ts = rpmtsFree(s->ts);
1285 Fclose(s->scriptFd);
1287 /* this will free the keyList, and decrement the ref count of all
1288 the items on the list as well :-) */
1289 Py_DECREF(s->keyList);
1291 PyObject_Del((PyObject *)s);
1296 static PyObject * rpmts_alloc(PyTypeObject * subtype, int nitems)
1298 PyObject * s = PyType_GenericAlloc(subtype, nitems);
1300 if (_rpmts_debug < 0)
1301 fprintf(stderr, "*** rpmts_alloc(%p,%d) ret %p\n", subtype, nitems, s);
1307 static PyObject * rpmts_new(PyTypeObject * subtype, PyObject *args, PyObject *kwds)
1309 rpmtsObject * s = (void *) PyObject_New(rpmtsObject, subtype);
1311 char * rootDir = "/";
1312 rpmVSFlags vsflags = rpmExpandNumeric("%{?__vsflags}");
1313 char * kwlist[] = {"rootdir", "vsflags", 0};
1315 if (_rpmts_debug < 0)
1316 fprintf(stderr, "*** rpmts_new(%p,%p,%p)\n", s, args, kwds);
1318 if (!PyArg_ParseTupleAndKeywords(args, kwds, "|si:rpmts_init", kwlist,
1319 &rootDir, &vsflags))
1322 s->ts = rpmtsCreate();
1323 /* XXX: Why is there no rpmts_SetRootDir() ? */
1324 (void) rpmtsSetRootDir(s->ts, rootDir);
1325 /* XXX: make this use common code with rpmts_SetVSFlags() to check the
1327 (void) rpmtsSetVSFlags(s->ts, vsflags);
1328 s->keyList = PyList_New(0);
1334 fprintf(stderr, "%p ++ ts %p db %p\n", s, s->ts, rpmtsGetRdb(s->ts));
1336 return (PyObject *)s;
1341 static char rpmts_doc[] =
1346 PyTypeObject rpmts_Type = {
1347 PyObject_HEAD_INIT(&PyType_Type)
1349 "rpm.ts", /* tp_name */
1350 sizeof(rpmtsObject), /* tp_size */
1351 0, /* tp_itemsize */
1352 (destructor) rpmts_dealloc, /* tp_dealloc */
1354 (getattrfunc)0, /* tp_getattr */
1355 (setattrfunc)0, /* tp_setattr */
1358 0, /* tp_as_number */
1359 0, /* tp_as_sequence */
1360 0, /* tp_as_mapping */
1364 (getattrofunc) rpmts_getattro, /* tp_getattro */
1365 (setattrofunc) rpmts_setattro, /* tp_setattro */
1366 0, /* tp_as_buffer */
1367 Py_TPFLAGS_DEFAULT, /* tp_flags */
1368 rpmts_doc, /* tp_doc */
1369 #if Py_TPFLAGS_HAVE_ITER
1370 0, /* tp_traverse */
1372 0, /* tp_richcompare */
1373 0, /* tp_weaklistoffset */
1374 (getiterfunc) rpmts_iter, /* tp_iter */
1375 (iternextfunc) rpmts_iternext, /* tp_iternext */
1376 rpmts_methods, /* tp_methods */
1381 0, /* tp_descr_get */
1382 0, /* tp_descr_set */
1383 0, /* tp_dictoffset */
1384 (initproc) rpmts_init, /* tp_init */
1385 (allocfunc) rpmts_alloc, /* tp_alloc */
1386 (newfunc) rpmts_new, /* tp_new */
1387 (freefunc) rpmts_free, /* tp_free */
1395 rpmts_Create(PyObject * self, PyObject * args, PyObject * kwds)
1397 return PyObject_Call((PyObject *) &rpmts_Type, args, kwds);