Radish alpha
H
rad:z3QDZAW2FAfuLvihrhiyDC9fAD8G9
HardenedBSD Package Manager
Radicle
Git
Introduce priorities for the solver.
Vsevolod Stakhov committed 12 years ago
commit c86e0befc072ac421793779ede86c800b07ddd4e
parent 9f9581b
7 files changed +234 -102
modified libpkg/pkg.h.in
@@ -1166,7 +1166,6 @@ void pkg_jobs_free(struct pkg_jobs *jobs);
 */
int pkg_jobs_add(struct pkg_jobs *j, match_t match, char **argv, int argc);
int pkg_jobs_solve(struct pkg_jobs *j);
-
int pkg_jobs_find(struct pkg_jobs *j, const char *origin, struct pkg **pkg);
int pkg_jobs_set_repository(struct pkg_jobs *j, const char *name);
void pkg_jobs_set_flags(struct pkg_jobs *j, pkg_flags f);
pkg_jobs_t pkg_jobs_type(struct pkg_jobs *j);
@@ -1178,11 +1177,11 @@ int pkg_jobs_count(struct pkg_jobs *jobs);

/**
 * Iterates over the packages in the jobs queue.
-
 * @param pkg Must be set to NULL for the first call.
-
 * @return An error code.
+
 * @param iter Must be set to NULL for the first call.
+
 * @return A next pkg or NULL.
 */
-
int pkg_jobs_add_iter(struct pkg_jobs *jobs, struct pkg **pkg);
-
int pkg_jobs_delete_iter(struct pkg_jobs *jobs, struct pkg **pkg);
+
struct pkg * pkg_jobs_add_iter(struct pkg_jobs *jobs, void **iter);
+
struct pkg * pkg_jobs_delete_iter(struct pkg_jobs *jobs, void **iter);

/**
 * Apply the jobs in the queue (fetch and install).
modified libpkg/pkg_cudf.c
@@ -277,6 +277,21 @@ cudf_strdup(const char *in)
	return (out);
}

+
static void
+
pkg_jobs_cudf_insert_res_job (struct pkg_solved **target, struct pkg_job_universe_item *it)
+
{
+
	struct pkg_solved *res;
+

+
	res = calloc(1, sizeof(struct pkg_solved));
+
	if (res == NULL) {
+
		pkg_emit_errno("calloc", "pkg_solved");
+
		return;
+
	}
+
	res->priority = it->priority;
+
	res->pkg = it->pkg;
+
	DL_APPEND(*target, res);
+
}
+

struct pkg_cudf_entry {
	char *origin;
	bool was_installed;
@@ -318,10 +333,14 @@ pkg_jobs_cudf_add_package(struct pkg_jobs *j, struct pkg_cudf_entry *entry)

	pkg_get(selected->pkg, PKG_ORIGIN, &origin);
	/* XXX: handle forced versions here including reinstall */
-
	if (entry->installed && selected->pkg->type != PKG_INSTALLED)
-
		HASH_ADD_KEYPTR(hh, j->jobs_add, origin, strlen(origin), selected->pkg);
-
	else if (!entry->installed && selected->pkg->type == PKG_INSTALLED)
-
		HASH_ADD_KEYPTR(hh, j->jobs_delete, origin, strlen(origin), selected->pkg);
+
	if (entry->installed && selected->pkg->type != PKG_INSTALLED) {
+
		pkg_jobs_cudf_insert_res_job (&j->jobs_add, selected);
+
		j->count ++;
+
	}
+
	else if (!entry->installed && selected->pkg->type == PKG_INSTALLED) {
+
		pkg_jobs_cudf_insert_res_job (&j->jobs_delete, selected);
+
		j->count ++;
+
	}

	return (EPKG_OK);
}
modified libpkg/pkg_jobs.c
@@ -45,7 +45,7 @@
#include "private/pkg.h"
#include "private/pkgdb.h"

-
static int find_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, int priority);
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);
@@ -97,7 +97,6 @@ pkg_jobs_free(struct pkg_jobs *j)
	struct pkg_job_request *req, *tmp;
	struct pkg_job_universe_item *un, *untmp, *cur;

-

	if (j == NULL)
		return;

