summaryrefslogtreecommitdiff
path: root/lib/libalpm
diff options
context:
space:
mode:
Diffstat (limited to 'lib/libalpm')
-rw-r--r--lib/libalpm/alpm.h1
-rw-r--r--lib/libalpm/db.c14
-rw-r--r--lib/libalpm/sync.c129
3 files changed, 132 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;