Radish alpha
H
rad:z3QDZAW2FAfuLvihrhiyDC9fAD8G9
HardenedBSD Package Manager
Radicle
Git
Merge pull request #56 from dnaeon/multi-repos
Baptiste committed 14 years ago
commit e74426a1f64e0939a1dfd403fc5d38a291fba219
parent adb0316
8 files changed +471 -118
modified libpkg/pkg.c
@@ -54,6 +54,7 @@ pkg_new(struct pkg **pkg, pkg_t type)
	STAILQ_INIT(&(*pkg)->conflicts);
	STAILQ_INIT(&(*pkg)->scripts);
	STAILQ_INIT(&(*pkg)->options);
+
	STAILQ_INIT(&(*pkg)->repos);

	(*pkg)->automatic = false;
	(*pkg)->type = type;
@@ -84,6 +85,7 @@ pkg_reset(struct pkg *pkg, pkg_t type)
	pkg_freeconflicts(pkg);
	pkg_freescripts(pkg);
	pkg_freeoptions(pkg);
+
	pkg_repos_free_in_pkg(pkg);

	pkg->type = type;
}
@@ -105,6 +107,7 @@ pkg_free(struct pkg *pkg)
	pkg_freeconflicts(pkg);
	pkg_freescripts(pkg);
	pkg_freeoptions(pkg);