@@ -122,6 +121,8 @@ pkg_jobs_free(struct pkg_jobs *j)
	}
	HASH_FREE(j->seen, pkg_job_seen, free);
	LL_FREE(j->patterns, job_pattern, free);
+
	LL_FREE(j->jobs_add, pkg_solved, free);
+
	LL_FREE(j->jobs_delete, pkg_solved, free);

	free(j);
}
@@ -155,24 +156,64 @@ pkg_jobs_add(struct pkg_jobs *j, match_t match, char **argv, int argc)
	return (EPKG_OK);
}

-
int
-
pkg_jobs_add_iter(struct pkg_jobs *jobs, struct pkg **pkg)
+
struct pkg *
+
pkg_jobs_add_iter(struct pkg_jobs *jobs, void **iter)
{
-
	assert(pkg != NULL);
+
	struct pkg_solved *s;
+
	struct pkg *res;
+
	assert(iter != NULL);
+

+
	if (jobs->jobs_add == NULL) {
+
		return NULL;
+
	}

-
	HASH_NEXT(jobs->jobs_add, (*pkg));
+
	if (*iter == NULL) {
+
		s = jobs->jobs_add;
+
	}
+
	else if (*iter == jobs->jobs_add) {
+
		return (NULL);
+
	}
+
	else {
+
		s = *iter;
+
	}
+

+
	res = s->pkg;
+

+
	*iter = s->next ? s->next : jobs->jobs_add;
+

+
	return (res);
}

-
int
-
pkg_jobs_delete_iter(struct pkg_jobs *jobs, struct pkg **pkg)
+
struct pkg *
+
pkg_jobs_delete_iter(struct pkg_jobs *jobs, void **iter)
{
-
	assert(pkg != NULL);
+
	struct pkg_solved *s;
+
	struct pkg *res;
+
	assert(iter != NULL);
+

+
	if (jobs->jobs_delete == NULL) {
+
		return NULL;
+
	}

-
	HASH_NEXT(jobs->jobs_delete, (*pkg));
+
	if (*iter == NULL) {
+
		s = jobs->jobs_delete;
+
	}
+
	else if (*iter == jobs->jobs_delete) {
+
		return (NULL);
+
	}
+
	else {
+
		s = *iter;
+
	}
+

+
	res = s->pkg;
+

+
	*iter = s->next ? s->next : jobs->jobs_delete;
+

+
	return (res);
}

