From 58c9d5d66387821260ba9bdd0815568039462f39 Mon Sep 17 00:00:00 2001 From: Judd Vinet Date: Mon, 26 Dec 2005 06:40:29 +0000 Subject: applied first try at sync conflict handling (VMiklos) plus a couple changes --- lib/libalpm/alpm.h | 1 + lib/libalpm/db.c | 14 ++++++ lib/libalpm/sync.c | 129 ++++++++++++++++++++++++++++++++++++++++++++++++----- src/pacman/trans.c | 7 +++ 4 files changed, 139 insertions(+), 12 deletions(-) diff --git a/lib/libalpm/alpm.h b/lib/libalpm/alpm.h index 0e84d6e0..5a0ddf0a 100644 --- a/lib/libalpm/alpm.h +++ b/lib/libalpm/alpm.h @@ -235,6 +235,7 @@ enum { enum { PM_TRANS_CONV_INSTALL_IGNOREPKG, PM_TRANS_CONV_REPLACE_PKG, + PM_TRANS_CONV_CONFLICT_PKG, PM_TRANS_CONV_LOCAL_NEWER, PM_TRANS_CONV_LOCAL_UPTODATE }; diff --git a/lib/libalpm/db.c b/lib/libalpm/db.c index 139bc3bb..cf3b63ea 100644 --- a/lib/libalpm/db.c +++ b/lib/libalpm/db.c @@ -348,6 +348,20 @@ int db_read(pmdb_t *db, char *name, unsigned int inforeq, pmpkg_t *info) if(fgets(info->md5sum, sizeof(info->md5sum), fp) == NULL) { return(-1); } + /* XXX: these are only here as backwards-compatibility for pacman 2.x + * sync repos.... in pacman3, they have been moved to DEPENDS. + * Remove this when we move to pacman3 repos. + */ + } else if(!strcmp(line, "%REPLACES%")) { + /* the REPLACES tag is special -- it only appears in sync repositories, + * not the local one. */ + while(fgets(line, 512, fp) && strlen(_alpm_strtrim(line))) { + info->replaces = pm_list_add(info->replaces, strdup(line)); + } + } else if(!strcmp(line, "%FORCE%")) { + /* FORCE tag only appears in sync repositories, + * not the local one. */ + info->force = 1; } } fclose(fp); diff --git a/lib/libalpm/sync.c b/lib/libalpm/sync.c index 83b2da90..7e36fd11 100644 --- a/lib/libalpm/sync.c +++ b/lib/libalpm/sync.c @@ -42,6 +42,7 @@ #include "sync.h" #include "rpmvercmp.h" #include "handle.h" +#include "alpm.h" extern pmhandle_t *handle; @@ -225,9 +226,7 @@ int sync_sysupgrade(pmtrans_t *trans, pmdb_t *db_local, PMList *dbs_sync) _alpm_log(PM_LOG_FLOW1, "%s-%s: ignoring package upgrade (%s)", local->name, local->version, spkg->version); } else { - pmpkg_t *dummy = pkg_new(); - STRNCPY(dummy->name, local->name, PKG_NAME_LEN); - STRNCPY(dummy->version, local->version, PKG_VERSION_LEN); + pmpkg_t *dummy = pkg_dummy(local->name, local->version); sync = sync_new(PM_SYNC_TYPE_UPGRADE, spkg, dummy); if(sync == NULL) { FREEPKG(dummy); @@ -329,6 +328,13 @@ int sync_addtarget(pmtrans_t *trans, pmdb_t *db_local, PMList *dbs_sync, char *n return(0); } +/* Helper function for _alpm_list_remove + */ +static int ptr_cmp(const void *s1, const void *s2) +{ + return((s1 == s2)); +} + int sync_prepare(pmtrans_t *trans, pmdb_t *db_local, PMList *dbs_sync, PMList **data) { PMList *deps = NULL; @@ -368,6 +374,7 @@ int sync_prepare(pmtrans_t *trans, pmdb_t *db_local, PMList *dbs_sync, PMList ** trans->packages = pm_list_add(trans->packages, sync); } } + EVENT(trans, PM_TRANS_EVT_RESOLVEDEPS_DONE, NULL, NULL); /* check for inter-conflicts and whatnot */ @@ -375,7 +382,7 @@ int sync_prepare(pmtrans_t *trans, pmdb_t *db_local, PMList *dbs_sync, PMList ** deps = checkdeps(db_local, PM_TRANS_TYPE_UPGRADE, list); if(deps) { int found; - PMList *j, *k, *exfinal = NULL; + PMList *j, *k, *asked = NULL; int errorout = 0; _alpm_log(PM_LOG_FLOW1, "looking for unresolvable dependencies"); for(i = deps; i; i = i->next) { @@ -406,10 +413,6 @@ int sync_prepare(pmtrans_t *trans, pmdb_t *db_local, PMList *dbs_sync, PMList ** if(miss->type != PM_DEP_TYPE_CONFLICT) { continue; } - /* make sure this package wasn't already removed from the final list */ - if(pm_list_is_in(miss->target, exfinal)) { - continue; - } /* check if the conflicting package is one that's about to be removed/replaced. * if so, then just ignore it @@ -428,8 +431,111 @@ int sync_prepare(pmtrans_t *trans, pmdb_t *db_local, PMList *dbs_sync, PMList ** } } - /* ORE - if we didn't find it in any sync->replaces lists, then it's a conflict */ + /* if we didn't find it in any sync->replaces lists, then it's a conflict */ + if(!found) { + int solved = 0; + pmsyncpkg_t *sync = find_pkginsync(miss->target, trans->packages); + for(j = sync->pkg->provides; j && j->data && !solved; j = j->next) { + if(!strcmp(j->data, miss->depend.name)) { + /* this package also "provides" the package it's conflicting with, + * so just treat it like a "replaces" item so the REQUIREDBY + * fields are inherited properly. + */ + + /* we save the dependency info so we can move p's requiredby stuff + * over to the replacing package + */ + pmpkg_t *q = db_scan(db_local, miss->depend.name, INFRQ_DESC | INFRQ_DEPENDS); + if(q) { + /* append to the replaces list */ + pmsyncpkg_t *spkg = sync_new(PM_SYNC_TYPE_REPLACE, q, NULL); + trans->packages = pm_list_add(trans->packages, spkg); + solved = 1; + } else { + char *rmpkg = NULL; + /* hmmm, depend.name isn't installed, so it must be conflicting + * with another package in our final list. For example: + * + * pacman -S blackbox xfree86 + * + * If no x-servers are installed and blackbox pulls in xorg, then + * xorg and xfree86 will conflict with each other. In this case, + * we should follow the user's preference and rip xorg out of final, + * opting for xfree86 instead. + */ + + /* figure out which one was requested in targets. If they both were, + * then it's still an unresolvable conflict. */ + if(pm_list_is_in(miss->depend.name, trans->targets) && !pm_list_is_in(miss->target, trans->targets)) { + /* remove miss->target */ + rmpkg = strdup(miss->target); + } else if(pm_list_is_in(miss->target, trans->targets) && !pm_list_is_in(miss->depend.name, trans->targets)) { + /* remove miss->depend.name */ + rmpkg = strdup(miss->depend.name); + } else { + /* something's not right, bail out with a conflict error */ + } + if(rmpkg) { + for(k = trans->packages; k; k = k->next) { + pmsyncpkg_t *sync = k->data; + if(!strcmp(sync->pkg->name, rmpkg)) + trans->packages = _alpm_list_remove(trans->packages, sync, ptr_cmp, (void **)&data); + } + solved = 1; + } + } + } + } + if(!solved) { + /* It's a conflict -- see if they want to remove it + */ + pmpkg_t *p,*q = NULL; + int pkgfound = 0; + for(k = db_get_pkgcache(db_local); k; k = k->next) { + p = k->data; + if(!strcmp(p->name, miss->depend.name)) { + pkgfound = 1; + break; + } + } + if(pkgfound) { + int doremove = 0; + if(!pm_list_is_strin(miss->depend.name, asked)) { + QUESTION(trans, PM_TRANS_CONV_CONFLICT_PKG, miss->target, miss->depend.name, NULL, &doremove); + asked = pm_list_add(asked, strdup(miss->depend.name)); + if(doremove) { + PMList *l; + /* remove miss->depend.name */ + for(l = trans->packages; l; l = l->next) { + pmsyncpkg_t *s = l->data; + if(!strcmp(s->pkg->name, miss->target)) { + q = pkg_new(); + strcpy(q->name, miss->depend.name); + if(s->type == PM_SYNC_TYPE_REPLACE) { + /* append to the replaces list */ + s->data = pm_list_add(s->data, q); + } else { + /* switch this sync type to REPLACE */ + s->type = PM_SYNC_TYPE_REPLACE; + /* add miss->depend.name to the replaces list */ + k = pm_list_new(); + k = pm_list_add(k, q); + s->data = k; + } + } + } + } else { + /* abort */ + _alpm_log(PM_LOG_ERROR, "package conflicts detected"); + errorout = 1; + } + } + } else { + _alpm_log(PM_LOG_ERROR, "%s conflicts with %s", miss->target, miss->depend.name); + errorout = 1; + } + } + } } if(errorout) { @@ -494,8 +600,7 @@ int sync_commit(pmtrans_t *trans, pmdb_t *db_local) goto error; } - /* ORE - trans_init(PM_TRANS_TYPE_REMOVE, PM_TRANS_FLAGS_NODEPS); */ + trans_init(tr, PM_TRANS_TYPE_REMOVE, PM_TRANS_FLAG_NODEPS, trans->cb_event, trans->cb_conv); for(i = trans->packages; i; i = i->next) { pmsyncpkg_t *sync = i->data; diff --git a/src/pacman/trans.c b/src/pacman/trans.c index 3f6f6bea..6a997545 100644 --- a/src/pacman/trans.c +++ b/src/pacman/trans.c @@ -112,6 +112,13 @@ void cb_trans_conv(unsigned char event, void *data1, void *data2, void *data3, i (char *)alpm_pkg_getinfo(data2, PM_PKG_NAME)); *response = yesno(str); break; + case PM_TRANS_CONV_CONFLICT_PKG: + snprintf(str, LOG_STR_LEN, "\n:: %s conflicts with %s. Remove %s? [Y/n] ", + (char *)data1, + (char *)data2, + (char *)data2); + *response = yesno(str); + break; case PM_TRANS_CONV_LOCAL_NEWER: snprintf(str, LOG_STR_LEN, ":: %s-%s: local version is newer. Upgrade anyway? [Y/n] ", (char *)alpm_pkg_getinfo(data1, PM_PKG_NAME), -- cgit v1.2.3-70-g09d2