+
	pkg_repos_free_in_pkg(pkg);

	free(pkg);
}
@@ -188,6 +191,8 @@ pkg_flatsize(struct pkg *pkg)
int
pkg_setautomatic(struct pkg *pkg)
{
+
	assert(pkg != NULL);
+

	pkg->automatic = true;

	return (EPKG_OK);
modified libpkg/pkg.h
@@ -18,6 +18,7 @@ struct pkgdb;
struct pkgdb_it;

struct pkg_jobs;
+
struct pkg_jobs_entry;

struct pkg_repos;
struct pkg_repos_entry;
@@ -535,35 +536,58 @@ int pkgdb_compact(struct pkgdb *db);
int pkg_add(struct pkgdb *db, const char *path);

/**
-
 * Allocate a new pkg_jobs.
+
 * Create a new jobs object
+
 * @return EPKG_OK on success, EPKG_FATAL on error
+
 */
+
int pkg_jobs_new(struct pkg_jobs **jobs);
+

+
/**
+
 * Allocate a new pkg_jobs_entry object.
 * @param db A pkgdb open with PKGDB_REMOTE.
 * @return An error code.
 */
-
int pkg_jobs_new(struct pkg_jobs **jobs, pkg_jobs_t type, struct pkgdb *db);
+
int pkg_jobs_new_entry(struct pkg_jobs *jobs, struct pkg_jobs_entry **je, pkg_jobs_t type, struct pkgdb *db);

/**
-
 * Free a pkg_jobs
+
 * Free a pkg_jobs object
 */
void pkg_jobs_free(struct pkg_jobs *jobs);

/**
-
 * Add a pkg to the jobs queue.
+
 * Add a pkg to the jobs entry queue.
 * @return An error code.
 */
-
int pkg_jobs_add(struct pkg_jobs *jobs, struct pkg *pkg);
+
int pkg_jobs_add(struct pkg_jobs_entry *je, struct pkg *pkg);
+

+
/**
+
 * Iterates over the jobs entry objects
+
 * @param je Returns the next entry in a jobs object.
+
 * Must be set to NULL for the first call.
+
 * @return EPKG_OK on success, EPKG_END if end of tail is reached.
+
 */
+
int pkg_jobs(struct pkg_jobs *jobs, struct pkg_jobs_entry **je);

/**
 * Iterates over the packages in the jobs queue.
 * @param pkg Must be set to NULL for the first call.
 * @return An error code.
 */
-
int pkg_jobs(struct pkg_jobs *jobs, struct pkg **pkg);
+
int pkg_jobs_entry(struct pkg_jobs_entry *je, struct pkg **pkg);

/**
-
 * Apply the jobs in the queue (fetch and install).
+
 * Apply the jobs in the queue (fetch/install/deinstall).
 * @return An error code.
 */
-
int pkg_jobs_apply(struct pkg_jobs *jobs, int force);
+
int pkg_jobs_apply(struct pkg_jobs_entry *je, int force);
+

+
/**
+
 * Checks if a given job is already added in another jobs entry
+
 * @param jobs A valid jobs object as received from pkg_jobs_new()
+
 * @param pkg A package that will be checked if it exists already as a job
+
 * @param res A pkg where to store the result if a package is found to exist
+
 * @return EPKG_OK if the is not added yet and EPKG_FATAL otherwise
+
 */
+
int pkg_jobs_exists(struct pkg_jobs *jobs, struct pkg *pkg, struct pkg **res);

/**
 * Archive formats options.
@@ -613,6 +637,14 @@ int pkg_repos_load(struct pkg_repos *repos);
int pkg_repos_add(struct pkg_repos *repos, struct pkg_repos_entry *re);

/**
+
 * Adds a repository entry to a package object
+
 * @param pkg A valid package object
+
 * @param re A valid repository entry object
+
 * @return EPKG_OK on success, EPKG_FATAL on error
+
 */
+
int pkg_repos_add_in_pkg(struct pkg *pkg, struct pkg_repos_entry *re);
+

+
/**
 * Get the next repository from the tail
 * @param repos A valid repository pointer as returned by pkg_repos_new()
 * @param re A pointer to a repository entry to save the result. Must be set to
@@ -622,6 +654,15 @@ int pkg_repos_add(struct pkg_repos *repos, struct pkg_repos_entry *re);
int pkg_repos_next(struct pkg_repos *repos, struct pkg_repos_entry **re);

/**
+
 * Get the next repository assigned to a package object
+
 * @param pkg A valid package object
+
 * @param re A pointer to a repository entry to save the result. Must be set to
+
 * NULL for the first repository entry
+
 * @return EPKG_OK on success, EPKG_END if end of repository is reached
+
 */
+
int pkg_repos_next_in_pkg(struct pkg *pkg, struct pkg_repos_entry **re);
+

+
/**
 * Returns the name associated with a repository entry object
 * @param re A valid repository entry object
 */
@@ -645,6 +686,11 @@ unsigned int pkg_repos_get_line(struct pkg_repos_entry *re);
void pkg_repos_free(struct pkg_repos *repos);

/**
+
 * Free the memory used by the repository objects in a package
+
 */
+
void pkg_repos_free_in_pkg(struct pkg *pkg);
+

+
/**
 * Get the value of a configuration key
 */
const char * pkg_config(const char *key);
modified libpkg/pkg_jobs.c
@@ -8,26 +8,59 @@
#include "pkg_private.h"

int
-
pkg_jobs_new(struct pkg_jobs **j, pkg_jobs_t t, struct pkgdb *db)
+
pkg_jobs_new(struct pkg_jobs **jm)
{
+
	if ((*jm = calloc(1, sizeof(struct pkg_jobs))) == NULL) {
+
		EMIT_ERRNO("calloc", "pkg_jobs_new");
+
		return (EPKG_FATAL);
+
	}
+

+
	STAILQ_INIT(&(*jm)->multi);
+

+
	return (EPKG_OK);
+
}
+

+
int
+
pkg_jobs_new_entry(struct pkg_jobs *jm, struct pkg_jobs_entry **je, pkg_jobs_t t, struct pkgdb *db)
+
{
+
	assert(jm != NULL);
	assert(db != NULL);
	assert(t != PKG_JOBS_INSTALL || db->type == PKGDB_REMOTE);

-
	if((*j = calloc(1, sizeof(struct pkg_jobs))) == NULL) {
-
		EMIT_ERRNO("calloc", "pkg_jobs");
+
	if((*je = calloc(1, sizeof(struct pkg_jobs_entry))) == NULL) {
+
		EMIT_ERRNO("calloc", "pkg_jobs_new_entry");
		return (EPKG_FATAL);
	}

-
	STAILQ_INIT(&(*j)->jobs);
-
	LIST_INIT(&(*j)->nodes);
-
	(*j)->db = db;
-
	(*j)->type = t;
+
	STAILQ_INIT(&(*je)->jobs);
+
	LIST_INIT(&(*je)->nodes);
+
	(*je)->db = db;
+
	(*je)->type = t;
+

+
	STAILQ_INSERT_TAIL(&jm->multi, *je, next);

	return (EPKG_OK);
}

void
-
pkg_jobs_free(struct pkg_jobs *j)
+
pkg_jobs_free(struct pkg_jobs *jm)
+
{
+
	struct pkg_jobs_entry *je;
+

+
	if (jm == NULL)
+
		return;
+

+
	while (!STAILQ_EMPTY(&jm->multi)) {
+
		je = STAILQ_FIRST(&jm->multi);
+
		STAILQ_REMOVE_HEAD(&jm->multi, next);
+
		pkg_jobs_free_entry(je);
+
	}
+

+
	free(jm);
+
}
+

+
void
+
pkg_jobs_free_entry(struct pkg_jobs_entry *j)
{
	struct pkg *p;

@@ -37,31 +70,49 @@ pkg_jobs_free(struct pkg_jobs *j)
	while (!STAILQ_EMPTY(&j->jobs)) {
		p = STAILQ_FIRST(&j->jobs);
		STAILQ_REMOVE_HEAD(&j->jobs, next);
+
		pkgdb_close(j->db);
		pkg_free(p);
	}
+

	free(j);
}

int
-
pkg_jobs_add(struct pkg_jobs *j, struct pkg *pkg)
+
pkg_jobs_add(struct pkg_jobs_entry *je, struct pkg *pkg)
{
-
	assert(j != NULL);
+
	assert(je != NULL);
	assert(pkg != NULL);

-
	STAILQ_INSERT_TAIL(&j->jobs, pkg, next);
+
	STAILQ_INSERT_TAIL(&je->jobs, pkg, next);

	return (EPKG_OK);
}

int
-
pkg_jobs(struct pkg_jobs *j, struct pkg **pkg)
+
pkg_jobs(struct pkg_jobs *jm, struct pkg_jobs_entry **je)
{
-
	assert(j != NULL);
+
	assert(jm != NULL);

-
	pkg_jobs_resolv(j);
+
	if (*je == NULL)
+
		*je = STAILQ_FIRST(&jm->multi);
+
	else
+
		*je = STAILQ_NEXT(*je, next);
+

+
	if (*je == NULL)
+
		return (EPKG_END);
+
	else
+
		return (EPKG_OK);
+
}
+

+
int
+
pkg_jobs_entry(struct pkg_jobs_entry *je, struct pkg **pkg)
+
{
+
	assert(je != NULL);
+

+
	pkg_jobs_resolv(je);

	if (*pkg == NULL)
-
		*pkg = STAILQ_FIRST(&j->jobs);
+
		*pkg = STAILQ_FIRST(&je->jobs);
	else
		*pkg = STAILQ_NEXT(*pkg, next);

@@ -71,15 +122,34 @@ pkg_jobs(struct pkg_jobs *j, struct pkg **pkg)
		return (EPKG_OK);
}

+
int
+
pkg_jobs_exists(struct pkg_jobs *jobs, struct pkg *pkg, struct pkg **res)
+
{
+
	struct pkg_jobs_entry *je = NULL;
+
	struct pkg *p = NULL;
+

+
	while (pkg_jobs(jobs, &je) == EPKG_OK) {
+
		p = NULL; /* starts with the first package job */
+
		while (pkg_jobs_entry(je, &p) == EPKG_OK) {
+
			if (strcmp(pkg_get(p, PKG_ORIGIN), pkg_get(pkg, PKG_ORIGIN)) == 0) {
+
				*res = p;
+
				return (EPKG_FATAL);
+
			}
+
		}
+
	}
+

+
	return (EPKG_OK);
+
}
+

static int
-
pkg_jobs_install(struct pkg_jobs *j)
+
pkg_jobs_install(struct pkg_jobs_entry *je)
{
	struct pkg *p = NULL;
	const char *cachedir;
	char path[MAXPATHLEN];

	/* Fetch */
-
	while (pkg_jobs(j, &p) == EPKG_OK) {
+
	while (pkg_jobs_entry(je, &p) == EPKG_OK) {
		if (pkg_repo_fetch(p) != EPKG_OK)
			return (EPKG_FATAL);
	}
@@ -87,11 +157,11 @@ pkg_jobs_install(struct pkg_jobs *j)
	/* Install */
	cachedir = pkg_config("PKG_CACHEDIR");
	p = NULL;
-
	while (pkg_jobs(j, &p) == EPKG_OK) {
+
	while (pkg_jobs_entry(je, &p) == EPKG_OK) {
		snprintf(path, sizeof(path), "%s/%s", cachedir,
				 pkg_get(p, PKG_REPOPATH));

-
		if (pkg_add(j->db, path) != EPKG_OK) {
+
		if (pkg_add(je->db, path) != EPKG_OK) {
			return (EPKG_FATAL);
		}
	}
@@ -100,13 +170,13 @@ pkg_jobs_install(struct pkg_jobs *j)
}

static int
-
pkg_jobs_deinstall(struct pkg_jobs *j, int force)
+
pkg_jobs_deinstall(struct pkg_jobs_entry *je, int force)
{
	struct pkg *p = NULL;
-
	int retcode;
+
	int retcode = EPKG_OK;

-
	while (pkg_jobs(j, &p) == EPKG_OK) {
-
		retcode = pkg_delete(p, j->db, force);
+
	while (pkg_jobs_entry(je, &p) == EPKG_OK) {
+
		retcode = pkg_delete(p, je->db, force);
		if (retcode != EPKG_OK)
			return (retcode);
	}
@@ -115,24 +185,24 @@ pkg_jobs_deinstall(struct pkg_jobs *j, int force)
}

int
-
pkg_jobs_apply(struct pkg_jobs *j, int force)
+
pkg_jobs_apply(struct pkg_jobs_entry *je, int force)
{
-
	if (j->type == PKG_JOBS_INSTALL)
-
		return (pkg_jobs_install(j));
-
	if (j->type == PKG_JOBS_DEINSTALL)
-
		return (pkg_jobs_deinstall(j, force));
+
	if (je->type == PKG_JOBS_INSTALL)
+
		return (pkg_jobs_install(je));
+
	if (je->type == PKG_JOBS_DEINSTALL)
+
		return (pkg_jobs_deinstall(je, force));

	EMIT_PKG_ERROR("%s", "bad jobs argument");
	return (EPKG_FATAL);
}

static struct pkg_jobs_node *
-
get_node(struct pkg_jobs *j, const char *name, int create)
+
get_node(struct pkg_jobs_entry *je, const char *name, int create)
{
-
	struct pkg_jobs_node *n;
+
	struct pkg_jobs_node *n = NULL;

	/* XXX hashmap? */
-
	LIST_FOREACH(n, &j->nodes, entries) {
+
	LIST_FOREACH(n, &je->nodes, entries) {
		if (strcmp(name, pkg_get(n->pkg, PKG_ORIGIN)) == 0) {
			return (n);
		}
@@ -142,7 +212,7 @@ get_node(struct pkg_jobs *j, const char *name, int create)
		return (NULL);

	n = calloc(1, sizeof(struct pkg_jobs_node));
-
	LIST_INSERT_HEAD(&j->nodes, n, entries);
+
	LIST_INSERT_HEAD(&je->nodes, n, entries);
	return (n);
}

@@ -164,48 +234,48 @@ add_parent(struct pkg_jobs_node *n, struct pkg_jobs_node *p)
}

static void
-
add_dep(struct pkg_jobs *j, struct pkg_jobs_node *n)
+
add_dep(struct pkg_jobs_entry *je, struct pkg_jobs_node *n)
{
	struct pkg_dep *dep = NULL;
-
	struct pkg_jobs_node *ndep;
+
	struct pkg_jobs_node *ndep = NULL;

	while (pkg_deps(n->pkg, &dep) != EPKG_END) {
-
		ndep = get_node(j, pkg_dep_origin(dep), 1);
+
		ndep = get_node(je, pkg_dep_origin(dep), 1);
		if (ndep->pkg == NULL) {
-
			ndep->pkg = pkgdb_query_remote(j->db, pkg_dep_origin(dep));
+
			ndep->pkg = pkgdb_query_remote(je->db, pkg_dep_origin(dep));
			if (ndep->pkg == NULL)
				EMIT_MISSING_DEP(n->pkg, dep);
			else
-
				add_dep(j, ndep);
+
				add_dep(je, ndep);
		}
		add_parent(ndep, n);
	}
}

static void
-
add_rdep(struct pkg_jobs *j, struct pkg_jobs_node *n)
+
add_rdep(struct pkg_jobs_entry *je, struct pkg_jobs_node *n)
{
-
	struct pkg_jobs_node *nrdep;
+
	struct pkg_jobs_node *nrdep = NULL;
	struct pkg_dep *rdep = NULL;

-
	pkgdb_loadrdeps(j->db, n->pkg);
+
	pkgdb_loadrdeps(je->db, n->pkg);

	while (pkg_rdeps(n->pkg, &rdep) == EPKG_OK) {
-
		nrdep = get_node(j, pkg_dep_origin(rdep), 0);
+
		nrdep = get_node(je, pkg_dep_origin(rdep), 0);
		if (nrdep != NULL)
			add_parent(nrdep, n);
	}
}

static void
-
remove_node(struct pkg_jobs *j, struct pkg_jobs_node *n)
+
remove_node(struct pkg_jobs_entry *je, struct pkg_jobs_node *n)
{
-
	struct pkg_jobs_node *np;
-
	size_t i;
+
	struct pkg_jobs_node *np = 0;
+
	size_t i = 0;

	assert(n->nrefs == 0);

-
	STAILQ_INSERT_TAIL(&j->jobs, n->pkg, next);
+
	STAILQ_INSERT_TAIL(&je->jobs, n->pkg, next);

	LIST_REMOVE(n, entries);

@@ -218,42 +288,42 @@ remove_node(struct pkg_jobs *j, struct pkg_jobs_node *n)
}

int
-
pkg_jobs_resolv(struct pkg_jobs *j)
+
pkg_jobs_resolv(struct pkg_jobs_entry *je)
{
-
	struct pkg_jobs_node *n, *tmp;
-
	struct pkg *p;
+
	struct pkg_jobs_node *n = NULL, *tmp = NULL;
+
	struct pkg *p = NULL;

-
	assert(j != NULL);
+
	assert(je != NULL);

-
	if (j->resolved == 1)
+
	if (je->resolved == 1)
		return (EPKG_OK);

	/* Create nodes and remove jobs form the queue */
-
	while (!STAILQ_EMPTY(&j->jobs)) {
-
		p = STAILQ_FIRST(&j->jobs);
-
		STAILQ_REMOVE_HEAD(&j->jobs, next);
+
	while (!STAILQ_EMPTY(&je->jobs)) {
+
		p = STAILQ_FIRST(&je->jobs);
+
		STAILQ_REMOVE_HEAD(&je->jobs, next);

-
		n = get_node(j, pkg_get(p, PKG_ORIGIN), 1);
+
		n = get_node(je, pkg_get(p, PKG_ORIGIN), 1);

		n->pkg = p;
	}

	/* Add dependencies into nodes */
-
	LIST_FOREACH(n, &j->nodes, entries) {
-
		if (j->type == PKG_JOBS_INSTALL)
-
			add_dep(j, n);
-
		if (j->type == PKG_JOBS_DEINSTALL)
-
			add_rdep(j, n);
+
	LIST_FOREACH(n, &je->nodes, entries) {
+
		if (je->type == PKG_JOBS_INSTALL)
+
			add_dep(je, n);
+
		if (je->type == PKG_JOBS_DEINSTALL)
+
			add_rdep(je, n);
	}

	/* Resolv !*/
	do {
-
		LIST_FOREACH_SAFE(n, &j->nodes, entries, tmp) {
+
		LIST_FOREACH_SAFE(n, &je->nodes, entries, tmp) {
			if (n->nrefs == 0)
-
				remove_node(j, n);
+
				remove_node(je, n);
		}
-
	} while (!LIST_EMPTY(&j->nodes));
+
	} while (!LIST_EMPTY(&je->nodes));

-
	j->resolved = 1;
+
	je->resolved = 1;
	return (EPKG_OK);
}
modified libpkg/pkg_private.h
@@ -35,6 +35,7 @@ struct pkg {
	STAILQ_HEAD(conflicts, pkg_conflict) conflicts;
	STAILQ_HEAD(scripts, pkg_script) scripts;
	STAILQ_HEAD(options, pkg_option) options;
+
	STAILQ_HEAD(repos_entry, pkg_repos_entry) repos;
	int flags;
	int64_t rowid;
	pkg_t type;
@@ -82,11 +83,16 @@ struct pkg_option {
};

struct pkg_jobs {
-
	STAILQ_HEAD(jobs, pkg) jobs;
-
	LIST_HEAD(nodes, pkg_jobs_node) nodes;
-
	struct pkgdb *db;
-
	pkg_jobs_t type;
-
	unsigned int resolved :1;
+
	struct pkg_jobs_entry {
+
		STAILQ_HEAD(jobs, pkg) jobs;
+
		LIST_HEAD(nodes, pkg_jobs_node) nodes;
+
		struct pkgdb *db;
+
		pkg_jobs_t type;
+
		unsigned int resolved :1;
+
		STAILQ_ENTRY(pkg_jobs_entry) next;
+
	} j;
+

+
	STAILQ_HEAD(jobs_multi, pkg_jobs_entry) multi;
};

struct pkg_jobs_node {
@@ -99,14 +105,14 @@ struct pkg_jobs_node {
};

struct pkg_repos {
-
	STAILQ_HEAD(repos, pkg_repos_entry) nodes;
-
};
+
	struct pkg_repos_entry {
+
		char *name;
+
		char *url;
+
		unsigned int line;
+
		STAILQ_ENTRY(pkg_repos_entry) entries;
+
	} r;

-
struct pkg_repos_entry {
-
	char *name;
-
	char *url;
-
	unsigned int line;
-
	STAILQ_ENTRY(pkg_repos_entry) entries;
+
	STAILQ_HEAD(repos, pkg_repos_entry) nodes;
};

int pkg_open2(struct pkg **p, struct archive **a, struct archive_entry **ae, const char *path);
@@ -140,7 +146,8 @@ void pkg_script_free(struct pkg_script *);
int pkg_option_new(struct pkg_option **);
void pkg_option_free(struct pkg_option *);

-
int pkg_jobs_resolv(struct pkg_jobs *jobs);
+
int pkg_jobs_resolv(struct pkg_jobs_entry *je);
+
void pkg_jobs_free_entry(struct pkg_jobs_entry *je);

struct packing;

modified libpkg/pkg_repo.c
@@ -11,15 +11,19 @@
#include "pkg_private.h"

static int pkg_repos_is_reserved_name(struct pkg_repos *repos, struct pkg_repos_entry *re);
+
static int pkg_repos_exists_in_pkg(struct pkg *pkg, struct pkg_repos_entry *re);

int
pkg_repo_fetch(struct pkg *pkg)
{
	char dest[MAXPATHLEN];
	char cksum[65];
-
	char *path;
-
	char *url;
+
	char *path = NULL;
+
	char *url = NULL;
	int retcode = EPKG_OK;
+
	int fetch_ok = 0;
+

+
	struct pkg_repos_entry *re = NULL;

	assert((pkg->type & PKG_REMOTE) == PKG_REMOTE ||
		(pkg->type & PKG_UPGRADE) == PKG_UPGRADE);
@@ -27,7 +31,7 @@ pkg_repo_fetch(struct pkg *pkg)
	snprintf(dest, sizeof(dest), "%s/%s", pkg_config("PKG_CACHEDIR"),
			 pkg_get(pkg, PKG_REPOPATH));

-
	/* If it is already in the local cachedir, dont bother to download it */
+
	/* If it is already in the local cachedir, don't bother to download it */
	if (access(dest, F_OK) == 0)
		goto checksum;

@@ -40,11 +44,37 @@ pkg_repo_fetch(struct pkg *pkg)
	if ((retcode = mkdirs(path)) != 0)
		goto cleanup;

-
	asprintf(&url, "%s/%s", pkg_config("PACKAGESITE"),
-
			 pkg_get(pkg, PKG_REPOPATH));
+
	if (pkg_config("PACKAGESITE") != NULL) {
+
		asprintf(&url, "%s/%s", pkg_config("PACKAGESITE"),
+
				 pkg_get(pkg, PKG_REPOPATH));
+

+
		retcode = pkg_fetch_file(url, dest);
+
		free(url);
+
	} else {
+
		/* 
+
		 * Get the repository URL from the package itself 
+
		 * Working on multiple repos here.
+
		 *
+
		 * If a package fetch is not successful go to the next
+
		 * repository in the list and give it more chance for
+
		 * successful fetch :)
+
		 */
+

+
		re = NULL; /* starts with the first repository entry */
+
		fetch_ok = EPKG_FATAL;
+
		while ((pkg_repos_next_in_pkg(pkg, &re) == EPKG_OK) && fetch_ok != EPKG_OK) {
+
			printf("Fetching package from repository '%s' [%s]\n",
+
					pkg_repos_get_name(re),
+
					pkg_repos_get_url(re));
+

+
			asprintf(&url, "%s/%s", pkg_repos_get_url(re),
+
					 pkg_get(pkg, PKG_REPOPATH));
+

+
			fetch_ok = retcode = pkg_fetch_file(url, dest);
+
			free(url);
+
		}
+
	}

-
	retcode = pkg_fetch_file(url, dest);
-
	free(url);
	if (retcode != EPKG_OK)
		goto cleanup;

@@ -84,7 +114,7 @@ pkg_repos_load(struct pkg_repos *repos)
        char buf[MAXPATHLEN];
        char *token = NULL, *tmp = NULL;
        unsigned int count = 0, line = 0;
-
	struct pkg_repos_entry *re;
+
	struct pkg_repos_entry *re = NULL;

	assert(repos != NULL);

@@ -158,6 +188,32 @@ pkg_repos_add(struct pkg_repos *repos, struct pkg_repos_entry *re)
}

int
+
pkg_repos_add_in_pkg(struct pkg *pkg, struct pkg_repos_entry *re)
+
{
+
	struct pkg_repos_entry *newre;
+

+
	assert(pkg != NULL && re != NULL);
+

+
	if (pkg_repos_exists_in_pkg(pkg, re) == EPKG_FATAL)
+
		return (EPKG_FATAL);
+

+
	if ((newre = calloc(1, sizeof(struct pkg_repos_entry))) == NULL) {
+
		EMIT_ERRNO("calloc", "pkg_repos_entry");
+
		return (EPKG_FATAL);
+
	}
+

+
	newre->name = strdup(re->name);
+
	newre->url  = strdup(re->url);
+
	newre->line = re->line;
+

+
	assert (newre->name != NULL && newre->url != NULL);
+

+
	STAILQ_INSERT_TAIL(&pkg->repos, newre, entries);
+

+
	return (EPKG_OK);
+
}
+

+
int
pkg_repos_next(struct pkg_repos *repos, struct pkg_repos_entry **re)
{
	assert(repos != NULL);
@@ -173,6 +229,22 @@ pkg_repos_next(struct pkg_repos *repos, struct pkg_repos_entry **re)
		return (EPKG_OK);
}

+
int
+
pkg_repos_next_in_pkg(struct pkg *pkg, struct pkg_repos_entry **re)
+
{
+
	assert(pkg != NULL);
+

+
	if (*re == NULL)
+
		*re = STAILQ_FIRST(&pkg->repos);
+
	else
+
		*re = STAILQ_NEXT(*re, entries);
+

+
	if (*re == NULL)
+
		return (EPKG_END);
+
	else
+
		return (EPKG_OK);
+
}
+

const char *
pkg_repos_get_name(struct pkg_repos_entry *re)
{
@@ -202,6 +274,9 @@ pkg_repos_free(struct pkg_repos *repos)
{
	struct pkg_repos_entry *re1, *re2;

+
	if (repos == NULL)
+
		return;
+

        re1 = STAILQ_FIRST(&repos->nodes);
        while (re1 != NULL) {
                re2 = STAILQ_NEXT(re1, entries);
@@ -218,6 +293,28 @@ pkg_repos_free(struct pkg_repos *repos)
	free(repos);
}

+
void
+
pkg_repos_free_in_pkg(struct pkg *pkg)
+
{
+
	struct pkg_repos_entry *re1, *re2;
+

+
	if (pkg == NULL)
+
		return;
+

+
	re1 = STAILQ_FIRST(&pkg->repos);
+
	while (re1 != NULL) {
+
		re2 = STAILQ_NEXT(re1, entries);
+

+
		if (re1->name != NULL)
+
			free(re1->name);
+
		if (re1->url != NULL)
+
			free(re1->url);
+

+
		free(re1);
+
		re1 = re2;
+
	}
+
}
+

static int
pkg_repos_is_reserved_name(struct pkg_repos *repos, struct pkg_repos_entry *re)
{
@@ -236,3 +333,15 @@ pkg_repos_is_reserved_name(struct pkg_repos *repos, struct pkg_repos_entry *re)

	return (EPKG_OK);
}
+

+
static int
+
pkg_repos_exists_in_pkg(struct pkg *pkg, struct pkg_repos_entry *re)
+
{
+
	struct pkg_repos_entry *tmp = NULL;
+

+
	while(pkg_repos_next_in_pkg(pkg, &tmp) == EPKG_OK)
+
		if (strcmp(pkg_repos_get_name(tmp), pkg_repos_get_name(re)) == 0)
+
			return (EPKG_FATAL);
+

+
	return (EPKG_OK);
+
}
modified pkg/delete.c
@@ -21,9 +21,12 @@ int
exec_delete(int argc, char **argv)
{
	struct pkg_jobs *jobs = NULL;
+
	struct pkg_jobs_entry *je = NULL;
+

	struct pkg *pkg = NULL;
	struct pkgdb *db = NULL;
	struct pkgdb_it *it = NULL;
+

	match_t match = MATCH_EXACT;
	char *origin = NULL;
	int ch;
@@ -64,7 +67,15 @@ exec_delete(int argc, char **argv)
	if (argc == 1)
		origin = argv[0];

-
	if ((retcode = pkg_jobs_new(&jobs, PKG_JOBS_DEINSTALL, db)) != EPKG_OK) {
+
	/* create a jobs object */
+
	if (pkg_jobs_new(&jobs) != EPKG_OK) {
+
		retcode = EPKG_FATAL;
+
		goto cleanup;
+
	}
+

+
	/* create a jobs entry */
+
	if (pkg_jobs_new_entry(jobs, &je, PKG_JOBS_DEINSTALL, db) != EPKG_OK) {
+
		retcode = EPKG_FATAL;
		goto cleanup;
	}

@@ -74,7 +85,7 @@ exec_delete(int argc, char **argv)
	}

	while ((retcode = pkgdb_it_next(it, &pkg, flags)) == EPKG_OK) {
-
		pkg_jobs_add(jobs, pkg);
+
		pkg_jobs_add(je, pkg);
		pkg = NULL;
	}

@@ -82,7 +93,7 @@ exec_delete(int argc, char **argv)
		goto cleanup;
	}

-
	if ((retcode = pkg_jobs_apply(jobs, force)) != EPKG_OK) {
+
	if ((retcode = pkg_jobs_apply(je, force)) != EPKG_OK) {
		goto cleanup;
	}

@@ -90,7 +101,6 @@ exec_delete(int argc, char **argv)

	cleanup:
	pkgdb_it_free(it);
-
	pkgdb_close(db);
	pkg_jobs_free(jobs);

	return (retcode == EPKG_OK ? EX_OK : 1);
modified pkg/install.c
@@ -1,4 +1,5 @@
#include <sys/types.h>
+
#include <sys/param.h>

#include <err.h>
#include <libgen.h>
@@ -22,11 +23,19 @@ usage_install(void)
int
exec_install(int argc, char **argv)
{
-
	struct pkg *pkg = NULL;
-
	struct pkgdb *db = NULL;
-
	struct pkg_jobs *jobs = NULL;
+
	char dbfile[MAXPATHLEN];
+

	int retcode = EPKG_OK;
-
	int i;
+
	int i, multi_repos = 0;
+

+
	struct pkg_jobs *jobs = NULL;
+
	struct pkg_jobs_entry *je = NULL;
+

+
	struct pkg_repos *repos = NULL;
+
	struct pkg_repos_entry *re = NULL;
+

+
	struct pkg *pkg = NULL, *tmp = NULL;
+
	struct pkgdb *db = NULL;

	if (argc < 2) {
		usage_install();
@@ -38,37 +47,129 @@ exec_install(int argc, char **argv)
		return (EX_NOPERM);
	}

-
	if (pkgdb_open(&db, PKGDB_REMOTE, "repo.sqlite") != EPKG_OK) {
-
		return (EX_IOERR);
-
	}
-

-
	if (pkg_jobs_new(&jobs, PKG_JOBS_INSTALL, db) != EPKG_OK) {
+
	/* create a jobs object */
+
	if (pkg_jobs_new(&jobs) != EPKG_OK) {
		retcode = EPKG_FATAL;
		goto cleanup;
	}

-
	for (i = 1; i < argc; i++) {
-
		if ((pkg = pkgdb_query_remote(db, argv[i])) == NULL) {
-
			retcode = EPKG_FATAL;
-
			goto cleanup;
+
	/*
+
	 * Honor PACKAGESITE if specified 
+
	 * Working on a single repo database
+
	 */
+
	if (pkg_config("PACKAGESITE") != NULL) {
+
                if (pkgdb_open(&db, PKGDB_REMOTE, "repo.sqlite") != EPKG_OK) {
+
                        warnx("cannot open repository database: %s/repo.sqlite\n", pkg_config("PKG_DBDIR"));
+
                        retcode = EPKG_FATAL;
+
                        goto cleanup;
+
                }
+

+
                /* create a jobs entry */
+
                if (pkg_jobs_new_entry(jobs, &je, PKG_JOBS_INSTALL, db) != EPKG_OK) {
+
                        retcode = EPKG_FATAL;
+
                        goto cleanup;
+
                }
+

+
		for (i = 1; i < argc; i++) {
+
			if ((pkg = pkgdb_query_remote(db, argv[i])) == NULL) {
+
				retcode = EPKG_FATAL;
+
				goto cleanup;
+
			}
+
			
+
			/* pkg_jobs_resolv() will be enough here for jobs resolving :) */
+
			pkg_jobs_add(je, pkg);
		}
-

-
		pkg_jobs_add(jobs, pkg);
-
	}
+
	} else {
+
		/* MULTI_REPOS_INSTALL */
+

+
		multi_repos = 1;
+

+
                fprintf(stderr, "\n");
+
                warnx("/!\\     Working on multiple repositories     /!\\");
+
                warnx("/!\\  This is an unsupported preview feature  /!\\");
+
                warnx("/!\\     It can kill kittens and puppies      /!\\");
+
                fprintf(stderr, "\n");
+

+
                if (pkg_repos_new(&repos) != EPKG_OK) {
+
                        retcode = EPKG_FATAL;
+
                        goto cleanup;
+
                }
+

+
                if (pkg_repos_load(repos) != EPKG_OK) {
+
                        retcode = EPKG_FATAL;
+
                        goto cleanup;
+
                }
+
        
+
                while (pkg_repos_next(repos, &re) == EPKG_OK) { 
+
                        snprintf(dbfile, MAXPATHLEN, "%s.sqlite", pkg_repos_get_name(re));
+

+
                        if (pkgdb_open(&db, PKGDB_REMOTE, dbfile) != EPKG_OK) {
+
                                warnx("cannot open repository database: %s/%s\n", 
+
                                                pkg_config("PKG_DBDIR"), dbfile);
+
                                retcode = EPKG_FATAL;
+
                                goto cleanup;
+
                        }
+

+
                        /* create a jobs entry for each db connection */
+
                        if (pkg_jobs_new_entry(jobs, &je, PKG_JOBS_INSTALL, db) != EPKG_OK) {
+
                                retcode = EPKG_FATAL;
+
                                goto cleanup;
+
                        }
+

+
        		for (i = 1; i < argc; i++) {
+
				if ((pkg = pkgdb_query_remote(db, argv[i])) == NULL) {
+
					retcode = EPKG_FATAL;
+
					goto cleanup;
+
				}
+
				
+
				/* 
+
				 * check if the job already exists in other job entries
+
				 * If it exists we add additional repo to the package.
+
				 * Otherwise we have a new package job.
+
				 */
+
				tmp = NULL;
+
				if (pkg_jobs_exists(jobs, pkg, &tmp) == EPKG_OK)
+
					pkg_jobs_add(je, pkg);
+
				else
+
					pkg_repos_add_in_pkg(tmp, re);
+
			}
+
                }
+
	} /* !MULTI_REPOS_INSTALL */

	/* print a summary before applying the jobs */
-
	pkg = NULL;
	printf("The following packages will be installed:\n");
-
	while (pkg_jobs(jobs, &pkg) == EPKG_OK) {
-
		printf("%s-%s\n", pkg_get(pkg, PKG_NAME), pkg_get(pkg, PKG_VERSION));
+

+
	je = NULL; /* starts with the first job entry */
+
	while (pkg_jobs(jobs, &je) == EPKG_OK) {
+
		pkg = NULL; /* start with the first package in a job entry */
+
		while (pkg_jobs_entry(je, &pkg) == EPKG_OK) {
+
			printf("\t%s-%s", pkg_get(pkg, PKG_NAME), pkg_get(pkg, PKG_VERSION));
+

+
			if (multi_repos == 1) {
+
				printf(" [ found in repos: ");
+

+
				re = NULL;
+
				while (pkg_repos_next_in_pkg(pkg, &re) == EPKG_OK)
+
					printf("%s ", pkg_repos_get_name(re));
+

+
				printf(" ]");
+
			}
+

+
			printf("\n");
+
		}
	}

-
	retcode = pkg_jobs_apply(jobs, 0);
+
	je = NULL;
+
	while (pkg_jobs(jobs, &je) == EPKG_OK)
+
		retcode = pkg_jobs_apply(je, 0);

	cleanup:
-
	pkgdb_close(db);
+
	
+
	if (multi_repos == 1)
+
		pkg_repos_free(repos);
+

+
	/* db connections are closed by pkg_jobs_free() */
	pkg_jobs_free(jobs);

	return (retcode == EPKG_OK ? EX_OK : 1);
}
-

modified pkg/search.c
@@ -137,7 +137,12 @@ search_remote_repo(const char *pattern, match_t match, unsigned int field, const
		humanize_number(size, sizeof(size), pkg_new_pkgsize(pkg), "B", HN_AUTOSCALE, 0);
		printf("Pkg size:   %s\n", size);
		printf("\n");
+

	}

+
	pkg_free(pkg);
+
	pkgdb_it_free(it);
+
	pkgdb_close(db);
+

	return (retcode);
}