2 * \file python/rpmts-py.c
12 #include "header-py.h"
13 #include "rpmds-py.h" /* XXX for rpmdsNew */
14 #include "rpmfi-py.h" /* XXX for rpmfiNew */
20 #define _RPMTS_INTERNAL /* XXX for ts->rdb, ts->availablePackage */
27 extern int _rpmts_debug;
42 * \brief A python rpm.ts object represents an RPM transaction set.
44 * The transaction set is the workhorse of RPM. It performs the
45 * installation and upgrade of packages. The rpm.ts object is
46 * instantiated by the TransactionSet function in the rpm module.
48 * The TransactionSet function takes two optional arguments. The first
49 * argument is the root path. The second is the verify signature disable flags,
50 * a set of the following bits:
52 * - rpm.RPMVSF_NOHDRCHK if set, don't check rpmdb headers
53 * - rpm.RPMVSF_NEEDPAYLOAD if not set, check header+payload (if possible)
54 * - rpm.RPMVSF_NOSHA1HEADER if set, don't check header SHA1 digest
55 * - rpm.RPMVSF_NODSAHEADER if set, don't check header DSA signature
56 * - rpm.RPMVSF_NOMD5 if set, don't check header+payload MD5 digest
57 * - rpm.RPMVSF_NODSA if set, don't check header+payload DSA signature
58 * - rpm.RPMVSF_NORSA if set, don't check header+payload RSA signature
60 * For convenience, there are the following masks:
61 * - rpm._RPMVSF_NODIGESTS if set, don't check digest(s).
62 * - rpm._RPMVSF_NOSIGNATURES if set, don't check signature(s).
64 * A rpm.ts object has the following methods:
66 * - addInstall(hdr,data,mode) Add an install element to a transaction set.
67 * @param hdr the header to be added
68 * @param data user data that will be passed to the transaction callback
69 * during transaction execution
70 * @param mode optional argument that specifies if this package should
71 * be installed ('i'), upgraded ('u'), or if it is just
72 * available to the transaction when computing
73 * dependencies but no action should be performed with it
76 * - addErase(name) Add an erase element to a transaction set.
77 * @param name the package name to be erased
79 * - check() Perform a dependency check on the transaction set. After
80 * headers have been added to a transaction set, a dependency
81 * check can be performed to make sure that all package
82 * dependencies are satisfied.
83 * @return None If there are no unresolved dependencies
84 * Otherwise a list of complex tuples is returned, one tuple per
85 * unresolved dependency, with
86 * The format of the dependency tuple is:
87 * ((packageName, packageVersion, packageRelease),
88 * (reqName, reqVersion),
92 * packageName, packageVersion, packageRelease are the name,
93 * version, and release of the package that has the unresolved
94 * dependency or conflict.
95 * The reqName and reqVersion are the name and version of the
96 * requirement or conflict.
97 * The needsFlags is a bitfield that describes the versioned
98 * nature of a requirement or conflict. The constants
99 * rpm.RPMSENSE_LESS, rpm.RPMSENSE_GREATER, and
100 * rpm.RPMSENSE_EQUAL can be logical ANDed with the needsFlags
101 * to get versioned dependency information.
102 * suggestedPackage is a tuple if the dependency check was aware
103 * of a package that solves this dependency problem when the
104 * dependency check was run. Packages that are added to the
105 * transaction set as "available" are examined during the
106 * dependency check as possible dependency solvers. The tuple
107 * contains two values, (header, suggestedName). These are set to
108 * the header of the suggested package and its name, respectively.
109 * If there is no known package to solve the dependency problem,
110 * suggestedPackage is None.
111 * The constants rpm.RPMDEP_SENSE_CONFLICTS and
112 * rpm.RPMDEP_SENSE_REQUIRES are set to show a dependency as a
113 * requirement or a conflict.
115 * - ts.order() Do a topological sort of added element relations.
118 * - ts.setFlags(transFlags) Set transaction set flags.
119 * @param transFlags - bit(s) to controll transaction operations. The
120 * following values can be logically OR'ed together:
121 * - rpm.RPMTRANS_FLAG_TEST - test mode, do not modify the RPM
122 * database, change any files, or run any package scripts
123 * - rpm.RPMTRANS_FLAG_BUILD_PROBS - only build a list of
124 * problems encountered when attempting to run this transaction
126 * - rpm.RPMTRANS_FLAG_NOSCRIPTS - do not execute package scripts
127 * - rpm.RPMTRANS_FLAG_JUSTDB - only make changes to the rpm
128 * database, do not modify files.
129 * - rpm.RPMTRANS_FLAG_NOTRIGGERS - do not run trigger scripts
130 * - rpm.RPMTRANS_FLAG_NODOCS - do not install files marked as %doc
131 * - rpm.RPMTRANS_FLAG_ALLFILES - create all files, even if a
132 * file is marked %config(missingok) and an upgrade is
134 * - rpm.RPMTRANS_FLAG_KEEPOBSOLETE - do not remove obsoleted
136 * @return previous transFlags
138 * - ts.setProbFilter(ignoreSet) Set transaction set problem filter.
139 * @param problemSetFilter - control bit(s) to ignore classes of problems,
140 * a logical or of one or more of the following bit(s):
141 * - rpm.RPMPROB_FILTER_IGNOREOS -
142 * - rpm.RPMPROB_FILTER_IGNOREARCH -
143 * - rpm.RPMPROB_FILTER_REPLACEPKG -
144 * - rpm.RPMPROB_FILTER_FORCERELOCATE -
145 * - rpm.RPMPROB_FILTER_REPLACENEWFILES -
146 * - rpm.RPMPROB_FILTER_REPLACEOLDFILES -
147 * - rpm.RPMPROB_FILTER_OLDPACKAGE -
148 * - rpm.RPMPROB_FILTER_DISKSPACE -
149 * @return previous ignoreSet
151 * - ts.run(callback,data) Attempt to execute a transaction set.
152 * After the transaction set has been populated with install/upgrade or
153 * erase actions, the transaction set can be executed by invoking
154 * the ts.run() method.
159 struct rpmtsCallbackType_s {
164 PyThreadState *_save;
171 rpmts_Debug(/*@unused@*/ rpmtsObject * s, PyObject * args, PyObject * kwds)
172 /*@globals _Py_NoneStruct @*/
173 /*@modifies _Py_NoneStruct @*/
175 char * kwlist[] = {"debugLevel", NULL};
177 if (!PyArg_ParseTupleAndKeywords(args, kwds, "i:Debug", kwlist,
181 if (_rpmts_debug < 0)
182 fprintf(stderr, "*** rpmts_Debug(%p) ts %p\n", s, s->ts);
189 * Add package to universe of possible packages to install in transaction set.
190 * @param ts transaction set
192 * @param key package private data
194 static void rpmtsAddAvailableElement(rpmts ts, Header h,
195 /*@exposed@*/ /*@null@*/ fnpyKey key)
196 /*@globals rpmGlobalMacroContext @*/
197 /*@modifies h, ts, rpmGlobalMacroContext @*/
200 rpmds provides = rpmdsNew(h, RPMTAG_PROVIDENAME, scareMem);
201 rpmfi fi = rpmfiNew(ts, h, RPMTAG_BASENAMES, scareMem);
203 /* XXX FIXME: return code RPMAL_NOMATCH is error */
204 (void) rpmalAdd(&ts->availablePackages, RPMAL_NOMATCH, key,
205 provides, fi, rpmtsColor(ts));
207 provides = rpmdsFree(provides);
209 if (_rpmts_debug < 0)
210 fprintf(stderr, "\tAddAvailable(%p) list %p\n", ts, ts->availablePackages);
218 rpmts_AddInstall(rpmtsObject * s, PyObject * args, PyObject * kwds)
219 /*@globals rpmGlobalMacroContext, _Py_NoneStruct @*/
220 /*@modifies s, rpmGlobalMacroContext, _Py_NoneStruct @*/
224 char * how = "u"; /* XXX default to upgrade element if missing */
226 char * kwlist[] = {"header", "key", "how", NULL};
229 if (!PyArg_ParseTupleAndKeywords(args, kwds, "O!O|s:AddInstall", kwlist,
230 &hdr_Type, &h, &key, &how))
233 { PyObject * hObj = (PyObject *) h;
234 if (hObj->ob_type != &hdr_Type) {
235 PyErr_SetString(PyExc_TypeError, "bad type for header argument");
240 if (_rpmts_debug < 0 || (_rpmts_debug > 0 && *how != 'a'))
241 fprintf(stderr, "*** rpmts_AddInstall(%p,%p,%p,%s) ts %p\n", s, h, key, how, s->ts);
243 if (how && strcmp(how, "a") && strcmp(how, "u") && strcmp(how, "i")) {
244 PyErr_SetString(PyExc_TypeError, "how argument must be \"u\", \"a\", or \"i\"");
246 } else if (how && !strcmp(how, "u"))
249 if (how && !strcmp(how, "a"))
250 rpmtsAddAvailableElement(s->ts, hdrGetHeader(h), key);
252 rc = rpmtsAddInstallElement(s->ts, hdrGetHeader(h), key, isUpgrade, NULL);
254 PyErr_SetString(pyrpmError, "adding package to transaction failed");
259 /* This should increment the usage count for me */
261 PyList_Append(s->keyList, key);
268 * @todo Permit finer control (i.e. not just --allmatches) of deleted elments.
272 rpmts_AddErase(rpmtsObject * s, PyObject * args, PyObject * kwds)
273 /*@globals rpmGlobalMacroContext, _Py_NoneStruct @*/
274 /*@modifies s, rpmGlobalMacroContext, _Py_NoneStruct @*/
278 rpmdbMatchIterator mi;
279 char * kwlist[] = {"name", NULL};
282 fprintf(stderr, "*** rpmts_AddErase(%p) ts %p\n", s, s->ts);
284 if (!PyArg_ParseTupleAndKeywords(args, kwds, "O:AddErase", kwlist, &o))
287 if (PyString_Check(o)) {
288 char * name = PyString_AsString(o);
290 mi = rpmtsInitIterator(s->ts, RPMDBI_LABEL, name, 0);
291 count = rpmdbGetIteratorCount(mi);
293 mi = rpmdbFreeIterator(mi);
294 PyErr_SetString(pyrpmError, "package not installed");
296 } else { /* XXX: Note that we automatically choose to remove all matches */
298 while ((h = rpmdbNextIterator(mi)) != NULL) {
299 unsigned int recOffset = rpmdbGetIteratorOffset(mi);
301 rpmtsAddEraseElement(s->ts, h, recOffset);
304 mi = rpmdbFreeIterator(mi);
306 if (PyInt_Check(o)) {
307 uint_32 instance = PyInt_AsLong(o);
309 mi = rpmtsInitIterator(s->ts, RPMDBI_PACKAGES, &instance, sizeof(instance));
310 if (instance == 0 || mi == NULL) {
311 mi = rpmdbFreeIterator(mi);
312 PyErr_SetString(pyrpmError, "package not installed");
316 while ((h = rpmdbNextIterator(mi)) != NULL) {
317 uint_32 recOffset = rpmdbGetIteratorOffset(mi);
319 rpmtsAddEraseElement(s->ts, h, recOffset);
323 mi = rpmdbFreeIterator(mi);
333 rpmts_SolveCallback(rpmts ts, rpmds ds, const void * data)
336 struct rpmtsCallbackType_s * cbInfo = (struct rpmtsCallbackType_s *) data;
337 PyObject * args, * result;
341 fprintf(stderr, "*** rpmts_SolveCallback(%p,%p,%p) \"%s\"\n", ts, ds, data, rpmdsDNEVR(ds));
343 if (cbInfo->tso == NULL) return res;
344 if (cbInfo->pythonError) return res;
345 if (cbInfo->cb == Py_None) return res;
347 PyEval_RestoreThread(cbInfo->_save);
349 args = Py_BuildValue("(Oissi)", cbInfo->tso,
350 rpmdsTagN(ds), rpmdsN(ds), rpmdsEVR(ds), rpmdsFlags(ds));
351 result = PyEval_CallObject(cbInfo->cb, args);
355 cbInfo->pythonError = 1;
357 if (PyInt_Check(result))
358 res = PyInt_AsLong(result);
362 cbInfo->_save = PyEval_SaveThread();
371 rpmts_Check(rpmtsObject * s, PyObject * args, PyObject * kwds)
372 /*@globals rpmGlobalMacroContext, _Py_NoneStruct @*/
373 /*@modifies s, rpmGlobalMacroContext, _Py_NoneStruct @*/
377 PyObject * list, * cf;
378 struct rpmtsCallbackType_s cbInfo;
381 char * kwlist[] = {"callback", NULL};
383 memset(&cbInfo, 0, sizeof(cbInfo));
384 if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O:Check", kwlist,
388 if (cbInfo.cb != NULL) {
389 if (!PyCallable_Check(cbInfo.cb)) {
390 PyErr_SetString(PyExc_TypeError, "expected a callable");
393 xx = rpmtsSetSolveCallback(s->ts, rpmts_SolveCallback, (void *)&cbInfo);
397 fprintf(stderr, "*** rpmts_Check(%p) ts %p cb %p\n", s, s->ts, cbInfo.cb);
400 cbInfo.pythonError = 0;
401 cbInfo._save = PyEval_SaveThread();
403 /* XXX resurrect availablePackages one more time ... */
404 rpmalMakeIndex(s->ts->availablePackages);
406 xx = rpmtsCheck(s->ts);
407 ps = rpmtsProblems(s->ts);
410 xx = rpmtsSetSolveCallback(s->ts, rpmtsSolve, NULL);
412 PyEval_RestoreThread(cbInfo._save);
415 list = PyList_New(0);
417 /* XXX TODO: rpmlib >= 4.0.3 can return multiple suggested keys. */
418 for (i = 0; i < ps->numProblems; i++) {
420 cf = Py_BuildValue("((sss)(ss)iOi)", conflicts[i].byName,
421 conflicts[i].byVersion, conflicts[i].byRelease,
423 conflicts[i].needsName,
424 conflicts[i].needsVersion,
426 conflicts[i].needsFlags,
427 conflicts[i].suggestedPkgs ?
428 conflicts[i].suggestedPkgs[0] : Py_None,
431 char * byName, * byVersion, * byRelease, *byArch;
432 char * needsName, * needsOP, * needsVersion;
433 int needsFlags, sense;
438 /* XXX autorelocated i386 on ia64, fix system-config-packages! */
439 if (p->type == RPMPROB_BADRELOCATE)
443 if ((byArch= strrchr(byName, '.')) != NULL)
445 if ((byRelease = strrchr(byName, '-')) != NULL)
447 if ((byVersion = strrchr(byName, '-')) != NULL)
452 needsName = p->altNEVR;
453 if (needsName[1] == ' ') {
454 sense = (needsName[0] == 'C')
455 ? RPMDEP_SENSE_CONFLICTS : RPMDEP_SENSE_REQUIRES;
458 sense = RPMDEP_SENSE_REQUIRES;
459 if ((needsVersion = strrchr(needsName, ' ')) != NULL)
460 *needsVersion++ = '\0';
463 if ((needsOP = strrchr(needsName, ' ')) != NULL) {
464 for (*needsOP++ = '\0'; *needsOP != '\0'; needsOP++) {
465 if (*needsOP == '<') needsFlags |= RPMSENSE_LESS;
466 else if (*needsOP == '>') needsFlags |= RPMSENSE_GREATER;
467 else if (*needsOP == '=') needsFlags |= RPMSENSE_EQUAL;
471 cf = Py_BuildValue("((sss)(ss)iOi)", byName, byVersion, byRelease,
472 needsName, needsVersion, needsFlags,
473 (key != NULL ? key : Py_None),
476 PyList_Append(list, (PyObject *) cf);
493 rpmts_Order(rpmtsObject * s)
494 /*@globals rpmGlobalMacroContext @*/
495 /*@modifies s, rpmGlobalMacroContext @*/
500 fprintf(stderr, "*** rpmts_Order(%p) ts %p\n", s, s->ts);
502 Py_BEGIN_ALLOW_THREADS
503 rc = rpmtsOrder(s->ts);
506 return Py_BuildValue("i", rc);
513 rpmts_Clean(rpmtsObject * s)
514 /*@globals _Py_NoneStruct @*/
515 /*@modifies s, _Py_NoneStruct @*/
518 fprintf(stderr, "*** rpmts_Clean(%p) ts %p\n", s, s->ts);
530 rpmts_IDTXload(rpmtsObject * s)
531 /*@globals rpmGlobalMacroContext, _Py_NoneStruct @*/
532 /*@modifies s, rpmGlobalMacroContext, _Py_NoneStruct @*/
534 PyObject * result = NULL;
535 rpmTag tag = RPMTAG_INSTALLTID;
539 fprintf(stderr, "*** rpmts_IDTXload(%p) ts %p\n", s, s->ts);
541 Py_BEGIN_ALLOW_THREADS
542 idtx = IDTXload(s->ts, tag);
546 if (idtx == NULL || idtx->nidt <= 0) {
555 result = PyTuple_New(idtx->nidt);
556 for (i = 0; i < idtx->nidt; i++) {
558 ho = (PyObject *) hdr_Wrap(idt->h);
559 tuple = Py_BuildValue("(iOi)", idt->val.u32, ho, idt->instance);
560 PyTuple_SET_ITEM(result, i, tuple);
566 idtx = IDTXfree(idtx);
575 rpmts_IDTXglob(rpmtsObject * s)
576 /*@globals rpmGlobalMacroContext, _Py_NoneStruct @*/
577 /*@modifies s, rpmGlobalMacroContext, _Py_NoneStruct @*/
579 PyObject * result = NULL;
580 rpmTag tag = RPMTAG_REMOVETID;
581 const char * globstr;
585 fprintf(stderr, "*** rpmts_IDTXglob(%p) ts %p\n", s, s->ts);
587 Py_BEGIN_ALLOW_THREADS
588 globstr = rpmExpand("%{_repackage_dir}/*.rpm", NULL);
589 idtx = IDTXglob(s->ts, globstr, tag);
590 globstr = _free(globstr);
594 if (idtx == NULL || idtx->nidt <= 0) {
603 result = PyTuple_New(idtx->nidt);
604 for (i = 0; i < idtx->nidt; i++) {
606 ho = (PyObject *) hdr_Wrap(idt->h);
607 tuple = Py_BuildValue("(iOs)", idt->val.u32, ho, idt->key);
608 PyTuple_SET_ITEM(result, i, tuple);
614 idtx = IDTXfree(idtx);
623 rpmts_Rollback(rpmtsObject * s, PyObject * args, PyObject * kwds)
624 /*@globals rpmGlobalMacroContext @*/
625 /*@modifies s, rpmGlobalMacroContext @*/
627 struct rpmInstallArguments_s * ia = alloca(sizeof(*ia));
628 rpmtransFlags transFlags;
629 const char ** av = NULL;
632 char * kwlist[] = {"transactionId", NULL};
635 fprintf(stderr, "*** rpmts_Rollback(%p) ts %p\n", s, s->ts);
637 if (!PyArg_ParseTupleAndKeywords(args, kwds, "i:Rollback", kwlist, &rbtid))
640 Py_BEGIN_ALLOW_THREADS
641 memset(ia, 0, sizeof(*ia));
642 ia->qva_flags = (VERIFY_DIGEST|VERIFY_SIGNATURE|VERIFY_HDRCHK);
643 ia->transFlags |= (INSTALL_UPGRADE|INSTALL_FRESHEN|INSTALL_INSTALL);
644 ia->transFlags |= RPMTRANS_FLAG_NOMD5;
645 ia->installInterfaceFlags = (INSTALL_UPGRADE|INSTALL_FRESHEN|INSTALL_INSTALL);
647 ia->relocations = NULL;
648 ia->probFilter |= RPMPROB_FILTER_OLDPACKAGE;
650 transFlags = rpmtsSetFlags(s->ts, ia->transFlags);
651 rc = rpmRollback(s->ts, ia, av);
652 transFlags = rpmtsSetFlags(s->ts, transFlags);
655 return Py_BuildValue("i", rc);
662 rpmts_OpenDB(rpmtsObject * s)
663 /*@globals rpmGlobalMacroContext @*/
664 /*@modifies s, rpmGlobalMacroContext @*/
668 fprintf(stderr, "*** rpmts_OpenDB(%p) ts %p\n", s, s->ts);
670 if (s->ts->dbmode == -1)
671 s->ts->dbmode = O_RDONLY;
673 return Py_BuildValue("i", rpmtsOpenDB(s->ts, s->ts->dbmode));
680 rpmts_CloseDB(rpmtsObject * s)
686 fprintf(stderr, "*** rpmts_CloseDB(%p) ts %p\n", s, s->ts);
688 rc = rpmtsCloseDB(s->ts);
689 s->ts->dbmode = -1; /* XXX disable lazy opens */
691 return Py_BuildValue("i", rc);
698 rpmts_InitDB(rpmtsObject * s)
699 /*@globals rpmGlobalMacroContext @*/
700 /*@modifies s, rpmGlobalMacroContext @*/
705 fprintf(stderr, "*** rpmts_InitDB(%p) ts %p\n", s, s->ts);
707 rc = rpmtsInitDB(s->ts, O_RDONLY);
709 rc = rpmtsCloseDB(s->ts);
711 return Py_BuildValue("i", rc);
718 rpmts_RebuildDB(rpmtsObject * s)
719 /*@globals rpmGlobalMacroContext @*/
720 /*@modifies s, rpmGlobalMacroContext @*/
725 fprintf(stderr, "*** rpmts_RebuildDB(%p) ts %p\n", s, s->ts);
727 Py_BEGIN_ALLOW_THREADS
728 rc = rpmtsRebuildDB(s->ts);
731 return Py_BuildValue("i", rc);
738 rpmts_VerifyDB(rpmtsObject * s)
739 /*@globals rpmGlobalMacroContext @*/
740 /*@modifies s, rpmGlobalMacroContext @*/
745 fprintf(stderr, "*** rpmts_VerifyDB(%p) ts %p\n", s, s->ts);
747 Py_BEGIN_ALLOW_THREADS
748 rc = rpmtsVerifyDB(s->ts);
751 return Py_BuildValue("i", rc);
758 rpmts_HdrFromFdno(rpmtsObject * s, PyObject * args, PyObject * kwds)
759 /*@globals rpmGlobalMacroContext, fileSystem @*/
760 /*@modifies s, rpmGlobalMacroContext, fileSystem @*/
762 PyObject * result = NULL;
767 char * kwlist[] = {"fd", NULL};
769 if (!PyArg_ParseTupleAndKeywords(args, kwds, "i:HdrFromFdno", kwlist,
774 rpmrc = rpmReadPackageFile(s->ts, fd, "rpmts_HdrFromFdno", &h);
778 fprintf(stderr, "*** rpmts_HdrFromFdno(%p) ts %p rc %d\n", s, s->ts, rpmrc);
784 result = Py_BuildValue("N", hdr_Wrap(h));
785 h = headerFree(h); /* XXX ref held by result */
789 PyErr_SetString(pyrpmError, "public key not available");
792 case RPMRC_NOTTRUSTED:
793 PyErr_SetString(pyrpmError, "public key not trusted");
799 PyErr_SetString(pyrpmError, "error reading package header");
811 rpmts_HdrCheck(rpmtsObject * s, PyObject * args, PyObject * kwds)
812 /*@globals rpmGlobalMacroContext, _Py_NoneStruct @*/
813 /*@modifies s, rpmGlobalMacroContext, _Py_NoneStruct @*/
816 PyObject * result = NULL;
817 const char * msg = NULL;
821 char * kwlist[] = {"headers", NULL};
824 fprintf(stderr, "*** rpmts_HdrCheck(%p) ts %p\n", s, s->ts);
826 if (!PyArg_ParseTupleAndKeywords(args, kwds, "O:HdrCheck", kwlist, &blob))
829 if (blob == Py_None) {
833 if (!PyString_Check(blob)) {
834 PyErr_SetString(pyrpmError, "hdrCheck takes a string of octets");
837 uh = PyString_AsString(blob);
838 uc = PyString_Size(blob);
840 rpmrc = headerCheck(s->ts, uh, uc, &msg);
849 PyErr_SetString(pyrpmError, "public key not availaiable");
852 case RPMRC_NOTTRUSTED:
853 PyErr_SetString(pyrpmError, "public key not trusted");
858 PyErr_SetString(pyrpmError, msg);
870 rpmts_SetVSFlags(rpmtsObject * s, PyObject * args, PyObject * kwds)
874 char * kwlist[] = {"flags", NULL};
877 fprintf(stderr, "*** rpmts_SetVSFlags(%p) ts %p\n", s, s->ts);
879 if (!PyArg_ParseTupleAndKeywords(args, kwds, "i:SetVSFlags", kwlist,
883 /* XXX FIXME: value check on vsflags, or build pure python object
884 * for it, and require an object of that type */
886 return Py_BuildValue("i", rpmtsSetVSFlags(s->ts, vsflags));
893 rpmts_SetColor(rpmtsObject * s, PyObject * args, PyObject * kwds)
897 char * kwlist[] = {"color", NULL};
900 fprintf(stderr, "*** rpmts_SetColor(%p) ts %p\n", s, s->ts);
902 if (!PyArg_ParseTupleAndKeywords(args, kwds, "i:Color", kwlist, &tscolor))
905 /* XXX FIXME: value check on tscolor, or build pure python object
906 * for it, and require an object of that type */
908 return Py_BuildValue("i", rpmtsSetColor(s->ts, tscolor));
915 rpmts_PgpPrtPkts(rpmtsObject * s, PyObject * args, PyObject * kwds)
916 /*@globals _Py_NoneStruct @*/
917 /*@modifies _Py_NoneStruct @*/
923 char * kwlist[] = {"octets", NULL};
926 fprintf(stderr, "*** rpmts_PgpPrtPkts(%p) ts %p\n", s, s->ts);
928 if (!PyArg_ParseTupleAndKeywords(args, kwds, "O:PgpPrtPkts", kwlist, &blob))
931 if (blob == Py_None) {
935 if (!PyString_Check(blob)) {
936 PyErr_SetString(pyrpmError, "pgpPrtPkts takes a string of octets");
939 pkt = (unsigned char *)PyString_AsString(blob);
940 pktlen = PyString_Size(blob);
942 rc = pgpPrtPkts(pkt, pktlen, NULL, 1);
944 return Py_BuildValue("i", rc);
951 rpmts_PgpImportPubkey(rpmtsObject * s, PyObject * args, PyObject * kwds)
952 /*@globals rpmGlobalMacroContext, _Py_NoneStruct @*/
953 /*@modifies s, rpmGlobalMacroContext, _Py_NoneStruct @*/
959 char * kwlist[] = {"pubkey", NULL};
962 fprintf(stderr, "*** rpmts_PgpImportPubkey(%p) ts %p\n", s, s->ts);
964 if (!PyArg_ParseTupleAndKeywords(args, kwds, "O:PgpImportPubkey",
968 if (blob == Py_None) {
972 if (!PyString_Check(blob)) {
973 PyErr_SetString(pyrpmError, "PgpImportPubkey takes a string of octets");
976 pkt = (unsigned char *)PyString_AsString(blob);
977 pktlen = PyString_Size(blob);
979 rc = rpmcliImportPubkey(s->ts, pkt, pktlen);
981 return Py_BuildValue("i", rc);
988 rpmts_GetKeys(rpmtsObject * s)
989 /*@globals _Py_NoneStruct @*/
990 /*@modifies s, _Py_NoneStruct @*/
992 const void **data = NULL;
997 fprintf(stderr, "*** rpmts_GetKeys(%p) ts %p\n", s, s->ts);
999 rpmtsGetKeys(s->ts, &data, &num);
1000 if (data == NULL || num <= 0) {
1006 tuple = PyTuple_New(num);
1008 for (i = 0; i < num; i++) {
1010 obj = (data[i] ? (PyObject *) data[i] : Py_None);
1012 PyTuple_SetItem(tuple, i, obj);
1024 rpmtsCallback(/*@unused@*/ const void * hd, const rpmCallbackType what,
1025 const unsigned long amount, const unsigned long total,
1026 const void * pkgKey, rpmCallbackData data)
1027 /*@globals _Py_NoneStruct @*/
1028 /*@modifies _Py_NoneStruct @*/
1031 Header h = (Header) hd;
1033 struct rpmtsCallbackType_s * cbInfo = data;
1034 PyObject * pkgObj = (PyObject *) pkgKey;
1035 PyObject * args, * result;
1038 if (cbInfo->pythonError) return NULL;
1039 if (cbInfo->cb == Py_None) return NULL;
1041 /* Synthesize a python object for callback (if necessary). */
1042 if (pkgObj == NULL) {
1044 const char * n = NULL;
1045 (void) headerNVR(h, &n, NULL, NULL);
1046 pkgObj = Py_BuildValue("s", n);
1054 PyEval_RestoreThread(cbInfo->_save);
1056 args = Py_BuildValue("(illOO)", what, amount, total, pkgObj, cbInfo->data);
1057 result = PyEval_CallObject(cbInfo->cb, args);
1062 cbInfo->pythonError = 1;
1063 cbInfo->_save = PyEval_SaveThread();
1067 if (what == RPMCALLBACK_INST_OPEN_FILE) {
1070 if (!PyArg_Parse(result, "i", &fdno)) {
1071 cbInfo->pythonError = 1;
1072 cbInfo->_save = PyEval_SaveThread();
1076 cbInfo->_save = PyEval_SaveThread();
1080 fprintf(stderr, "\t%p = fdDup(%d)\n", fd, fdno);
1082 fcntl(Fileno(fd), F_SETFD, FD_CLOEXEC);
1086 if (what == RPMCALLBACK_INST_CLOSE_FILE) {
1088 fprintf(stderr, "\tFclose(%p)\n", fd);
1092 fprintf(stderr, "\t%ld:%ld key %p\n", amount, total, pkgKey);
1096 cbInfo->_save = PyEval_SaveThread();
1104 rpmts_SetFlags(rpmtsObject * s, PyObject * args, PyObject * kwds)
1107 rpmtransFlags transFlags = 0;
1108 char * kwlist[] = {"flags", NULL};
1110 if (!PyArg_ParseTupleAndKeywords(args, kwds, "i:SetFlags", kwlist,
1115 fprintf(stderr, "*** rpmts_SetFlags(%p) ts %p transFlags %x\n", s, s->ts, transFlags);
1117 /* XXX FIXME: value check on flags, or build pure python object
1118 * for it, and require an object of that type */
1120 return Py_BuildValue("i", rpmtsSetFlags(s->ts, transFlags));
1126 rpmts_SetProbFilter(rpmtsObject * s, PyObject * args, PyObject * kwds)
1129 rpmprobFilterFlags ignoreSet = 0;
1130 rpmprobFilterFlags oignoreSet;
1131 char * kwlist[] = {"ignoreSet", NULL};
1133 if (!PyArg_ParseTupleAndKeywords(args, kwds, "i:ProbFilter", kwlist,
1138 fprintf(stderr, "*** rpmts_SetProbFilter(%p) ts %p ignoreSet %x\n", s, s->ts, ignoreSet);
1140 oignoreSet = s->ignoreSet;
1141 s->ignoreSet = ignoreSet;
1143 return Py_BuildValue("i", oignoreSet);
1149 static rpmpsObject *
1150 rpmts_Problems(rpmtsObject * s)
1155 fprintf(stderr, "*** rpmts_Problems(%p) ts %p\n", s, s->ts);
1157 return rpmps_Wrap( rpmtsProblems(s->ts) );
1163 rpmts_Run(rpmtsObject * s, PyObject * args, PyObject * kwds)
1164 /*@globals rpmGlobalMacroContext, _Py_NoneStruct @*/
1165 /*@modifies s, rpmGlobalMacroContext, _Py_NoneStruct @*/
1170 struct rpmtsCallbackType_s cbInfo;
1171 char * kwlist[] = {"callback", "data", NULL};
1173 if (!PyArg_ParseTupleAndKeywords(args, kwds, "OO:Run", kwlist,
1174 &cbInfo.cb, &cbInfo.data))
1178 cbInfo.pythonError = 0;
1179 cbInfo._save = PyEval_SaveThread();
1181 if (cbInfo.cb != NULL) {
1182 if (!PyCallable_Check(cbInfo.cb)) {
1183 PyErr_SetString(PyExc_TypeError, "expected a callable");
1186 (void) rpmtsSetNotifyCallback(s->ts, rpmtsCallback, (void *) &cbInfo);
1190 fprintf(stderr, "*** rpmts_Run(%p) ts %p ignore %x\n", s, s->ts, s->ignoreSet);
1192 rc = rpmtsRun(s->ts, NULL, s->ignoreSet);
1193 ps = rpmtsProblems(s->ts);
1196 (void) rpmtsSetNotifyCallback(s->ts, NULL, NULL);
1198 PyEval_RestoreThread(cbInfo._save);
1200 if (cbInfo.pythonError) {
1206 list = PyList_New(0);
1213 list = PyList_New(0);
1214 for (i = 0; i < ps->numProblems; i++) {
1215 rpmProblem p = ps->probs + i;
1216 PyObject * prob = Py_BuildValue("s(isN)", rpmProblemString(p),
1219 PyLong_FromLongLong(p->ulong1));
1220 PyList_Append(list, prob);
1229 #if Py_TPFLAGS_HAVE_ITER
1231 rpmts_iter(rpmtsObject * s)
1235 fprintf(stderr, "*** rpmts_iter(%p) ts %p\n", s, s->ts);
1238 return (PyObject *)s;
1243 * @todo Add TR_ADDED filter to iterator.
1247 rpmts_iternext(rpmtsObject * s)
1250 PyObject * result = NULL;
1254 fprintf(stderr, "*** rpmts_iternext(%p) ts %p tsi %p %d\n", s, s->ts, s->tsi, s->tsiFilter);
1256 /* Reset iterator on 1st entry. */
1257 if (s->tsi == NULL) {
1258 s->tsi = rpmtsiInit(s->ts);
1264 te = rpmtsiNext(s->tsi, s->tsiFilter);
1267 result = (PyObject *) rpmte_Wrap(te);
1269 s->tsi = rpmtsiFree(s->tsi);
1278 * @todo Add TR_ADDED filter to iterator.
1281 rpmts_Next(rpmtsObject * s)
1282 /*@globals _Py_NoneStruct @*/
1283 /*@modifies s, _Py_NoneStruct @*/
1288 fprintf(stderr, "*** rpmts_Next(%p) ts %p\n", s, s->ts);
1290 result = rpmts_iternext(s);
1292 if (result == NULL) {
1304 spec_Parse(rpmtsObject * s, PyObject * args, PyObject * kwds)
1305 /*@globals rpmGlobalMacroContext @*/
1306 /*@modifies s, rpmGlobalMacroContext @*/
1308 const char * specfile;
1310 char * buildRoot = NULL;
1312 char * passPhrase = "";
1313 char *cookie = NULL;
1316 char * kwlist[] = {"specfile", NULL};
1318 if (!PyArg_ParseTupleAndKeywords(args, kwds, "s:Parse", kwlist, &specfile))
1321 if (parseSpec(s->ts, specfile,"/", buildRoot,recursing, passPhrase,
1322 cookie, anyarch, force)!=0) {
1323 PyErr_SetString(pyrpmError, "can't parse specfile\n");
1327 spec = rpmtsSpec(s->ts);
1328 return spec_Wrap(spec);
1334 static rpmmiObject *
1335 rpmts_Match(rpmtsObject * s, PyObject * args, PyObject * kwds)
1336 /*@globals rpmGlobalMacroContext @*/
1337 /*@modifies s, rpmGlobalMacroContext @*/
1339 PyObject *TagN = NULL;
1340 PyObject *Key = NULL;
1342 /* XXX lkey *must* be a 32 bit integer, int "works" on all known platforms. */
1345 int tag = RPMDBI_PACKAGES;
1346 char * kwlist[] = {"tagNumber", "key", NULL};
1349 fprintf(stderr, "*** rpmts_Match(%p) ts %p\n", s, s->ts);
1351 if (!PyArg_ParseTupleAndKeywords(args, kwds, "|OO:Match", kwlist,
1355 if (TagN && (tag = tagNumFromPyObject (TagN)) == -1) {
1356 PyErr_SetString(PyExc_TypeError, "unknown tag type");
1362 if (PyString_Check(Key) || PyUnicode_Check(Key)) {
1363 key = PyString_AsString(Key);
1364 len = PyString_Size(Key);
1365 } else if (PyInt_Check(Key)) {
1366 lkey = PyInt_AsLong(Key);
1367 key = (char *)&lkey;
1370 PyErr_SetString(PyExc_TypeError, "unknown key type");
1376 /* XXX If not already opened, open the database O_RDONLY now. */
1377 /* XXX FIXME: lazy default rdonly open also done by rpmtsInitIterator(). */
1378 if (s->ts->rdb == NULL) {
1379 int rc = rpmtsOpenDB(s->ts, O_RDONLY);
1380 if (rc || s->ts->rdb == NULL) {
1381 PyErr_SetString(PyExc_TypeError, "rpmdb open failed");
1386 return rpmmi_Wrap( rpmtsInitIterator(s->ts, tag, key, len), (PyObject*)s);
1391 /*@-fullinitblock@*/
1392 /*@unchecked@*/ /*@observer@*/
1393 static struct PyMethodDef rpmts_methods[] = {
1394 {"Debug", (PyCFunction)rpmts_Debug, METH_VARARGS|METH_KEYWORDS,
1397 {"addInstall", (PyCFunction) rpmts_AddInstall, METH_VARARGS|METH_KEYWORDS,
1399 {"addErase", (PyCFunction) rpmts_AddErase, METH_VARARGS|METH_KEYWORDS,
1401 {"check", (PyCFunction) rpmts_Check, METH_VARARGS|METH_KEYWORDS,
1403 {"order", (PyCFunction) rpmts_Order, METH_NOARGS,
1405 {"setFlags", (PyCFunction) rpmts_SetFlags, METH_VARARGS|METH_KEYWORDS,
1406 "ts.setFlags(transFlags) -> previous transFlags\n\
1407 - Set control bit(s) for executing ts.run().\n\
1408 Note: This method replaces the 1st argument to the old ts.run()\n" },
1409 {"setProbFilter", (PyCFunction) rpmts_SetProbFilter, METH_VARARGS|METH_KEYWORDS,
1410 "ts.setProbFilter(ignoreSet) -> previous ignoreSet\n\
1411 - Set control bit(s) for ignoring problems found by ts.run().\n\
1412 Note: This method replaces the 2nd argument to the old ts.run()\n" },
1413 {"problems", (PyCFunction) rpmts_Problems, METH_NOARGS,
1414 "ts.problems() -> ps\n\
1415 - Return current problem set.\n" },
1416 {"run", (PyCFunction) rpmts_Run, METH_VARARGS|METH_KEYWORDS,
1417 "ts.run(callback, data) -> (problems)\n\
1418 - Run a transaction set, returning list of problems found.\n\
1419 Note: The callback may not be None.\n" },
1420 {"clean", (PyCFunction) rpmts_Clean, METH_NOARGS,
1422 {"IDTXload", (PyCFunction) rpmts_IDTXload, METH_NOARGS,
1423 "ts.IDTXload() -> ((tid,hdr,instance)+)\n\
1424 - Return list of installed packages reverse sorted by transaction id.\n" },
1425 {"IDTXglob", (PyCFunction) rpmts_IDTXglob, METH_NOARGS,
1426 "ts.IDTXglob() -> ((tid,hdr,instance)+)\n\
1427 - Return list of removed packages reverse sorted by transaction id.\n" },
1428 {"rollback", (PyCFunction) rpmts_Rollback, METH_VARARGS|METH_KEYWORDS,
1430 {"openDB", (PyCFunction) rpmts_OpenDB, METH_NOARGS,
1431 "ts.openDB() -> None\n\
1432 - Open the default transaction rpmdb.\n\
1433 Note: The transaction rpmdb is lazily opened, so ts.openDB() is seldom needed.\n" },
1434 {"closeDB", (PyCFunction) rpmts_CloseDB, METH_NOARGS,
1435 "ts.closeDB() -> None\n\
1436 - Close the default transaction rpmdb.\n\
1437 Note: ts.closeDB() disables lazy opens, and should hardly ever be used.\n" },
1438 {"initDB", (PyCFunction) rpmts_InitDB, METH_NOARGS,
1439 "ts.initDB() -> None\n\
1440 - Initialize the default transaction rpmdb.\n\
1441 Note: ts.initDB() is seldom needed anymore.\n" },
1442 {"rebuildDB", (PyCFunction) rpmts_RebuildDB, METH_NOARGS,
1443 "ts.rebuildDB() -> None\n\
1444 - Rebuild the default transaction rpmdb.\n" },
1445 {"verifyDB", (PyCFunction) rpmts_VerifyDB, METH_NOARGS,
1446 "ts.verifyDB() -> None\n\
1447 - Verify the default transaction rpmdb.\n" },
1448 {"hdrFromFdno",(PyCFunction) rpmts_HdrFromFdno,METH_VARARGS|METH_KEYWORDS,
1449 "ts.hdrFromFdno(fdno) -> hdr\n\
1450 - Read a package header from a file descriptor.\n" },
1451 {"hdrCheck", (PyCFunction) rpmts_HdrCheck, METH_VARARGS|METH_KEYWORDS,
1453 {"setVSFlags",(PyCFunction) rpmts_SetVSFlags, METH_VARARGS|METH_KEYWORDS,
1454 "ts.setVSFlags(vsflags) -> ovsflags\n\
1455 - Set signature verification flags. Values for vsflags are:\n\
1456 rpm.RPMVSF_NOHDRCHK if set, don't check rpmdb headers\n\
1457 rpm.RPMVSF_NEEDPAYLOAD if not set, check header+payload (if possible)\n\
1458 rpm.RPMVSF_NOSHA1HEADER if set, don't check header SHA1 digest\n\
1459 rpm.RPMVSF_NODSAHEADER if set, don't check header DSA signature\n\
1460 rpm.RPMVSF_NOMD5 if set, don't check header+payload MD5 digest\n\
1461 rpm.RPMVSF_NODSA if set, don't check header+payload DSA signature\n\
1462 rpm.RPMVSF_NORSA if set, don't check header+payload RSA signature\n\
1463 rpm._RPMVSF_NODIGESTS if set, don't check digest(s)\n\
1464 rpm._RPMVSF_NOSIGNATURES if set, don't check signature(s)\n" },
1465 {"setColor",(PyCFunction) rpmts_SetColor, METH_VARARGS|METH_KEYWORDS,
1467 {"pgpPrtPkts", (PyCFunction) rpmts_PgpPrtPkts, METH_VARARGS|METH_KEYWORDS,
1469 {"pgpImportPubkey", (PyCFunction) rpmts_PgpImportPubkey, METH_VARARGS|METH_KEYWORDS,
1471 {"getKeys", (PyCFunction) rpmts_GetKeys, METH_NOARGS,
1473 {"parseSpec", (PyCFunction) spec_Parse, METH_VARARGS|METH_KEYWORDS,
1474 "ts.parseSpec(\"/path/to/foo.spec\") -> spec\n\
1475 - Parse a spec file.\n" },
1476 {"dbMatch", (PyCFunction) rpmts_Match, METH_VARARGS|METH_KEYWORDS,
1477 "ts.dbMatch([TagN, [key, [len]]]) -> mi\n\
1478 - Create a match iterator for the default transaction rpmdb.\n" },
1479 {"next", (PyCFunction)rpmts_Next, METH_NOARGS,
1481 - Retrieve next transaction set element.\n" },
1482 {NULL, NULL} /* sentinel */
1484 /*@=fullinitblock@*/
1488 static void rpmts_dealloc(/*@only@*/ rpmtsObject * s)
1493 fprintf(stderr, "%p -- ts %p db %p\n", s, s->ts, s->ts->rdb);
1494 s->ts = rpmtsFree(s->ts);
1496 if (s->scriptFd) Fclose(s->scriptFd);
1497 /* this will free the keyList, and decrement the ref count of all
1498 the items on the list as well :-) */
1499 Py_DECREF(s->keyList);
1500 PyObject_Del((PyObject *)s);
1503 static PyObject * rpmts_getattro(PyObject * o, PyObject * n)
1506 return PyObject_GenericGetAttr(o, n);
1511 static int rpmts_setattro(PyObject * o, PyObject * n, PyObject * v)
1514 rpmtsObject *s = (rpmtsObject *)o;
1515 char * name = PyString_AsString(n);
1518 if (!strcmp(name, "scriptFd")) {
1519 if (!PyArg_Parse(v, "i", &fdno)) return 0;
1521 PyErr_SetString(PyExc_TypeError, "bad file descriptor");
1524 s->scriptFd = fdDup(fdno);
1525 rpmtsSetScriptFd(s->ts, s->scriptFd);
1528 PyErr_SetString(PyExc_AttributeError, name);
1537 static int rpmts_init(rpmtsObject * s, PyObject *args, PyObject *kwds)
1538 /*@globals rpmGlobalMacroContext @*/
1539 /*@modifies s, rpmGlobalMacroContext @*/
1541 /* nothing to do atm... */
1547 static void rpmts_free(/*@only@*/ rpmtsObject * s)
1551 fprintf(stderr, "%p -- ts %p db %p\n", s, s->ts, s->ts->rdb);
1552 s->ts = rpmtsFree(s->ts);
1555 Fclose(s->scriptFd);
1557 /* this will free the keyList, and decrement the ref count of all
1558 the items on the list as well :-) */
1559 Py_DECREF(s->keyList);
1561 PyObject_Del((PyObject *)s);
1566 static PyObject * rpmts_alloc(PyTypeObject * subtype, int nitems)
1569 PyObject * s = PyType_GenericAlloc(subtype, nitems);
1571 if (_rpmts_debug < 0)
1572 fprintf(stderr, "*** rpmts_alloc(%p,%d) ret %p\n", subtype, nitems, s);
1578 static PyObject * rpmts_new(PyTypeObject * subtype, PyObject *args, PyObject *kwds)
1579 /*@globals rpmGlobalMacroContext @*/
1580 /*@modifies rpmGlobalMacroContext @*/
1582 rpmtsObject * s = (void *) PyObject_New(rpmtsObject, subtype);
1584 char * rootDir = "/";
1585 int vsflags = rpmExpandNumeric("%{?__vsflags}");
1586 char * kwlist[] = {"rootdir", "vsflags", 0};
1588 if (_rpmts_debug < 0)
1589 fprintf(stderr, "*** rpmts_new(%p,%p,%p)\n", s, args, kwds);
1591 if (!PyArg_ParseTupleAndKeywords(args, kwds, "|si:rpmts_init", kwlist,
1592 &rootDir, &vsflags))
1595 s->ts = rpmtsCreate();
1596 /* XXX: Why is there no rpmts_SetRootDir() ? */
1597 (void) rpmtsSetRootDir(s->ts, rootDir);
1598 /* XXX: make this use common code with rpmts_SetVSFlags() to check the
1600 (void) rpmtsSetVSFlags(s->ts, vsflags);
1601 s->keyList = PyList_New(0);
1607 fprintf(stderr, "%p ++ ts %p db %p\n", s, s->ts, s->ts->rdb);
1609 return (PyObject *)s;
1614 /*@unchecked@*/ /*@observer@*/
1615 static char rpmts_doc[] =
1620 /*@-fullinitblock@*/
1621 PyTypeObject rpmts_Type = {
1622 PyObject_HEAD_INIT(&PyType_Type)
1624 "rpm.ts", /* tp_name */
1625 sizeof(rpmtsObject), /* tp_size */
1626 0, /* tp_itemsize */
1627 (destructor) rpmts_dealloc, /* tp_dealloc */
1629 (getattrfunc)0, /* tp_getattr */
1630 (setattrfunc)0, /* tp_setattr */
1633 0, /* tp_as_number */
1634 0, /* tp_as_sequence */
1635 0, /* tp_as_mapping */
1639 (getattrofunc) rpmts_getattro, /* tp_getattro */
1640 (setattrofunc) rpmts_setattro, /* tp_setattro */
1641 0, /* tp_as_buffer */
1642 Py_TPFLAGS_DEFAULT, /* tp_flags */
1643 rpmts_doc, /* tp_doc */
1644 #if Py_TPFLAGS_HAVE_ITER
1645 0, /* tp_traverse */
1647 0, /* tp_richcompare */
1648 0, /* tp_weaklistoffset */
1649 (getiterfunc) rpmts_iter, /* tp_iter */
1650 (iternextfunc) rpmts_iternext, /* tp_iternext */
1651 rpmts_methods, /* tp_methods */
1656 0, /* tp_descr_get */
1657 0, /* tp_descr_set */
1658 0, /* tp_dictoffset */
1659 (initproc) rpmts_init, /* tp_init */
1660 (allocfunc) rpmts_alloc, /* tp_alloc */
1661 (newfunc) rpmts_new, /* tp_new */
1662 (freefunc) rpmts_free, /* tp_free */
1666 /*@=fullinitblock@*/
1671 rpmts_Create(/*@unused@*/ PyObject * self, PyObject * args, PyObject * kwds)
1673 return PyObject_Call((PyObject *) &rpmts_Type, args, kwds);