Radish alpha
H
rad:z3QDZAW2FAfuLvihrhiyDC9fAD8G9
HardenedBSD Package Manager
Radicle
Git
Another pkg universe rework.
Vsevolod Stakhov committed 12 years ago
commit 07272b80d077971700209a599555ce11d186ed44
parent 8d462a5
5 files changed +404 -132
modified libpkg/pkg.c
@@ -59,7 +59,7 @@ static struct _fields {
	[PKG_OLD_VERSION] = {"oldversion", PKG_REMOTE, 1},
	[PKG_REPONAME] = {"reponame", PKG_REMOTE, 1},
	[PKG_REPOURL] = {"repourl", PKG_REMOTE, 1},
-
	[PKG_DIGEST] = {"manifestdigest", PKG_REMOTE, 1},
+
	[PKG_DIGEST] = {"manifestdigest", PKG_REMOTE|PKG_INSTALLED, 1},
	[PKG_REASON] = {"reason", PKG_REMOTE, 1}
};

modified libpkg/pkg_cudf.c
@@ -135,14 +135,18 @@ cudf_emit_request_packages(const char *op, struct pkg_jobs *j, FILE *f)
int
pkg_jobs_cudf_emit_file(struct pkg_jobs *j, pkg_jobs_t t, FILE *f, struct pkgdb *db)
{
-
	struct pkg *pkg, *tmp;
+
	struct pkg *pkg;
+
	struct pkg_job_universe_item *it, *itmp, *icur;

	if (fprintf(f, "preamble: \n\n") < 0)
		return (EPKG_FATAL);

-
	HASH_ITER(hh, j->universe, pkg, tmp) {
-
		if (cudf_emit_pkg(pkg, f, db) != EPKG_OK)
-
			return (EPKG_FATAL);
+
	HASH_ITER(hh, j->universe, it, itmp) {
+
		LL_FOREACH(it, icur) {
+
			pkg = icur->pkg;
+
			if (cudf_emit_pkg(pkg, f, db) != EPKG_OK)
+
				return (EPKG_FATAL);
+
		}
	}

	if (fprintf(f, "request: \n") < 0)
modified libpkg/pkg_jobs.c
@@ -42,8 +42,9 @@
#include "private/pkg.h"
#include "private/pkgdb.h"

-
static int get_remote_pkg(struct pkg_jobs *j, const char *pattern, match_t m, bool root);
+
static int find_remote_pkg(struct pkg_jobs *j, const char *pattern, match_t m, bool root);
static struct pkg *get_local_pkg(struct pkg_jobs *j, const char *origin, unsigned flag);
+
static struct pkg *get_remote_pkg(struct pkg_jobs *j, const char *origin, unsigned flag);
static int pkg_jobs_fetch(struct pkg_jobs *j);
static bool newer_than_local_pkg(struct pkg_jobs *j, struct pkg *rp, bool force);
static bool new_pkg_version(struct pkg_jobs *j);
@@ -158,6 +159,146 @@ pkg_jobs_add_req(struct pkg_jobs *j, const char *origin, struct pkg *pkg, bool a
		HASH_ADD_KEYPTR(hh, j->request_delete, origin, strlen(origin), req);
}

+
/**
+
 * Check whether a package is in the universe already or add it
+
 * @return item or NULL
+
 */
+
static int
+
pkg_jobs_handle_pkg_universe(struct pkg_jobs *j, struct pkg *pkg)
+
{
+
	struct pkg_job_universe_item *item, *cur, *tmp;
+
	const char *origin, *digest, *digest_cur;
+

+
	pkg_get(pkg, PKG_ORIGIN, &origin, PKG_DIGEST, &digest);
+
	HASH_FIND_STR(j->universe, __DECONST(char *, origin), item);
+
	if (item == NULL) {
+
		/* Insert new origin */
+
		item = calloc(1, sizeof (struct pkg_job_universe_item));
+

+
		if (item == NULL) {
+
			pkg_emit_errno("pkg_jobs_handle_universe", "calloc: struct pkg_job_universe_item");
+
			return (EPKG_FATAL);
+
		}
+
		item->pkg = pkg;
+
		HASH_ADD_KEYPTR(hh, j->universe, __DECONST(char *, origin), strlen(origin), item);
+
	}
+

+
	/* Search for the same package added */
+
	LL_FOREACH(item, cur) {
+
		pkg_get(cur->pkg, PKG_DIGEST, &digest_cur);
+
		if (strcmp (digest, digest_cur) == 0) {
+
			/* Free new package */
+
			pkg_free(pkg);
+
			return (EPKG_OK);
+
		}
+
		tmp = cur;
+
	}
+

+
	item = calloc(1, sizeof (struct pkg_job_universe_item));
+
	if (item == NULL) {
+
		pkg_emit_errno("pkg_jobs_pkg_insert_universe", "calloc: struct pkg_job_universe_item");
+
		return (EPKG_FATAL);
+
	}
+

+
	item->pkg = pkg;
+
	tmp->next = item;
+

+
	return (EPKG_OK);
+
}
+

+
static int
+
pkg_jobs_add_universe(struct pkg_jobs *j, struct pkg *pkg)
+
{
+
	struct pkg_dep *d = NULL;
+
	struct pkg_conflict *c = NULL;
+
	struct pkg *npkg;
+

+
	/* Go through all depends */
+
	while (pkg_deps(pkg, &d) == EPKG_OK) {
+
		if (pkg->type == PKG_INSTALLED) {
+
			npkg = get_local_pkg(j, pkg_dep_get(d, PKG_DEP_ORIGIN), 0);
+
			if (npkg == NULL) {
+
				/*
+
				 * We have a package installed, but its dependencies are not,
+
				 * try to search a remote dependency
+
				 */
+
				npkg = get_remote_pkg(j, pkg_dep_get(d, PKG_DEP_ORIGIN), 0);
+
				if (npkg == NULL) {
+
					/* Cannot continue */
+
					pkg_emit_error("Missing dependency matching '%s'", pkg_dep_get(d, PKG_DEP_ORIGIN));
+
					return (EPKG_FATAL);
+
				}
+
			}
+
		}
+
		else {
+
			npkg = get_remote_pkg(j, pkg_dep_get(d, PKG_DEP_ORIGIN), 0);
+
			if (npkg == NULL) {
+
				npkg = get_local_pkg(j, pkg_dep_get(d, PKG_DEP_ORIGIN), 0);
+
				if (npkg == NULL) {
+
					/* Cannot continue */
+
					pkg_emit_error("Missing dependency matching '%s'", pkg_dep_get(d, PKG_DEP_ORIGIN));
+
					return (EPKG_FATAL);
+
				}
+
			}
+
		}
+
		if (pkg_jobs_handle_pkg_universe(j, npkg) != EPKG_OK)
+
			return (EPKG_FATAL);
+
	}
+

+
	/* Go through all rdeps */
+
	d = NULL;
+
	while (pkg_rdeps(pkg, &d) == EPKG_OK) {
+
		if (pkg->type == PKG_INSTALLED) {
+
			npkg = get_local_pkg(j, pkg_dep_get(d, PKG_DEP_ORIGIN), 0);
+
			if (npkg == NULL) {
+
				/*
+
				 * We have a package installed, but its dependencies are not,
+
				 * try to search a remote dependency
+
				 */
+
				npkg = get_remote_pkg(j, pkg_dep_get(d, PKG_DEP_ORIGIN), 0);
+
				if (npkg == NULL) {
+
					/* Cannot continue */
+
					pkg_emit_error("Missing dependency matching '%s'", pkg_dep_get(d, PKG_DEP_ORIGIN));
+
					return (EPKG_FATAL);
+
				}
+
			}
+
		}
+
		else {
+
			/* Do not care about remote rdeps */
+
			continue;
+
		}
+

+
		if (pkg_jobs_handle_pkg_universe(j, npkg) != EPKG_OK)
+
			return (EPKG_FATAL);
+
	}
+

+
	/* Examine conflicts */
+
	while (pkg_conflicts(pkg, &c) == EPKG_OK) {
+
		if (pkg->type == PKG_INSTALLED) {
+
			/* We assume that we cannot have conflicts installed */
+
			npkg = get_remote_pkg(j, pkg_conflict_origin(c), 0);
+
			if (npkg == NULL) {
+
				continue;
+
			}
+
		}
+
		else {
+
			/* Check both local and remote conflicts */
+
			npkg = get_remote_pkg(j, pkg_dep_get(d, PKG_DEP_ORIGIN), 0);
+
			if (pkg_jobs_handle_pkg_universe(j, npkg) != EPKG_OK)
+
				return (EPKG_FATAL);
+
			npkg = get_local_pkg(j, pkg_dep_get(d, PKG_DEP_ORIGIN), 0);
+
			if (npkg == NULL) {
+
				continue;
+
			}
+
		}
+

+
		if (pkg_jobs_handle_pkg_universe(j, npkg) != EPKG_OK)
+
			return (EPKG_FATAL);
+
	}
+

+
	return (EPKG_OK);
+
}
+


static int
populate_local_rdeps(struct pkg_jobs *j, struct pkg *p)
@@ -282,8 +423,10 @@ jobs_solve_deinstall(struct pkg_jobs *j)
			pkg_set(pkg, PKG_OLD_FLATSIZE, oldsize, PKG_FLATSIZE, (int64_t)0);
			HASH_ADD_KEYPTR(hh, j->bulk, origin, strlen(origin), pkg);
			pkg_jobs_add_req(j, origin, pkg, false);
-
			if (recursive)
+
			if (recursive) {
				populate_local_rdeps(j, pkg);
+
				pkg_jobs_add_universe(j, pkg);
+
			}
			pkg = NULL;
		}
		pkgdb_it_free(it);
@@ -389,7 +532,7 @@ jobs_solve_upgrade(struct pkg_jobs *j)
		pkg_get(pkg, PKG_ORIGIN, &origin);
		pkg_jobs_add_req(j, origin, pkg, true);
		/* Do not test we ignore what doesn't exists remotely */
-
		get_remote_pkg(j, origin, MATCH_EXACT, false);
+
		find_remote_pkg(j, origin, MATCH_EXACT, false);
		pkg = NULL;
	}
	pkgdb_it_free(it);