static void
-
pkg_jobs_add_req(struct pkg_jobs *j, const char *origin, struct pkg *pkg, bool add)
+
pkg_jobs_add_req(struct pkg_jobs *j, const char *origin, struct pkg *pkg, bool add, int priority)
{
	struct pkg_job_request *req;

@@ -182,6 +223,8 @@ pkg_jobs_add_req(struct pkg_jobs *j, const char *origin, struct pkg *pkg, bool a
		return;
	}
	req->pkg = pkg;
+
	req->priority = priority;
+

	if (add)
		HASH_ADD_KEYPTR(hh, j->request_add, origin, strlen(origin), req);
	else
@@ -193,7 +236,7 @@ pkg_jobs_add_req(struct pkg_jobs *j, const char *origin, struct pkg *pkg, bool a
 * @return item or NULL
 */
static int
-
pkg_jobs_handle_pkg_universe(struct pkg_jobs *j, struct pkg *pkg)
+
pkg_jobs_handle_pkg_universe(struct pkg_jobs *j, struct pkg *pkg, int priority)
{
	struct pkg_job_universe_item *item, *cur, *tmp = NULL;
	const char *origin, *digest, *digest_cur, *version, *name;
@@ -237,6 +280,7 @@ pkg_jobs_handle_pkg_universe(struct pkg_jobs *j, struct pkg *pkg)
			return (EPKG_FATAL);
		}
		item->pkg = pkg;
+
		item->priority = priority;
		HASH_ADD_KEYPTR(hh, j->universe, __DECONST(char *, origin), strlen(origin), item);
	}
	else {
@@ -244,7 +288,12 @@ pkg_jobs_handle_pkg_universe(struct pkg_jobs *j, struct pkg *pkg)
		LL_FOREACH(item, cur) {
			pkg_get(cur->pkg, PKG_DIGEST, &digest_cur);
			if (strcmp (digest, digest_cur) == 0) {
-
				/* Free new package */
+
				/* Adjust priority */
+
				if (priority > cur->priority) {
+
					pkg_debug(2, "universe: update priority of %s: %d -> %d",
+
								origin, cur->priority, priority);
+
					cur->priority = priority;
+
				}
				pkg_free(pkg);
				return (EPKG_OK);
			}
@@ -258,9 +307,11 @@ pkg_jobs_handle_pkg_universe(struct pkg_jobs *j, struct pkg *pkg)
		return (EPKG_FATAL);
	}

-
	pkg_debug(2, "universe: add new %s pkg: %s, (%s-%s)",
-
			(pkg->type == PKG_INSTALLED ? "local" : "remote"), origin, name, version);
+
	pkg_debug(2, "universe: add new %s pkg: %s(%d), (%s-%s)",
+
			(pkg->type == PKG_INSTALLED ? "local" : "remote"), origin,
+
			priority, name, version);
	item->pkg = pkg;
+
	item->priority = priority;
	if (tmp != NULL)
		tmp->next = item;

@@ -268,7 +319,7 @@ pkg_jobs_handle_pkg_universe(struct pkg_jobs *j, struct pkg *pkg)
}

static int
-
pkg_jobs_add_universe(struct pkg_jobs *j, struct pkg *pkg, bool recursive)
+
pkg_jobs_add_universe(struct pkg_jobs *j, struct pkg *pkg, int priority, bool recursive)
{
	struct pkg_dep *d = NULL;
	struct pkg_conflict *c = NULL;
@@ -277,7 +328,7 @@ pkg_jobs_add_universe(struct pkg_jobs *j, struct pkg *pkg, bool recursive)
	struct pkg_job_universe_item *unit;

	/* Add the requested package itself */
-
	ret = pkg_jobs_handle_pkg_universe(j, pkg);
+
	ret = pkg_jobs_handle_pkg_universe(j, pkg, priority);

	if (ret == EPKG_END)
		return (EPKG_OK);
@@ -317,9 +368,9 @@ pkg_jobs_add_universe(struct pkg_jobs *j, struct pkg *pkg, bool recursive)
				}
			}
		}
-
		if (pkg_jobs_add_universe(j, npkg, recursive) != EPKG_OK)
+
		if (pkg_jobs_add_universe(j, npkg, priority + 1, recursive) != EPKG_OK)
			return (EPKG_FATAL);
-
		if (rpkg != NULL && pkg_jobs_add_universe(j, rpkg, recursive) != EPKG_OK)
+
		if (rpkg != NULL && pkg_jobs_add_universe(j, priority + 1, rpkg, recursive) != EPKG_OK)
			return (EPKG_FATAL);
	}

@@ -344,7 +395,7 @@ pkg_jobs_add_universe(struct pkg_jobs *j, struct pkg *pkg, bool recursive)
				return (EPKG_FATAL);
			}
		}
-
		if (pkg_jobs_add_universe(j, npkg, recursive) != EPKG_OK)
+
		if (pkg_jobs_add_universe(j, npkg, priority - 1, recursive) != EPKG_OK)
			return (EPKG_FATAL);
	}

@@ -357,14 +408,14 @@ pkg_jobs_add_universe(struct pkg_jobs *j, struct pkg *pkg, bool recursive)

		/* Check both local and remote conflicts */
		npkg = get_remote_pkg(j, pkg_conflict_origin(c), 0);
-
		if (pkg_jobs_add_universe(j, npkg, recursive) != EPKG_OK)
+
		if (pkg_jobs_add_universe(j, npkg, priority, recursive) != EPKG_OK)
			return (EPKG_FATAL);
		npkg = get_local_pkg(j, pkg_conflict_origin(c), 0);
		if (npkg == NULL) {
			continue;
		}

-
		if (pkg_jobs_add_universe(j, npkg, recursive) != EPKG_OK)
+
		if (pkg_jobs_add_universe(j, npkg, priority, recursive) != EPKG_OK)
			return (EPKG_FATAL);
	}

@@ -485,8 +536,9 @@ jobs_solve_deinstall(struct pkg_jobs *j)
			else {
				pkg_get(pkg, PKG_ORIGIN, &origin, PKG_FLATSIZE, &oldsize);
				pkg_set(pkg, PKG_OLD_FLATSIZE, oldsize, PKG_FLATSIZE, (int64_t)0);
-
				pkg_jobs_add_req(j, origin, pkg, false);
-
				pkg_jobs_add_universe(j, pkg, recursive);
+
				pkg_jobs_add_req(j, origin, pkg, false, 0);
+
				/* TODO: use repository priority here */
+
				pkg_jobs_add_universe(j, pkg, 0, recursive);
			}
			pkg = NULL;
		}
