aboutsummaryrefslogtreecommitdiffstats
path: root/URPM.xs
diff options
context:
space:
mode:
Diffstat (limited to 'URPM.xs')
-rw-r--r--URPM.xs336
1 files changed, 318 insertions, 18 deletions
diff --git a/URPM.xs b/URPM.xs
index 5c080e0..62def76 100644
--- a/URPM.xs
+++ b/URPM.xs
@@ -35,7 +35,13 @@ struct s_Package {
Header h;
};
+struct s_Transaction {
+ rpmdb db;
+ rpmTransactionSet ts;
+};
+
typedef rpmdb URPM__DB;
+typedef struct s_Transaction* URPM__Transaction;
typedef struct s_Package* URPM__Package;
#define FLAG_ID 0x001fffffU
@@ -1539,24 +1545,9 @@ Pkg_set_rflags(pkg, ...)
MODULE = URPM PACKAGE = URPM::DB PREFIX = Db_
URPM::DB
-Db_open(prefix="/")
- char *prefix
- PREINIT:
- rpmdb db;
- rpmErrorCallBackType old_cb;
- CODE:
- read_config_files();
- old_cb = rpmErrorSetCallback(callback_empty);
- rpmSetVerbosity(RPMMESS_FATALERROR);
- RETVAL = rpmdbOpen(prefix, &db, O_RDONLY, 0644) == 0 ? db : NULL;
- rpmErrorSetCallback(old_cb);
- rpmSetVerbosity(RPMMESS_NORMAL);
- OUTPUT:
- RETVAL
-
-URPM::DB
-Db_open_rw(prefix="/")
+Db_open(prefix="/", write_perm=0)
char *prefix
+ int write_perm
PREINIT:
rpmdb db;
rpmErrorCallBackType old_cb;
@@ -1564,7 +1555,7 @@ Db_open_rw(prefix="/")
read_config_files();
old_cb = rpmErrorSetCallback(callback_empty);
rpmSetVerbosity(RPMMESS_FATALERROR);
- RETVAL = rpmdbOpen(prefix, &db, O_RDWR | O_CREAT, 0644) == 0 ? db : NULL;
+ RETVAL = rpmdbOpen(prefix, &db, write_perm ? O_RDWR | O_CREAT : O_RDONLY, 0644) == 0 ? db : NULL;
rpmErrorSetCallback(old_cb);
rpmSetVerbosity(RPMMESS_NORMAL);
OUTPUT:
@@ -1695,6 +1686,315 @@ Db_traverse_tag(db,tag,names,callback)
OUTPUT:
RETVAL
+URPM::Transaction
+Db_create_transaction(db, prefix="/")
+ URPM::DB db
+ char *prefix
+ CODE:
+ if ((RETVAL = malloc(sizeof(struct s_Transaction))) != NULL) {
+ RETVAL->db = db;
+ RETVAL->ts = rpmtransCreateSet(db, prefix);
+ }
+ OUTPUT:
+ RETVAL
+
+
+MODULE = URPM PACKAGE = URPM::Transaction PREFIX = Trans_
+
+void
+Trans_DESTROY(trans)
+ URPM::Transaction trans
+ CODE:
+ /* db should be SV with reference count updated */
+ rpmtransFree(trans->ts);
+ free(trans);
+
+int
+Trans_add_package(trans, pkg, update)
+ URPM::Transaction trans
+ SV* pkg
+ int update
+ PREINIT:
+ URPM__Package _pkg;
+ CODE:
+ if (sv_derived_from(ST(0), "URPM::Package")) {
+ IV tmp = SvIV((SV*)SvRV(ST(0)));
+ _pkg = INT2PTR(URPM__Package,tmp);
+ } else croak("pkg is not of type URPM::Package");
+ RETVAL = _pkg->h && rpmtransAddPackage(trans->ts, _pkg->h, NULL, /* SvREFCNT_inc(pkg) */ pkg, update, NULL) == 0;
+ OUTPUT:
+ RETVAL
+
+int
+Trans_remove_package(trans, name)
+ URPM::Transaction trans
+ char *name
+ PREINIT:
+ Header h;
+ rpmdbMatchIterator mi;
+ int count = 0;
+ CODE:
+ mi = rpmdbInitIterator(trans->db, RPMDBI_LABEL, name, 0);
+ while (h = rpmdbNextIterator(mi)) {
+ unsigned int recOffset = rpmdbGetIteratorOffset(mi);
+ if (recOffset) {
+ rpmtransRemovePackage(trans->ts, recOffset);
+ ++count;
+ }
+ }
+ rpmdbFreeIterator(mi);
+ RETVAL=count;
+ OUTPUT:
+ RETVAL
+
+void
+Trans_check(trans)
+ URPM::Transaction trans
+ PREINIT:
+ I32 gimme = GIMME_V;
+ rpmDependencyConflict conflicts;
+ int num_conflicts;
+ PPCODE:
+ if (rpmdepCheck(trans->ts, &conflicts, &num_conflicts)) {
+ if (gimme == G_SCALAR) {
+ XPUSHs(sv_2mortal(newSViv(0)));
+ } else if (gimme == G_ARRAY) {
+ XPUSHs(sv_2mortal(newSVpv("error while checking dependencies", 0)));
+ }
+ } else if (conflicts) {
+ if (gimme == G_SCALAR) {
+ XPUSHs(sv_2mortal(newSViv(0)));
+ } else if (gimme == G_ARRAY) {
+ char buff[1024];
+ int i;
+
+ for (i = 0; i < num_conflicts; ++i) {
+ char *p = buff;
+
+ p += snprintf(p, sizeof(buff) - (p-buff), "%s@%s",
+ conflicts[i].sense == RPMDEP_SENSE_REQUIRES ? "requires" : "conflicts",
+ conflicts[i].needsName);
+ if (sizeof(buff) - (p-buff) > 4 && conflicts[i].needsFlags & RPMSENSE_SENSEMASK) {
+ *p++ = ' ';
+ if (conflicts[i].needsFlags & RPMSENSE_LESS) *p++ = '<';
+ if (conflicts[i].needsFlags & RPMSENSE_GREATER) *p++ = '>';
+ if (conflicts[i].needsFlags & RPMSENSE_EQUAL) *p++ = '=';
+ if ((conflicts[i].needsFlags & RPMSENSE_SENSEMASK) == RPMSENSE_EQUAL) *p++ = '=';
+ *p++ = ' ';
+ p += snprintf(p, sizeof(buff) - (p-buff), "%s@%s-%s-%s",
+ conflicts[i].needsVersion,
+ conflicts[i].byName, conflicts[i].byVersion, conflicts[i].byRelease);
+ }
+ *p = 0;
+ XPUSHs(sv_2mortal(newSVpv(buff, p-buff)));
+ }
+ }
+ rpmdepFreeConflicts(conflicts, num_conflicts);
+ } else if (gimme == G_SCALAR) {
+ XPUSHs(sv_2mortal(newSViv(1)));
+ }
+
+int
+Trans_order(trans)
+ URPM::Transaction trans
+ PREINIT:
+ I32 gimme = GIMME_V;
+ PPCODE:
+ if (rpmdepOrder(trans->ts) == 0) {
+ if (gimme == G_SCALAR) {
+ XPUSHs(sv_2mortal(newSViv(1)));
+ }
+ } else {
+ if (gimme == G_SCALAR) {
+ XPUSHs(sv_2mortal(newSViv(0)));
+ } else if (gimme == G_ARRAY) {
+ XPUSHs(sv_2mortal(newSVpv("error while ordering dependencies", 0)));
+ }
+ }
+
+void
+Trans_run(trans, data, ...)
+ URPM::Transaction trans
+ SV *data
+ PREINIT:
+ /* available callback:
+ callback(data, 'open'|'close', pkg)
+ callback(data, 'trans'|'uninst'|'inst', pkg, 'start'|'progress'|'stop', amount, total)
+ */
+ SV* callback_open = NULL;
+ SV* callback_close = NULL;
+ SV* callback_trans = NULL;
+ SV* callback_uninst = NULL;
+ SV* callback_inst = NULL;
+ int min_delta = 200000;
+ rpmProblemSet probs;
+ int i;
+ void *rpmRunTransactions_callback(const void *h,
+ const rpmCallbackType what,
+ const unsigned long amount,
+ const unsigned long total,
+ const void * pkgKey,
+ void * data) {
+ static int last_amount;
+ static FD_t fd = NULL;
+ static struct timeval tprev;
+ static struct timeval tcurr;
+ long delta;
+ int i;
+ SV *callback = NULL;
+ char *callback_type = NULL;
+ char *callback_subtype = NULL;
+
+ switch (what) {
+ case RPMCALLBACK_INST_OPEN_FILE:
+ callback = callback_open; callback_type = "open"; break;
+
+ case RPMCALLBACK_INST_CLOSE_FILE:
+ callback = callback_close; callback_type = "close"; break;
+
+ case RPMCALLBACK_TRANS_START:
+ case RPMCALLBACK_TRANS_PROGRESS:
+ case RPMCALLBACK_TRANS_STOP:
+ callback = callback_trans; callback_type = "trans"; break;
+
+ case RPMCALLBACK_UNINST_START:
+ case RPMCALLBACK_UNINST_PROGRESS:
+ case RPMCALLBACK_UNINST_STOP:
+ callback = callback_uninst; callback_type = "uninst"; break;
+
+ case RPMCALLBACK_INST_START:
+ case RPMCALLBACK_INST_PROGRESS:
+ callback = callback_inst; callback_type = "inst"; break;
+ }
+
+ if (callback != NULL) {
+ switch (what) {
+ case RPMCALLBACK_TRANS_START:
+ case RPMCALLBACK_UNINST_START:
+ case RPMCALLBACK_INST_START:
+ callback_subtype = "start"; break;
+
+ case RPMCALLBACK_TRANS_PROGRESS:
+ case RPMCALLBACK_UNINST_PROGRESS:
+ case RPMCALLBACK_INST_PROGRESS:
+ gettimeofday(&tcurr, NULL);
+ delta = 1000000 * (tcurr.tv_sec - tprev.tv_sec) + (tcurr.tv_usec - tprev.tv_usec);
+ if (delta > 200000 || amount >= total - 1)
+ callback_subtype = "progress";
+ else
+ callback = NULL; /* avoid calling too often a given callback */
+ break;
+
+ case RPMCALLBACK_TRANS_STOP:
+ case RPMCALLBACK_UNINST_STOP:
+ callback_subtype = "stop"; break;
+ }
+
+ if (callback != NULL) {
+ /* now, a callback will be called for sure */
+ dSP;
+ PUSHMARK(sp);
+ XPUSHs(data);
+ XPUSHs(sv_2mortal(newSVpv(callback_type, 0)));
+ XPUSHs((SV *)pkgKey);
+ if (callback_subtype != NULL) {
+ XPUSHs(sv_2mortal(newSVpv(callback_subtype, 0)));
+ XPUSHs(sv_2mortal(newSViv(amount)));
+ XPUSHs(sv_2mortal(newSViv(total)));
+ }
+ PUTBACK;
+ i = perl_call_sv(callback, callback == callback_open ? G_SCALAR : G_DISCARD);
+ SPAGAIN;
+ if (i != 1 && callback == callback_open) croak("callback_open should return a file handle");
+ if (i == 1) {
+ i = POPi;
+ fd = fdDup(i);
+ fd = fdLink(fd, "persist perl-URPM");
+ PUTBACK;
+ return fd;
+ }
+ if (callback == callback_close) {
+ /* REFDEC on pkgKey */
+ fd = fdFree(fd, "persist perl-URPM");
+ if (fd) {
+ fdClose(fd);
+ fd = NULL;
+ }
+ }
+ }
+ }
+ return NULL;
+ }
+ PPCODE:
+ for (i = 2; i < items-1; i+=2) {
+ STRLEN len;
+ char *s = SvPV(ST(i), len);
+
+ if (len >= 9 && !memcmp(s, "callback_", 9)) {
+ if (len == 9+4 && !memcmp(s+9, "open", 4))
+ callback_open = ST(i+1);
+ else if (len == 9+5 && !memcmp(s+9, "close", 5))
+ callback_close = ST(i+1);
+ else if (len == 9+5 && !memcmp(s+9, "trans", 5))
+ callback_trans = ST(i+1);
+ else if (len == 9+6 && !memcmp(s+9, "uninst", 6))
+ callback_uninst = ST(i+1);
+ else if (len == 9+6 && !memcmp(s+9, "inst", 4))
+ callback_inst = ST(i+1);
+ } else if (len == 5 && !memcmp(s, "delta", 5))
+ min_delta = SvIV(ST(i+1));
+ }
+ if (rpmRunTransactions(trans->ts, rpmRunTransactions_callback, NULL, NULL, &probs, 0, 0)) {
+ EXTEND(SP, probs->numProblems);
+ for (i = 0; i < probs->numProblems; i++) {
+ const char *pkgNEVR = (probs->probs[i].pkgNEVR ? probs->probs[i].pkgNEVR : "");
+ const char *altNEVR = probs->probs[i].altNEVR ? probs->probs[i].altNEVR : "";
+ const char *s = probs->probs[i].str1 ? probs->probs[i].str1 : "";
+ SV *sv;
+
+ switch (probs->probs[i].type) {
+ case RPMPROB_BADARCH:
+ sv = newSVpvf("badarch@%s", pkgNEVR); break;
+
+ case RPMPROB_BADOS:
+ sv = newSVpvf("bados@%s", pkgNEVR); break;
+
+ case RPMPROB_PKG_INSTALLED:
+ sv = newSVpvf("installed@%s", pkgNEVR); break;
+
+ case RPMPROB_BADRELOCATE:
+ sv = newSVpvf("badrelocate@%s@%s", pkgNEVR, s); break;
+
+ case RPMPROB_NEW_FILE_CONFLICT:
+ case RPMPROB_FILE_CONFLICT:
+ sv = newSVpvf("conflicts@%s@%s@%s", pkgNEVR, altNEVR, s); break;
+
+ case RPMPROB_OLDPACKAGE:
+ sv = newSVpvf("installed@%s@%s", pkgNEVR, altNEVR); break;
+
+ case RPMPROB_DISKSPACE:
+ sv = newSVpvf("diskspace@%s@%s@%ld", pkgNEVR, s, probs->probs[i].ulong1); break;
+
+ case RPMPROB_DISKNODES:
+ sv = newSVpvf("disknodes@%s@%s@%ld", pkgNEVR, s, probs->probs[i].ulong1); break;
+
+ case RPMPROB_BADPRETRANS:
+ sv = newSVpvf("badpretrans@%s@%s@%s", pkgNEVR, s, strerror(probs->probs[i].ulong1)); break;
+
+ case RPMPROB_REQUIRES:
+ sv = newSVpvf("requires@%s@%s@%s", pkgNEVR, altNEVR+2); break;
+
+ case RPMPROB_CONFLICT:
+ sv = newSVpvf("conflicts@%s@%s", pkgNEVR, altNEVR+2); break;
+
+ default:
+ sv = newSVpvf("unknown@%s", pkgNEVR); break;
+ }
+ PUSHs(sv_2mortal(sv));
+ }
+ }
+
+
MODULE = URPM PACKAGE = URPM PREFIX = Urpm_
int