@@ -508,7 +651,7 @@ populate_rdeps(struct pkg_jobs *j, struct pkg *p)
		HASH_FIND_STR(j->seen, __DECONST(char *, pkg_dep_get(d, PKG_DEP_ORIGIN)), pkg);
		if (pkg != NULL)
			continue;
-
		if (get_remote_pkg(j, pkg_dep_get(d, PKG_DEP_ORIGIN), MATCH_EXACT, true) != EPKG_OK) {
+
		if (find_remote_pkg(j, pkg_dep_get(d, PKG_DEP_ORIGIN), MATCH_EXACT, true) != EPKG_OK) {
			pkg_emit_error("Missing reverse dependency matching '%s'", pkg_dep_get(d, PKG_DEP_ORIGIN));
			return (EPKG_FATAL);
		}
@@ -530,7 +673,7 @@ populate_deps(struct pkg_jobs *j, struct pkg *p)
		HASH_FIND_STR(j->seen, __DECONST(char *, pkg_dep_get(d, PKG_DEP_ORIGIN)), pkg);
		if (pkg != NULL)
			continue;
-
		if (get_remote_pkg(j, pkg_dep_get(d, PKG_DEP_ORIGIN), MATCH_EXACT, false) != EPKG_OK) {
+
		if (find_remote_pkg(j, pkg_dep_get(d, PKG_DEP_ORIGIN), MATCH_EXACT, false) != EPKG_OK) {
			pkg_emit_error("Missing dependency matching '%s'", pkg_dep_get(d, PKG_DEP_ORIGIN));
			return (EPKG_FATAL);
		}
@@ -565,7 +708,7 @@ new_pkg_version(struct pkg_jobs *j)
		goto end;
	}

-
	if (get_remote_pkg(j, origin, MATCH_EXACT, false) == EPKG_OK && HASH_COUNT(j->bulk) == 1) {
+
	if (find_remote_pkg(j, origin, MATCH_EXACT, false) == EPKG_OK && HASH_COUNT(j->bulk) == 1) {
		ret = true;
		goto end;
	}
@@ -582,7 +725,7 @@ end:
}

static int
-
get_remote_pkg(struct pkg_jobs *j, const char *pattern, match_t m, bool root)
+
find_remote_pkg(struct pkg_jobs *j, const char *pattern, match_t m, bool root)
{
	struct pkg *p = NULL;
	struct pkg *p1;
@@ -694,6 +837,29 @@ get_local_pkg(struct pkg_jobs *j, const char *origin, unsigned flag)
	return (pkg);
}

+
static struct pkg *
+
get_remote_pkg(struct pkg_jobs *j, const char *origin, unsigned flag)
+
{
+
	struct pkg *pkg = NULL;
+
	struct pkgdb_it *it;
+

+
	if (flag == 0) {
+
		flag = PKG_LOAD_BASIC|PKG_LOAD_DEPS|PKG_LOAD_OPTIONS|
+
				PKG_LOAD_SHLIBS_REQUIRED|PKG_LOAD_ANNOTATIONS|
+
				PKG_LOAD_CONFLICTS;
+
	}
+

+
	if ((it = pkgdb_rquery(j->db, origin, MATCH_EXACT, j->reponame)) == NULL)
+
		return (NULL);
+

+
	if (pkgdb_it_next(it, &pkg, flag) != EPKG_OK)
+
		pkg = NULL;
+

+
	pkgdb_it_free(it);
+

+
	return (pkg);
+
}
+

static bool
newer_than_local_pkg(struct pkg_jobs *j, struct pkg *rp, bool force)
{
@@ -903,17 +1069,17 @@ jobs_solve_install(struct pkg_jobs *j)
				d = NULL;
				pkg_get(pkg, PKG_ORIGIN, &origin);
				pkg_jobs_add_req(j, origin, pkg, false);
-
				if (get_remote_pkg(j, origin, MATCH_EXACT, true) == EPKG_FATAL)
+
				if (find_remote_pkg(j, origin, MATCH_EXACT, true) == EPKG_FATAL)
					pkg_emit_error("No packages matching '%s', has been found in the repositories", origin);

				while (pkg_rdeps(pkg, &d) == EPKG_OK) {
-
					if (get_remote_pkg(j, pkg_dep_origin(d), MATCH_EXACT, false) == EPKG_FATAL)
+
					if (find_remote_pkg(j, pkg_dep_origin(d), MATCH_EXACT, false) == EPKG_FATAL)
						pkg_emit_error("No packages matching '%s', has been found in the repositories", pkg_dep_origin(d));
				}
			}
			pkgdb_it_free(it);
		} else {
-
			if (get_remote_pkg(j, jp->pattern, jp->match, true) == EPKG_FATAL)
+
			if (find_remote_pkg(j, jp->pattern, jp->match, true) == EPKG_FATAL)
				pkg_emit_error("No packages matching '%s' has been found in the repositories", jp->pattern);
		}
	}