@@ -515,8 +567,9 @@ jobs_solve_autoremove(struct pkg_jobs *j)
		}
		else {
			pkg_get(pkg, PKG_ORIGIN, &origin);
-
			pkg_jobs_add_req(j, origin, pkg, false);
-
			pkg_jobs_add_universe(j, pkg, false);
+
			pkg_jobs_add_req(j, origin, pkg, false, 0);
+
			/* TODO: use repository priority here */
+
			pkg_jobs_add_universe(j, pkg, 0, false);
		}
		pkg = NULL;
	}
@@ -551,7 +604,7 @@ jobs_solve_upgrade(struct pkg_jobs *j)

		pkg_get(pkg, PKG_ORIGIN, &origin);
		/* Do not test we ignore what doesn't exists remotely */
-
		find_remote_pkg(j, origin, MATCH_EXACT, false);
+
		find_remote_pkg(j, origin, MATCH_EXACT, false, 0);
		pkg = NULL;
	}
	pkgdb_it_free(it);
@@ -589,7 +642,8 @@ new_pkg_version(struct pkg_jobs *j)
		goto end;
	}

-
	if (find_remote_pkg(j, origin, MATCH_EXACT, false) == EPKG_OK) {
+
	/* Use maximum priority for pkg */
+
	if (find_remote_pkg(j, origin, MATCH_EXACT, false, INT_MAX) == EPKG_OK) {
		ret = true;
		goto end;
	}
@@ -601,7 +655,7 @@ end:
}

static int
-
find_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, int priority)
{
	struct pkg *p = NULL;
	struct pkg *p1;
@@ -668,8 +722,8 @@ find_remote_pkg(struct pkg_jobs *j, const char *pattern, match_t m, bool root)
		rc = EPKG_OK;
		p->direct = root;
		/* Add a package to request chain and populate universe */
-
		pkg_jobs_add_req(j, origin, p, true);
-
		rc = pkg_jobs_add_universe(j, p, true);
+
		pkg_jobs_add_req(j, origin, p, true, priority);
+
		rc = pkg_jobs_add_universe(j, p, priority, true);

		p = NULL;
	}
@@ -931,7 +985,8 @@ jobs_solve_install(struct pkg_jobs *j)
				}

				pkg_get(pkg, PKG_ORIGIN, &origin);
-
				if (find_remote_pkg(j, origin, MATCH_EXACT, true) == EPKG_FATAL)
+
				/* TODO: use repository priority here */
+
				if (find_remote_pkg(j, origin, MATCH_EXACT, true, 0) == EPKG_FATAL)
					pkg_emit_error("No packages matching '%s', has been found in the repositories", origin);
			}
			pkgdb_it_free(it);
@@ -948,8 +1003,8 @@ jobs_solve_install(struct pkg_jobs *j)
				}
			}
			pkgdb_it_free(it);
-

-
			if (find_remote_pkg(j, jp->pattern, jp->match, true) == EPKG_FATAL)
+
			/* TODO: use repository priority here */
+
			if (find_remote_pkg(j, jp->pattern, jp->match, true, 0) == EPKG_FATAL)
				pkg_emit_error("No packages matching '%s' has been found in the repositories", jp->pattern);
		}
	}
@@ -992,13 +1047,14 @@ jobs_solve_fetch(struct pkg_jobs *j)

			pkg_get(pkg, PKG_ORIGIN, &origin);
			/* Do not test we ignore what doesn't exists remotely */
-
			find_remote_pkg(j, origin, MATCH_EXACT, false);
+
			find_remote_pkg(j, origin, MATCH_EXACT, false, 0);
			pkg = NULL;
		}
		pkgdb_it_free(it);
	} else {
		LL_FOREACH(j->patterns, jp) {
-
			if (find_remote_pkg(j, jp->pattern, jp->match, true) == EPKG_FATAL)
+
			/* TODO: use repository priority here */
+
			if (find_remote_pkg(j, jp->pattern, jp->match, true, 0) == EPKG_FATAL)
				pkg_emit_error("No packages matching '%s' has been found in the repositories", jp->pattern);
		}
	}
@@ -1008,6 +1064,18 @@ jobs_solve_fetch(struct pkg_jobs *j)
	return (EPKG_OK);
}

+
static int
+
jobs_sort_priority_dec(struct pkg_solved *r1, struct pkg_solved *r2)
+
{
+
	return (r1->priority - r2->priority);
+
}
+

+
static int
+
jobs_sort_priority_inc(struct pkg_solved *r1, struct pkg_solved *r2)
+
{
+
	return (r2->priority - r1->priority);
+
}
+

int
pkg_jobs_solve(struct pkg_jobs *j)
{
@@ -1098,25 +1166,14 @@ pkg_jobs_solve(struct pkg_jobs *j)
			}
		}
	}
-
	return (ret);
-
}

-
int
-
pkg_jobs_find(struct pkg_jobs *j, const char *origin, struct pkg **p)
-
{
-
	struct pkg *pkg;
-

-
	HASH_FIND_STR(j->jobs_add, __DECONST(char *, origin), pkg);
-
	if (pkg == NULL) {
-
		HASH_FIND_STR(j->jobs_add, __DECONST(char *, origin), pkg);
-
		if (pkg == NULL)
-
			return (EPKG_FATAL);
+
	/* Resort priorities */
+
	if (j->solved) {
+
		DL_SORT(j->jobs_add, jobs_sort_priority_inc);
+
		DL_SORT(j->jobs_delete, jobs_sort_priority_dec);
	}

-
	if (p != NULL)
-
		*p = pkg;
-

-
	return (EPKG_OK);
+
	return (ret);
}

int
@@ -1124,12 +1181,14 @@ pkg_jobs_count(struct pkg_jobs *j)
{
	assert(j != NULL);

-
	return (HASH_COUNT(j->jobs_add) + HASH_COUNT(j->jobs_delete));
+
	return (j->count);
}

pkg_jobs_t
pkg_jobs_type(struct pkg_jobs *j)
{
+
	assert(j != NULL);
+

	return (j->type);
}

@@ -1159,7 +1218,8 @@ pkg_jobs_keep_files_to_del(struct pkg *p1, struct pkg *p2)
static int
pkg_jobs_install(struct pkg_jobs *j)
{
-
	struct pkg *p = NULL, *ptmp;
+
	struct pkg *p = NULL;
+
	struct pkg_solved *ps;
	struct pkg *pkg = NULL;
	struct pkg *newpkg = NULL;
	struct pkg *pkg_temp = NULL;
@@ -1191,7 +1251,16 @@ pkg_jobs_install(struct pkg_jobs *j)
	/* Install */
	pkgdb_transaction_begin(j->db->sqlite, "upgrade");

-
	HASH_ITER(hh, j->jobs_add, p, ptmp) {
+
	/* Delete conflicts initially */
+
	DL_FOREACH(j->jobs_delete, ps) {
+
		p = ps->pkg;
+
		retcode = pkg_delete(p, j->db, flags);
+

+
		if (retcode != EPKG_OK)
+
			return (retcode);
+
	}
+
	DL_FOREACH(j->jobs_add, ps) {
+
		p = ps->pkg;
		const char *pkgorigin, *oldversion, *origin;
		struct pkg_note *an;
		bool automatic;
@@ -1331,7 +1400,9 @@ pkg_jobs_install(struct pkg_jobs *j)
static int
pkg_jobs_deinstall(struct pkg_jobs *j)
{
-
	struct pkg *p = NULL, *ptmp;
+
	struct pkg *p = NULL;
+
	struct pkg_solved *ps;
+
	const char *name;
	int retcode;
	int flags = 0;

@@ -1344,8 +1415,14 @@ pkg_jobs_deinstall(struct pkg_jobs *j)
	if ((j->flags & PKG_FLAG_NOSCRIPT) == PKG_FLAG_NOSCRIPT)
		flags |= PKG_DELETE_NOSCRIPT;

-
	HASH_ITER(hh, j->jobs_delete, p, ptmp) {
-

+
	DL_FOREACH(j->jobs_delete, ps) {
+
		p = ps->pkg;
+
		pkg_get(p, PKG_NAME, &name);
+
		if ((strcmp(name, "pkg") == 0 ||
+
			 strcmp(name, "pkg-devel") == 0) && flags != PKG_DELETE_FORCE) {
+
			pkg_emit_error("Cannot delete pkg itself without force flag");
+
			continue;
+
		}
		retcode = pkg_delete(p, j->db, flags);

		if (retcode != EPKG_OK)
@@ -1404,7 +1481,8 @@ pkg_jobs_apply(struct pkg_jobs *j)
static int
pkg_jobs_fetch(struct pkg_jobs *j)
{
-
	struct pkg *p = NULL, *ptmp;
+
	struct pkg *p = NULL;
+
	struct pkg_solved *ps;
	struct pkg *pkg = NULL;
	struct statfs fs;
	struct stat st;
@@ -1420,7 +1498,8 @@ pkg_jobs_fetch(struct pkg_jobs *j)
		return (EPKG_FATAL);

	/* check for available size to fetch */
-
	HASH_ITER(hh, j->jobs_add, p, ptmp) {
+
	DL_FOREACH(j->jobs_add, ps) {
+
		p = ps->pkg;
		int64_t pkgsize;
		pkg_get(p, PKG_PKGSIZE, &pkgsize, PKG_REPOPATH, &repopath);
		snprintf(cachedpath, sizeof(cachedpath), "%s/%s", cachedir, repopath);
@@ -1455,18 +1534,18 @@ pkg_jobs_fetch(struct pkg_jobs *j)
		return (EPKG_OK); /* don't download anything */

	/* Fetch */
-
	p = NULL;
-
	HASH_ITER(hh, j->jobs_add, p, ptmp) {
+
	DL_FOREACH(j->jobs_add, ps) {
+
		p = ps->pkg;
		if (pkg_repo_fetch(p) != EPKG_OK)
			return (EPKG_FATAL);
	}

-
	p = NULL;
	/* integrity checking */
	pkg_emit_integritycheck_begin();

	pkg_manifest_keys_new(&keys);
-
	HASH_ITER(hh, j->jobs_add, p, ptmp) {
+
	DL_FOREACH(j->jobs_add, ps) {
+
		p = ps->pkg;
		const char *pkgrepopath;

		pkg_get(p, PKG_REPOPATH, &pkgrepopath);
modified libpkg/pkg_solve.c
@@ -45,6 +45,7 @@
struct pkg_solve_variable {
	struct pkg *pkg;
	bool to_install;
+
	int priority;
	const char *digest;
	const char *origin;
	bool resolved;
@@ -140,7 +141,8 @@ pkg_solve_propagate_units(struct pkg_solve_rule *rules)
					unresolved->var->resolved = true;
					unresolved->var->to_install = !unresolved->inverse;
					solved_vars ++;
-
					pkg_debug(2, "propagate %s to %d", unresolved->var->origin, unresolved->var->to_install);
+
					pkg_debug(2, "propagate %s(%d) to %d",
+
							unresolved->var->origin, unresolved->var->priority, unresolved->var->to_install);
				}
				/* Now check for a conflict */
				ret = false;
@@ -227,14 +229,16 @@ pkg_solve_propagate_default(struct pkg_solve_rule *rules)
				if (it->var->pkg->type == PKG_INSTALLED) {
					it->var->to_install = true;
					if (pkg_solve_check_conflicts(rules)) {
-
						pkg_debug(2, "assume %s to %d", it->var->origin, it->var->to_install);
+
						pkg_debug(2, "assume %s(%d) to %d",
+
								it->var->origin, it->var->priority, it->var->to_install);
						it->var->resolved = true;
					}
				}
				else {
					it->var->to_install = false;
					if (pkg_solve_check_conflicts(rules)) {
-
						pkg_debug(2, "assume %s to %d", it->var->origin, it->var->to_install);
+
						pkg_debug(2, "assume %s(%d) to %d",
+
								it->var->origin, it->var->priority, it->var->to_install);
						it->var->resolved = true;
					}
				}
@@ -311,7 +315,7 @@ pkg_solve_rule_new(void)
}

static struct pkg_solve_variable *
-
pkg_solve_variable_new(struct pkg *pkg)
+
pkg_solve_variable_new(struct pkg *pkg, int priority)
{
	struct pkg_solve_variable *result;
	const char *digest, *origin;
@@ -324,6 +328,7 @@ pkg_solve_variable_new(struct pkg *pkg)
	}

	result->pkg = pkg;
+
	result->priority = priority;
	pkg_get(pkg, PKG_ORIGIN, &origin, PKG_DIGEST, &digest);
	/* XXX: Is it safe to save a ptr here ? */
	result->digest = digest;
@@ -372,7 +377,7 @@ pkg_solve_add_universe_variable(struct pkg_jobs *j,
		return (EPKG_FATAL);
	}
	/* Need to add a variable */
-
	nvar = pkg_solve_variable_new(unit->pkg);
+
	nvar = pkg_solve_variable_new(unit->pkg, unit->priority);
	if (nvar == NULL)
		return (EPKG_FATAL);
	HASH_ADD_KEYPTR(ho, problem->variables_by_origin, nvar->origin, strlen(nvar->origin), nvar);
@@ -381,7 +386,7 @@ pkg_solve_add_universe_variable(struct pkg_jobs *j,
	tvar = nvar;
	while (unit != NULL) {
		/* Add all alternatives as independent variables */
-
		tvar->next = pkg_solve_variable_new(unit->pkg);
+
		tvar->next = pkg_solve_variable_new(unit->pkg, unit->priority);
		tvar = tvar->next;
		if (tvar == NULL)
			return (EPKG_FATAL);
@@ -556,7 +561,7 @@ pkg_solve_jobs_to_sat(struct pkg_jobs *j)
		it = NULL;
		var = NULL;

-
		var = pkg_solve_variable_new(jreq->pkg);
+
		var = pkg_solve_variable_new(jreq->pkg, jreq->priority);
		if (var == NULL)
			goto err;

@@ -580,7 +585,7 @@ pkg_solve_jobs_to_sat(struct pkg_jobs *j)
		it = NULL;
		var = NULL;

-
		var = pkg_solve_variable_new(jreq->pkg);
+
		var = pkg_solve_variable_new(jreq->pkg, jreq->priority);
		if (var == NULL)
			goto err;

@@ -613,7 +618,7 @@ pkg_solve_jobs_to_sat(struct pkg_jobs *j)
			HASH_FIND(hd, problem->variables_by_digest, digest, strlen(digest), var);
			if (var == NULL) {
				/* Add new variable */
-
				var = pkg_solve_variable_new(ucur->pkg);
+
				var = pkg_solve_variable_new(ucur->pkg, ucur->priority);
				if (var == NULL)
					goto err;
				HASH_ADD_KEYPTR(hd, problem->variables_by_digest,
@@ -689,6 +694,21 @@ pkg_solve_dimacs_export(struct pkg_solve_problem *problem, FILE *f)
	return (EPKG_OK);
}

+
static void
+
pkg_solve_insert_res_job (struct pkg_solved **target, struct pkg_solve_variable *var)
+
{
+
	struct pkg_solved *res;
+

+
	res = calloc(1, sizeof(struct pkg_solved));
+
	if (res == NULL) {
+
		pkg_emit_errno("calloc", "pkg_solved");
+
		return;
+
	}
+
	res->priority = var->priority;
+
	res->pkg = var->pkg;
+
	DL_APPEND(*target, res);
+
}
+

int
pkg_solve_sat_to_jobs(struct pkg_solve_problem *problem, struct pkg_jobs *j)
{
@@ -700,10 +720,14 @@ pkg_solve_sat_to_jobs(struct pkg_solve_problem *problem, struct pkg_jobs *j)
			return (EPKG_FATAL);

		pkg_get(var->pkg, PKG_ORIGIN, &origin);
-
		if (var->to_install && var->pkg->type != PKG_INSTALLED)
-
			HASH_ADD_KEYPTR(hh, j->jobs_add, origin, strlen(origin), var->pkg);
-
		else if (!var->to_install && var->pkg->type == PKG_INSTALLED)
-
			HASH_ADD_KEYPTR(hh, j->jobs_delete, origin, strlen(origin), var->pkg);
+
		if (var->to_install && var->pkg->type != PKG_INSTALLED) {
+
			pkg_solve_insert_res_job(&j->jobs_add, var);
+
			j->count ++;
+
		}
+
		else if (!var->to_install && var->pkg->type == PKG_INSTALLED) {
+
			pkg_solve_insert_res_job(&j->jobs_delete, var);
+
			j->count ++;
+
		}
	}

	return (EPKG_OK);
modified libpkg/private/pkg.h
@@ -198,10 +198,17 @@ struct pkg_option {

struct pkg_job_request {
	struct pkg *pkg;
+
	int priority;
	bool skip;
	UT_hash_handle hh;
};

+
struct pkg_solved {
+
	struct pkg *pkg;
+
	int priority;
+
	struct pkg_solved *prev, *next;
+
};
+

struct pkg_job_seen {
	struct pkg *pkg;
	const char *digest;
@@ -211,6 +218,7 @@ struct pkg_job_seen {
struct pkg_job_universe_item {
	struct pkg *pkg;
	UT_hash_handle hh;
+
	int priority;
	struct pkg_job_universe_item *next;
};

@@ -218,13 +226,14 @@ struct pkg_jobs {
	struct pkg_job_universe_item *universe;
	struct pkg_job_request	*request_add;
	struct pkg_job_request	*request_delete;
-
	struct pkg *jobs_add;
-
	struct pkg *jobs_delete;
+
	struct pkg_solved *jobs_add;
+
	struct pkg_solved *jobs_delete;
	struct pkg_job_seen *seen;
	struct pkgdb	*db;
	pkg_jobs_t	 type;
	pkg_flags	 flags;
	bool		 solved;
+
	int count;
	const char *	 reponame;
	struct job_pattern *patterns;
};
modified pkg/delete.c
@@ -152,14 +152,6 @@ exec_delete(int argc, char **argv)
	if (pkg_jobs_solve(jobs) != EPKG_OK)
		goto cleanup;

-
	if (((pkg_jobs_find(jobs, "ports-mgmt/pkg", NULL) == EPKG_OK) ||
-
	    (pkg_jobs_find(jobs, "ports-mgmt/pkg-devel", NULL) == EPKG_OK))
-
	     && !force) {
-
		warnx("Deleting 'ports-mgmt/pkg' is really dangerous. "
-
		"If that is really required, -f must be specified");
-
		goto cleanup;
-
	}
-

	/* check if we have something to deinstall */
	if ((nbactions = pkg_jobs_count(jobs)) == 0) {
		if (argc == 0) {
modified pkg/utils.c
@@ -647,10 +647,11 @@ print_jobs_summary_pkg(struct pkg *pkg, pkg_jobs_t type, int64_t *oldsize,
void
print_jobs_summary(struct pkg_jobs *jobs, const char *msg, ...)
{
-
	struct pkg *pkg = NULL;
+
	struct pkg *pkg;
+
	void *iter = NULL;
	char size[7];
	va_list ap;
-
	pkg_jobs_t type;
+
	pkg_jobs_t type, inv_type;
	int64_t dlsize, oldsize, newsize;

	dlsize = oldsize = newsize = 0;
@@ -660,15 +661,24 @@ print_jobs_summary(struct pkg_jobs *jobs, const char *msg, ...)
	vprintf(msg, ap);
	va_end(ap);

-
	while (pkg_jobs_add_iter(jobs, &pkg) == EPKG_OK) {
-
		print_jobs_summary_pkg(pkg, type, &oldsize, &newsize, &dlsize);
+
	switch (type) {
+
	case PKG_JOBS_INSTALL:
+
	case PKG_JOBS_UPGRADE:
+
		inv_type = PKG_JOBS_DEINSTALL;
+
		break;
+
	default:
+
		inv_type = PKG_JOBS_INSTALL;
+
		break;
	}

-
	pkg = NULL;
-
	while (pkg_jobs_delete_iter(jobs, &pkg) == EPKG_OK) {
+
	while ((pkg = pkg_jobs_add_iter(jobs, &iter))) {
		print_jobs_summary_pkg(pkg, type, &oldsize, &newsize, &dlsize);
	}

+
	iter = NULL;
+
	while ((pkg = pkg_jobs_delete_iter(jobs, &iter))) {
+
		print_jobs_summary_pkg(pkg, inv_type, &oldsize, &newsize, &dlsize);
+
	}

	if (oldsize > newsize) {
		humanize_number(size, sizeof(size), oldsize - newsize, "B", HN_AUTOSCALE, 0);