@@ -983,13 +1149,13 @@ jobs_solve_fetch(struct pkg_jobs *j)
			pkg_get(pkg, PKG_ORIGIN, &origin);
			pkg_jobs_add_req(j, origin, pkg, false);
			/* Do not test we ignore what doesn't exists remotely */
-
			get_remote_pkg(j, origin, MATCH_EXACT, false);
+
			find_remote_pkg(j, origin, MATCH_EXACT, false);
			pkg = NULL;
		}
		pkgdb_it_free(it);
	} else {
		LL_FOREACH(j->patterns, jp) {
-
			if (get_remote_pkg(j, jp->pattern, jp->match, true) == EPKG_FATAL)
+
			if (find_remote_pkg(j, jp->pattern, jp->match, true) == EPKG_FATAL)
				pkg_emit_error("No packages matching '%s' has been found in the repositories", jp->pattern);
		}
	}
modified libpkg/pkg_solve.c
@@ -42,9 +42,12 @@
struct pkg_solve_variable {
	struct pkg *pkg;
	bool to_install;
+
	const char *digest;
	const char *origin;
	bool resolved;
-
	UT_hash_handle hh;
+
	UT_hash_handle hd;
+
	UT_hash_handle ho;
+
	struct pkg_solve_variable *next;
};

struct pkg_solve_item {
@@ -110,29 +113,42 @@ pkg_solve_propagate_units(struct pkg_solve_rule *rules)
{
	struct pkg_solve_rule *cur;
	struct pkg_solve_item *it, *unresolved = NULL;
-
	int resolved = 0, total = 0;
+
	int resolved = 0, total = 0, solved_vars;
+
	bool ret;

-
	LL_FOREACH(rules, cur) {
+
	do {
+
		solved_vars = 0;
+
		LL_FOREACH(rules, cur) {

-
		LL_FOREACH(cur->items, it) {
-
			if (it->var->resolved && PKG_SOLVE_CHECK_ITEM(it))
-
				resolved++;
-
			else
-
				unresolved = it;
-
			total ++;
-
		}
-
		/* It is a unit */
-
		if (total == resolved + 1 && unresolved != NULL) {
-
			if (!unresolved->var->resolved) {
-
				/* Propagate unit */
-
				unresolved->var->resolved = true;
-
				unresolved->var->to_install = !unresolved->inverse;
-
				return (true);
+
			LL_FOREACH(cur->items, it) {
+
				if (it->var->resolved && PKG_SOLVE_CHECK_ITEM(it))
+
					resolved++;
+
				else
+
					unresolved = it;
+
				total ++;
+
			}
+
			/* It is a unit */
+
			if (total == resolved + 1 && unresolved != NULL) {
+
				if (!unresolved->var->resolved) {
+
					/* Propagate unit */
+
					unresolved->var->resolved = true;
+
					unresolved->var->to_install = !unresolved->inverse;
+
					solved_vars ++;
+
				}
+
				/* Now check for a conflict */
+
				ret = false;
+
				LL_FOREACH(cur->items, it) {
+
					if (PKG_SOLVE_CHECK_ITEM(it))
+
						ret = true;
+
				}
+
				/* A conflict found */
+
				if (!ret)
+
					return false;
			}
		}
-
	}
+
	} while (solved_vars > 0);

-
	return (false);
+
	return (true);
}


@@ -285,7 +301,7 @@ static struct pkg_solve_variable *
pkg_solve_variable_new(struct pkg *pkg)
{
	struct pkg_solve_variable *result;
-
	const char *origin;
+
	const char *digest, *origin;

	result = calloc(1, sizeof(struct pkg_solve_variable));

@@ -295,8 +311,9 @@ pkg_solve_variable_new(struct pkg *pkg)
	}

	result->pkg = pkg;
-
	pkg_get(pkg, PKG_ORIGIN, &origin);
+
	pkg_get(pkg, PKG_ORIGIN, &origin, PKG_DIGEST, &digest);
	/* XXX: Is it safe to save a ptr here ? */
+
	result->digest = digest;
	result->origin = origin;

	return (result);
@@ -322,104 +339,166 @@ pkg_solve_problem_free(struct pkg_solve_problem *problem)
	LL_FOREACH_SAFE(problem->rules, r, rtmp) {
		pkg_solve_rule_free(r);
	}
-
	HASH_ITER(hh, problem->variables, v, vtmp) {
-
		HASH_DEL(problem->variables, v);
+
	HASH_ITER(hd, problem->variables, v, vtmp) {
+
		HASH_DELETE(hd, problem->variables, v);
		free(v);
	}
}

static int
+
pkg_solve_add_universe_variable(struct pkg_jobs *j,
+
		struct pkg_solve_problem *problem, const char *origin, struct pkg_solve_variable **var)
+
{
+
	struct pkg_job_universe_item *unit;
+
	struct pkg_solve_variable *nvar, *tvar;
+

+
	HASH_FIND_STR(j->universe, __DECONST(char *, origin), unit);
+
	/* If there is no package in universe, refuse continue */
+
	if (unit == NULL)
+
		return (EPKG_FATAL);
+
	/* Need to add a variable */
+
	nvar = pkg_solve_variable_new(unit->pkg);
+
	if (nvar == NULL)
+
		return (EPKG_FATAL);
+
	HASH_ADD_KEYPTR(ho, problem->variables, nvar->origin, strlen(nvar->origin), nvar);
+
	HASH_ADD_KEYPTR(hd, problem->variables, nvar->digest, strlen(nvar->digest), nvar);
+
	unit = unit->next;
+
	tvar = nvar;
+
	while (unit != NULL) {
+
		/* Add all alternatives as independent variables */
+
		tvar->next = pkg_solve_variable_new(unit->pkg);
+
		tvar = tvar->next;
+
		if (tvar == NULL)
+
			return (EPKG_FATAL);
+
		HASH_ADD_KEYPTR(hd, problem->variables, tvar->digest, strlen(tvar->digest), tvar);
+
		unit = unit->next;
+
	}
+

+
	*var = nvar;
+

+
	return (EPKG_OK);
+
}
+

+
static int
pkg_solve_add_pkg_rule(struct pkg_jobs *j, struct pkg_solve_problem *problem,
-
		struct pkg_solve_variable *pvar)
+
		struct pkg_solve_variable *pvar, bool conflicting)
{
	struct pkg_dep *dep, *dtmp;
	struct pkg_conflict *conflict, *ctmp;
-
	struct pkg *ptmp, *pkg = pvar->pkg;
+
	struct pkg *pkg;
	struct pkg_solve_rule *rule;
	struct pkg_solve_item *it;
-
	struct pkg_solve_variable *var;
-
	const char *origin;
+
	struct pkg_solve_variable *var, *tvar, *cur_var;

-
	/* Go through all deps */
-
	HASH_ITER(hh, pkg->deps, dep, dtmp) {
-
		rule = NULL;
-
		it = NULL;
-
		var = NULL;
+
	const char *origin;

-
		origin = pkg_dep_get(dep, PKG_DEP_ORIGIN);
-
		HASH_FIND_STR(problem->variables, __DECONST(char *, origin), var);
-
		if (var == NULL) {
-
			HASH_FIND_STR(j->universe, __DECONST(char *, origin), ptmp);
-
			/* If there is no package in universe, refuse continue */
-
			if (ptmp == NULL)
-
				return (EPKG_FATAL);
-
			/* Need to add a variable */
-
			var = pkg_solve_variable_new(ptmp);
-
			if (var == NULL)
+
	/* Go through all deps in all variables*/
+
	LL_FOREACH(pvar, cur_var) {
+
		pkg = cur_var->pkg;
+
		HASH_ITER(hh, pkg->deps, dep, dtmp) {
+
			rule = NULL;
+
			it = NULL;
+
			var = NULL;
+

+
			origin = pkg_dep_get(dep, PKG_DEP_ORIGIN);
+
			HASH_FIND(ho, problem->variables, __DECONST(char *, origin), strlen(origin), var);
+
			if (var == NULL) {
+
				if (pkg_solve_add_universe_variable(j, problem, origin, &var) != EPKG_OK)
+
					goto err;
+
			}
+
			/* Dependency rule: (!A | B) */
+
			rule = pkg_solve_rule_new();
+
			if (rule == NULL)
+
				goto err;
+
			/* !A */
+
			it = pkg_solve_item_new(cur_var);
+
			if (it == NULL)
				goto err;
-
			HASH_ADD_KEYPTR(hh, problem->variables, var->origin, strlen(var->origin), var);
-
		}
-
		/* Dependency rule: (!A | B) */
-
		rule = pkg_solve_rule_new();
-
		if (rule == NULL)
-
			goto err;
-
		/* !A */
-
		it = pkg_solve_item_new(pvar);
-
		if (it == NULL)
-
			goto err;
-

-
		it->inverse = true;
-
		LL_PREPEND(rule->items, it);
-
		/* B */
-
		it = pkg_solve_item_new(var);
-
		if (it == NULL)
-
			goto err;
-

-
		it->inverse = false;
-
		LL_PREPEND(rule->items, it);

-
		LL_PREPEND(problem->rules, rule);
-
	}
+
			it->inverse = true;
+
			LL_PREPEND(rule->items, it);
+
			/* B1 | B2 | ... */
+
			LL_FOREACH(var, tvar) {
+
				it = pkg_solve_item_new(tvar);
+
				if (it == NULL)
+
					goto err;

-
	/* Go through all conflicts */
-
	HASH_ITER(hh, pkg->conflicts, conflict, ctmp) {
-
		rule = NULL;
-
		it = NULL;
-
		var = NULL;
+
				it->inverse = false;
+
				LL_PREPEND(rule->items, it);
+
			}

-
		origin = pkg_conflict_origin(conflict);
-
		HASH_FIND_STR(problem->variables, __DECONST(char *, origin), var);
-
		if (var == NULL) {
-
			HASH_FIND_STR(j->universe, __DECONST(char *, origin), ptmp);
-
			/* If there is no package in universe, refuse continue */
-
			if (ptmp == NULL)
-
				return (EPKG_FATAL);
-
			/* Need to add a variable */
-
			var = pkg_solve_variable_new(ptmp);
-
			if (var == NULL)
-
				goto err;
-
			HASH_ADD_KEYPTR(hh, problem->variables, var->origin, strlen(var->origin), var);
+
			LL_PREPEND(problem->rules, rule);
		}
-
		/* Conflict rule: (!A | !B) */
-
		rule = pkg_solve_rule_new();
-
		if (rule == NULL)
-
			goto err;
-
		/* !A */
-
		it = pkg_solve_item_new(pvar);
-
		if (it == NULL)
-
			goto err;
-

-
		it->inverse = true;
-
		LL_PREPEND(rule->items, it);
-
		/* !B */
-
		it = pkg_solve_item_new(var);
-
		if (it == NULL)
-
			goto err;

-
		it->inverse = true;
-
		LL_PREPEND(rule->items, it);
+
		/* Go through all conflicts */
+
		HASH_ITER(hh, pkg->conflicts, conflict, ctmp) {
+
			rule = NULL;
+
			it = NULL;
+
			var = NULL;
+

+
			origin = pkg_conflict_origin(conflict);
+
			HASH_FIND(ho, problem->variables, __DECONST(char *, origin), strlen(origin), var);
+
			if (var == NULL) {
+
				if (pkg_solve_add_universe_variable(j, problem, origin, &var) != EPKG_OK)
+
					goto err;
+
			}
+
			/* Add conflict rule from each of the alternative */
+
			LL_FOREACH(var, tvar) {
+
				/* Conflict rule: (!A | !Bx) */
+
				rule = pkg_solve_rule_new();
+
				if (rule == NULL)
+
					goto err;
+
				/* !A */
+
				it = pkg_solve_item_new(cur_var);
+
				if (it == NULL)
+
					goto err;
+

+
				it->inverse = true;
+
				LL_PREPEND(rule->items, it);
+
				/* !Bx */
+
				it = pkg_solve_item_new(tvar);
+
				if (it == NULL)
+
					goto err;
+

+
				it->inverse = true;
+
				LL_PREPEND(rule->items, it);
+

+
				LL_PREPEND(problem->rules, rule);
+
			}
+
		}

-
		LL_PREPEND(problem->rules, rule);
+
		if (conflicting) {
+
			/*
+
			 * If this var chain contains mutually conflicting vars
+
			 * we need to register conflicts with all following
+
			 * vars
+
			 */
+
			var = cur_var->next;
+
			if (var != NULL) {
+
				LL_FOREACH(var, tvar) {
+
					/* Conflict rule: (!Ax | !Ay) */
+
					rule = pkg_solve_rule_new();
+
					if (rule == NULL)
+
						goto err;
+
					/* !Ax */
+
					it = pkg_solve_item_new(cur_var);
+
					if (it == NULL)
+
						goto err;
+

+
					it->inverse = true;
+
					LL_PREPEND(rule->items, it);
+
					/* !Ay */
+
					it = pkg_solve_item_new(tvar);
+
					if (it == NULL)
+
						goto err;
+

+
					it->inverse = true;
+
					LL_PREPEND(rule->items, it);
+

+
					LL_PREPEND(problem->rules, rule);
+
				}
+
			}
+
		}
	}

	return (EPKG_OK);
@@ -440,9 +519,9 @@ pkg_solve_jobs_to_sat(struct pkg_jobs *j)
	struct pkg_job_request *jreq, *jtmp;
	struct pkg_solve_rule *rule;
	struct pkg_solve_item *it;
-
	struct pkg *pkg, *ptmp;
-
	struct pkg_solve_variable *var;
-
	const char *origin;
+
	struct pkg_job_universe_item *un, *utmp, *ucur;
+
	struct pkg_solve_variable *var, *tvar;
+
	const char *origin, *digest;

	problem = calloc(1, sizeof(struct pkg_solve_problem));

@@ -461,7 +540,8 @@ pkg_solve_jobs_to_sat(struct pkg_jobs *j)
		if (var == NULL)
			goto err;

-
		HASH_ADD_KEYPTR(hh, problem->variables, var->origin, strlen(var->origin), var);
+
		HASH_ADD_KEYPTR(hd, problem->variables, var->digest, strlen(var->digest), var);
+
		HASH_ADD_KEYPTR(ho, problem->variables, var->origin, strlen(var->origin), var);
		it = pkg_solve_item_new(var);
		if (it == NULL)
			goto err;
@@ -483,7 +563,8 @@ pkg_solve_jobs_to_sat(struct pkg_jobs *j)
		if (var == NULL)
			goto err;

-
		HASH_ADD_KEYPTR(hh, problem->variables, var->origin, strlen(var->origin), var);
+
		HASH_ADD_KEYPTR(hd, problem->variables, var->digest, strlen(var->digest), var);
+
		HASH_ADD_KEYPTR(ho, problem->variables, var->origin, strlen(var->origin), var);
		it = pkg_solve_item_new(var);
		if (it == NULL)
			goto err;
@@ -499,21 +580,36 @@ pkg_solve_jobs_to_sat(struct pkg_jobs *j)
	}

	/* Parse universe */
-
	HASH_ITER(hh, j->universe, pkg, ptmp) {
+
	HASH_ITER(hh, j->universe, un, utmp) {
		rule = NULL;
		it = NULL;
		var = NULL;

-
		pkg_get(pkg, PKG_ORIGIN, &origin);
-
		HASH_FIND_STR(problem->variables, origin, var);
-
		if (var == NULL) {
-
			/* Add new variable */
-
			var = pkg_solve_variable_new(pkg);
-
			if (var == NULL)
-
				goto err;
-
			HASH_ADD_KEYPTR(hh, problem->variables, var->origin, strlen(var->origin), var);
+
		/* Add corresponding variables */
+
		LL_FOREACH(un, ucur) {
+
			pkg_get(ucur->pkg, PKG_ORIGIN, &origin, PKG_DIGEST, &digest);
+
			HASH_FIND(hd, problem->variables, digest, strlen(digest), var);
+
			if (var == NULL) {
+
				/* Add new variable */
+
				var = pkg_solve_variable_new(ucur->pkg);
+
				if (var == NULL)
+
					goto err;
+
				HASH_ADD_KEYPTR(hd, problem->variables, var->digest, strlen(var->digest), var);
+

+
				/* Check origin */
+
				HASH_FIND(ho, problem->variables, origin, strlen(origin), tvar);
+
				if (tvar == NULL) {
+
					HASH_ADD_KEYPTR(ho, problem->variables, var->origin, strlen(var->origin), var);
+
				}
+
				else {
+
					/* Insert a variable to a chain */
+
					tvar->next = var;
+
				}
+
			}
		}
-
		if (pkg_solve_add_pkg_rule(j, problem, var) == EPKG_FATAL)
+
		HASH_FIND(ho, problem->variables, origin, strlen(origin), var);
+
		/* Now `var' contains a variables chain related to this origin */
+
		if (pkg_solve_add_pkg_rule(j, problem, var, true) == EPKG_FATAL)
			goto err;
	}

modified libpkg/private/pkg.h
@@ -199,8 +199,14 @@ struct pkg_job_request {
	UT_hash_handle hh;
};

+
struct pkg_job_universe_item {
+
	struct pkg *pkg;
+
	UT_hash_handle hh;
+
	struct pkg_job_universe_item *next;
+
};
+

struct pkg_jobs {
-
	struct pkg *universe;
+
	struct pkg_job_universe_item *universe;
	struct pkg	*jobs;
	struct pkg 	*bulk;
	struct pkg	*seen;