Radish alpha
H
rad:z3QDZAW2FAfuLvihrhiyDC9fAD8G9
HardenedBSD Package Manager
Radicle
Git
Merge remote branch 'pkgng/master'
Will Andrews committed 14 years ago
commit f4f6257da7b80a1a42a9b49cf41f6d17df1f749d
parent 726e3ad
12 files changed +536 -247
modified libpkg/Makefile
@@ -16,6 +16,7 @@ SRCS= pkg.c \
		pkg_event.c \
		pkg_error.c \
		pkg_handle.c \
+
		pkg_jobs.c \
		pkg_manifest.c \
		pkg_ports.c \
		pkg_repo.c \
modified libpkg/pkg.h
@@ -16,6 +16,8 @@ struct pkg_option;
struct pkgdb;
struct pkgdb_it;

+
struct pkg_jobs;
+

typedef enum {
	PKGDB_DEFAULT=0,
	PKGDB_REMOTE
@@ -147,6 +149,8 @@ typedef enum {
typedef void (*fetch_cb)(void *data, const char *url, off_t total, off_t done,
						 time_t elapsed);

+
typedef void (*status_cb)(void *data, struct pkg *pkg);
+

/**
 * Allocate a new pkg.
 * Allocated pkg must be deallocated by pkg_free().
@@ -287,8 +291,6 @@ int pkg_setnewflatsize(struct pkg *pkg, int64_t size);
 */
int pkg_setnewpkgsize(struct pkg *pkg, int64_t size);

-

-

/**
 * Allocate a new struct pkg and add it to the deps of pkg.
 * @return An error code.
@@ -317,7 +319,6 @@ int pkg_adddir(struct pkg *pkg, const char *path);
 */
int pkg_addconflict(struct pkg *pkg, const char *glob);

-

/**
 * Allocate a new struct pkg_script and add it to the scripts of pkg.
 * @param path The path to the script on disk.
@@ -354,6 +355,7 @@ int pkg_load_manifest_file(struct pkg *pkg, const char *fpath);
 */
int pkg_emit_manifest(struct pkg *pkg, char **buf);

+
/* pkg_dep */
const char *pkg_dep_origin(struct pkg_dep *dep);
const char *pkg_dep_name(struct pkg_dep *dep);
const char *pkg_dep_version(struct pkg_dep *dep);
@@ -432,6 +434,13 @@ struct pkgdb_it * pkgdb_query(struct pkgdb *db, const char *pattern,
							  match_t type);

/**
+
 * Query the remote database.
+
 * @param db A pkgdb opened with PKGDB_REMOTE.
+
 * @warning Returns NULL on failure.
+
 */
+
struct pkg * pkgdb_query_remote(struct pkgdb *db, const char *pattern);
+

+
/**
 * 
 */
struct pkgdb_it *pkgdb_query_upgrades(struct pkgdb *db);
@@ -494,6 +503,38 @@ int pkgdb_compact(struct pkgdb *db);
int pkg_add(struct pkgdb *db, const char *path, struct pkg **pkg);

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

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

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

+
/**
+
 * 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);
+

+
/**
+
 * Apply the jobs in the queue (fetch and install).
+
 * @return An error code.
+
 */
+
int pkg_jobs_apply(struct pkg_jobs *jobs, void *data, fetch_cb fcb,
+
				   status_cb scb);
+

+
/**
 * Archive formats options.
 */
typedef enum pkg_formats { TAR, TGZ, TBZ, TXZ } pkg_formats;
@@ -574,6 +615,7 @@ int pkg_script_pre_upgrade(struct pkg *);
int pkg_script_post_upgrade(struct pkg *);
int pkg_script_pre_deinstall(struct pkg *);
int pkg_script_post_deinstall(struct pkg *);
+
int pkg_script_run(struct pkg *, pkg_script_t type);

/**
 * Event type used to report progress or problems.
modified libpkg/pkg_add.c
@@ -175,7 +175,7 @@ pkg_add(struct pkgdb *db, const char *path, struct pkg **pkg_p)
	/*
	 * Execute pre-install scripts
	 */
-
	pkg_script_pre_install(pkg);
+
	pkg_script_run(pkg, PKG_SCRIPT_PRE_INSTALL);

	/*
	 * Extract the files on disk.
@@ -190,7 +190,7 @@ pkg_add(struct pkgdb *db, const char *path, struct pkg **pkg_p)
	/*
	 * Execute post install scripts
	 */
-
	pkg_script_post_install(pkg);
+
	pkg_script_run(pkg, PKG_SCRIPT_POST_INSTALL);

	cleanup_reg:
	pkgdb_register_finale(db, retcode);
modified libpkg/pkg_config.c
@@ -43,9 +43,6 @@ load_config(void)
	}

	done = 1;
-

-
	if (p != NULL)
-
		properties_free(p);
}

const char *
modified libpkg/pkg_delete.c
@@ -62,13 +62,13 @@ pkg_delete(struct pkg *pkg, struct pkgdb *db, int force)
		sbuf_free(rdep_msg);
	}

-
	if ((ret = pkg_script_pre_deinstall(pkg)) != EPKG_OK)
+
	if ((ret = pkg_script_run(pkg, PKG_SCRIPT_PRE_DEINSTALL)) != EPKG_OK)
		return (ret);

	if ((ret = pkg_delete_files(pkg, force)) != EPKG_OK)
		return (ret);

-
	if ((ret = pkg_script_post_deinstall(pkg)) != EPKG_OK)
+
	if ((ret = pkg_script_run(pkg, PKG_SCRIPT_POST_DEINSTALL)) != EPKG_OK)
		return (ret);

	if ((ret = pkg_delete_dirs(pkg, force)) != EPKG_OK)
added libpkg/pkg_jobs.c
@@ -0,0 +1,217 @@
+
#include <assert.h>
+
#include <err.h>
+
#include <stdlib.h>
+
#include <string.h>
+

+
#include "pkg.h"
+
#include "pkgdb.h"
+
#include "pkg_error.h"
+
#include "pkg_private.h"
+

+
int
+
pkg_jobs_new(struct pkg_jobs **j, struct pkgdb *db)
+
{
+
	if (db == NULL || db->type != PKGDB_REMOTE)
+
		return (ERROR_BAD_ARG("db"));
+

+
	if((*j = calloc(1, sizeof(struct pkg_jobs))) == NULL)
+
		err(1, "calloc()");
+

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

+
	return (EPKG_OK);
+
}
+

+
void
+
pkg_jobs_free(struct pkg_jobs *j)
+
{
+
	struct pkg *p;
+

+
	while (!STAILQ_EMPTY(&j->jobs)) {
+
		p = STAILQ_FIRST(&j->jobs);
+
		STAILQ_REMOVE_HEAD(&j->jobs, next);
+
		pkg_free(p);
+
	}
+
	free(j);
+
}
+

+
int
+
pkg_jobs_add(struct pkg_jobs *j, struct pkg *pkg)
+
{
+
	if (j == NULL)
+
		return (ERROR_BAD_ARG("jobs"));
+
	if (pkg == NULL)
+
		return (ERROR_BAD_ARG("pkg"));
+

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

+
	return (EPKG_OK);
+
}
+

+
int
+
pkg_jobs(struct pkg_jobs *j, struct pkg **pkg)
+
{
+
	if (j == NULL)
+
		return (ERROR_BAD_ARG("jobs"));
+

+
	pkg_jobs_resolv(j, 0);
+

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

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

+
int
+
pkg_jobs_apply(struct pkg_jobs *j, void *data, fetch_cb fcb, status_cb scb)
+
{
+
	struct pkg *p = NULL;
+
	struct pkg *pfile = NULL;
+
	const char *cachedir;
+
	char path[MAXPATHLEN];
+

+
	/* Fetch */
+
	while (pkg_jobs(j, &p) == EPKG_OK) {
+
		if (pkg_repo_fetch(p, data, fcb) != EPKG_OK)
+
			return (EPKG_FATAL);
+
	}
+

+
	/* Install */
+
	cachedir = pkg_config("PKG_CACHEDIR");
+
	p = NULL;
+
	while (pkg_jobs(j, &p) == EPKG_OK) {
+
		snprintf(path, sizeof(path), "%s/%s", cachedir,
+
				 pkg_get(p, PKG_REPOPATH));
+

+
		if (scb != NULL)
+
			scb(data, p);
+
		if (pkg_add(j->db, path, &pfile) != EPKG_OK) {
+
			pkg_free(pfile);
+
			return (EPKG_FATAL);
+
		}
+
		if (scb != NULL)
+
			scb(data, pfile);
+
	}
+

+
	pkg_free(pfile);
+
	return (EPKG_OK);
+
}
+

+
static struct pkg_jobs_node *
+
get_node(struct pkg_jobs *j, const char *name)
+
{
+
	struct pkg_jobs_node *n;
+

+
	/* XXX hashmap? */
+
	LIST_FOREACH(n, &j->nodes, entries) {
+
		if (strcmp(name, pkg_get(n->pkg, PKG_ORIGIN)) == 0) {
+
			return (n);
+
		}
+
	}
+

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

+
static void
+
add_dep(struct pkg_jobs *j, struct pkg_jobs_node *n)
+
{
+
	struct pkg_dep *d = NULL;
+
	struct pkg_jobs_node *nd;
+

+
	while (pkg_deps(n->pkg, &d) != EPKG_END) {
+
		n->nrefs++;
+
		nd = get_node(j, pkg_dep_origin(d));
+

+
		if (nd->pkg == NULL) {
+
			/* XXX should query with origin */
+
			nd->pkg = pkgdb_query_remote(j->db, pkg_dep_origin(d));
+
			if (nd->pkg == NULL)
+
				err(1, "%s", pkg_error_string());
+
			add_dep(j, nd);
+
		}
+

+
		if (nd->parents_len == nd->parents_cap) {
+
			if (nd->parents_cap == 0)
+
				nd->parents_cap = 5;
+
			else
+
				nd->parents_cap *= 2;
+
			nd->parents = realloc(nd->parents, nd->parents_cap *
+
								  sizeof(struct pkg_jobs_node));
+
		}
+
		nd->parents[nd->parents_len] = n;
+
		nd->parents_len++;
+
	}
+
}
+

+
static void
+
remove_node(struct pkg_jobs *j, struct pkg_jobs_node *n)
+
{
+
	struct pkg_jobs_node *np;
+
	size_t i;
+

+
	assert(n->nrefs == 0);
+

+
	if (j->reverse == 1)
+
		STAILQ_INSERT_HEAD(&j->jobs, n->pkg, next);
+
	else
+
		STAILQ_INSERT_TAIL(&j->jobs, n->pkg, next);
+

+
	LIST_REMOVE(n, entries);
+

+
	for (i = 0; i < n->parents_len; i++) {
+
		np = n->parents[i];
+
		np->nrefs--;
+
	}
+
	free(n->parents);
+
	free(n);
+
}
+

+
int
+
pkg_jobs_resolv(struct pkg_jobs *j, int reverse)
+
{
+
	struct pkg_jobs_node *n, *tmp;
+
	struct pkg *p;
+

+
	if (j == NULL)
+
		return (ERROR_BAD_ARG("jobs"));
+

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

+
	j->reverse = reverse;
+

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

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

+
		n->pkg = p;
+
	}
+

+
	/* Add dependencies into nodes */
+
	LIST_FOREACH(n, &j->nodes, entries) {
+
		add_dep(j, n);
+
	}
+

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

+
	j->resolved = 1;
+
	return (EPKG_OK);
+
}
modified libpkg/pkg_private.h
@@ -37,6 +37,7 @@ struct pkg {
	int flags;
	int64_t rowid;
	pkg_t type;
+
	STAILQ_ENTRY(pkg) next;
};

struct pkg_dep {
@@ -74,6 +75,23 @@ struct pkg_option {
	STAILQ_ENTRY(pkg_option) next;
};

+
struct pkg_jobs {
+
	STAILQ_HEAD(jobs, pkg) jobs;
+
	LIST_HEAD(nodes, pkg_jobs_node) nodes;
+
	struct pkgdb *db;
+
	unsigned int resolved :1;
+
	unsigned int reverse :1;
+
};
+

+
struct pkg_jobs_node {
+
	struct pkg *pkg;
+
	size_t nrefs;
+
	struct pkg_jobs_node **parents; /* rdeps */
+
	size_t parents_len;
+
	size_t parents_cap;
+
	LIST_ENTRY(pkg_jobs_node) entries;
+
};
+

int pkg_open2(struct pkg **p, struct archive **a, struct archive_entry **ae, const char *path);
void pkg_freedeps(struct pkg *pkg);
void pkg_freerdeps(struct pkg *pkg);
@@ -101,6 +119,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 reverse);
+

struct packing;

int packing_init(struct packing **pack, const char *path, pkg_formats format);
modified libpkg/pkg_repo.c
@@ -13,7 +13,8 @@ pkg_repo_fetch(struct pkg *pkg, void *data, fetch_cb cb)
	char *url;
	int retcode = EPKG_OK;

-
	if ((pkg->type & PKG_REMOTE) != PKG_REMOTE)
+
	if ((pkg->type & PKG_REMOTE) != PKG_REMOTE &&
+
		(pkg->type & PKG_UPGRADE) != PKG_UPGRADE)
		return (ERROR_BAD_ARG("pkg"));

	snprintf(dest, sizeof(dest), "%s/%s", pkg_config("PKG_CACHEDIR"),
@@ -25,8 +26,11 @@ pkg_repo_fetch(struct pkg *pkg, void *data, fetch_cb cb)

	asprintf(&url, "%s/%s", pkg_config("PACKAGESITE"),
			 pkg_get(pkg, PKG_REPOPATH));
-
	pkg_fetch_file(url, dest, data, cb);
+

+
	retcode = pkg_fetch_file(url, dest, data, cb);
	free(url);
+
	if (retcode != EPKG_OK)
+
		goto cleanup;

	checksum:
	retcode = sha256_file(dest, cksum);
@@ -36,5 +40,9 @@ pkg_repo_fetch(struct pkg *pkg, void *data, fetch_cb cb)
			retcode = EPKG_FATAL;
		}

+
	cleanup:
+
	if (retcode != EPKG_OK)
+
		unlink(dest);
+

	return (retcode);
}
modified libpkg/pkgdb.c
@@ -366,9 +366,9 @@ pkgdb_it_next(struct pkgdb_it *it, struct pkg **pkg_p, int flags)
	switch (sqlite3_step(it->stmt)) {
	case SQLITE_ROW:
		if (*pkg_p == NULL)
-
			pkg_new(pkg_p, PKG_INSTALLED);
+
			pkg_new(pkg_p, it->type);
		else
-
			pkg_reset(*pkg_p, PKG_INSTALLED);
+
			pkg_reset(*pkg_p, it->type);
		pkg = *pkg_p;

		pkg->rowid = sqlite3_column_int64(it->stmt, 0);
@@ -385,7 +385,7 @@ pkgdb_it_next(struct pkgdb_it *it, struct pkg **pkg_p, int flags)
		pkg_set(pkg, PKG_PREFIX, sqlite3_column_text(it->stmt, 11));
		pkg_setflatsize(pkg, sqlite3_column_int64(it->stmt, 12));

-
		if (it->type == IT_UPGRADE) {
+
		if (it->type == PKG_UPGRADE) {
			pkg->type = PKG_UPGRADE;

			pkg_set(pkg, PKG_NEWVERSION, sqlite3_column_text(it->stmt, 13));
@@ -394,6 +394,10 @@ pkgdb_it_next(struct pkgdb_it *it, struct pkg **pkg_p, int flags)
			pkg_set(pkg, PKG_REPOPATH, sqlite3_column_text(it->stmt, 16));
		}

+
		/* load only for PKG_INSTALLED */
+
		if (it->type != PKG_INSTALLED)
+
			return (EPKG_OK);
+

		if (flags & PKG_LOAD_DEPS)
			if ((ret = pkgdb_loaddeps(it->db, pkg)) != EPKG_OK)
				return (ret);
@@ -508,7 +512,82 @@ pkgdb_query(struct pkgdb *db, const char *pattern, match_t match)
	if (match != MATCH_ALL)
		sqlite3_bind_text(stmt, 1, pattern, -1, SQLITE_TRANSIENT);

-
	return (pkgdb_it_new(db, stmt, IT_LOCAL));
+
	return (pkgdb_it_new(db, stmt, PKG_INSTALLED));
+
}
+

+
struct pkg *
+
pkgdb_query_remote(struct pkgdb *db, const char *pattern)
+
{
+
	sqlite3_stmt *stmt = NULL;
+
	sqlite3_stmt *stmt_deps = NULL;
+
	struct pkg *pkg = NULL;
+
	int ret;
+
	char sql[] = ""
+
		"SELECT p.rowid, p.origin, p.name, p.version, p.comment, p.desc, "
+
			"p.arch, p.osversion, p.maintainer, p.www, p.pkgsize, "
+
			"p.flatsize, p.cksum, p.path "
+
		"FROM remote.packages AS p "
+
		"WHERE p.origin = ?1";
+
	char sql_deps[] = ""
+
		"SELECT d.name, d.origin, d.version "
+
		"FROM remote.deps AS d "
+
		"WHERE d.package_id = ?1 "
+
			"AND NOT EXISTS (SELECT 1 FROM main.packages AS p "
+
			"WHERE p.origin = d.origin)";
+

+
	if (db == NULL || db->type != PKGDB_REMOTE) {
+
		ERROR_BAD_ARG("db");
+
		return (NULL);
+
	}
+

+
	if (sqlite3_prepare_v2(db->sqlite, sql, -1, &stmt, NULL) != SQLITE_OK) {
+
		ERROR_SQLITE(db->sqlite);
+
		return (NULL);
+
	}
+

+
	if (sqlite3_prepare_v2(db->sqlite, sql_deps, -1, &stmt_deps, NULL) != SQLITE_OK) {
+
		ERROR_SQLITE(db->sqlite);
+
		return (NULL);
+
	}
+
	sqlite3_bind_text(stmt, 1, pattern, -1, SQLITE_STATIC);
+

+
	ret = sqlite3_step(stmt);
+
	if (ret != SQLITE_ROW) {
+
		if (ret != SQLITE_DONE)
+
			ERROR_SQLITE(db->sqlite);
+
		goto cleanup;
+
	}
+

+
	pkg_new(&pkg, PKG_REMOTE);
+

+
	pkg->rowid = sqlite3_column_int64(stmt, 0);
+
	pkg_set(pkg, PKG_ORIGIN, sqlite3_column_text(stmt, 1));
+
	pkg_set(pkg, PKG_NAME, sqlite3_column_text(stmt, 2));
+
	pkg_set(pkg, PKG_VERSION, sqlite3_column_text(stmt, 3));
+
	pkg_set(pkg, PKG_COMMENT, sqlite3_column_text(stmt, 4));
+
	pkg_set(pkg, PKG_DESC, sqlite3_column_text(stmt, 5));
+
	pkg_set(pkg, PKG_ARCH, sqlite3_column_text(stmt, 6));
+
	pkg_set(pkg, PKG_OSVERSION, sqlite3_column_text(stmt, 7));
+
	pkg_set(pkg, PKG_MAINTAINER, sqlite3_column_text(stmt, 8));
+
	pkg_set(pkg, PKG_WWW, sqlite3_column_text(stmt, 9));
+
	pkg_setnewpkgsize(pkg, sqlite3_column_int64(stmt, 10));
+
	pkg_setnewflatsize(pkg, sqlite3_column_int64(stmt, 11));
+
	pkg_set(pkg, PKG_CKSUM, sqlite3_column_text(stmt, 12));
+
	pkg_set(pkg, PKG_REPOPATH, sqlite3_column_text(stmt, 13));
+

+
	sqlite3_bind_int64(stmt_deps, 1, pkg->rowid);
+
	while ((ret = sqlite3_step(stmt_deps)) == SQLITE_ROW) {
+
		pkg_adddep(pkg, sqlite3_column_text(stmt_deps, 0),
+
				   sqlite3_column_text(stmt_deps, 1),
+
				   sqlite3_column_text(stmt_deps, 2));
+
	}
+

+
	cleanup:
+
	if (stmt != NULL)
+
		sqlite3_finalize(stmt);
+
	if (stmt_deps != NULL)
+
		sqlite3_finalize(stmt_deps);
+
	return (pkg);
}

struct pkgdb_it *
@@ -530,7 +609,7 @@ pkgdb_query_which(struct pkgdb *db, const char *path)

	sqlite3_bind_text(stmt, 1, path, -1, SQLITE_TRANSIENT);

-
	return (pkgdb_it_new(db, stmt, IT_LOCAL));
+
	return (pkgdb_it_new(db, stmt, PKG_INSTALLED));
}

int
@@ -1277,7 +1356,7 @@ pkgdb_query_upgrades(struct pkgdb *db)
		return (NULL);
	}

-
	return (pkgdb_it_new(db, stmt, IT_UPGRADE));
+
	return (pkgdb_it_new(db, stmt, PKG_UPGRADE));
}

struct pkgdb_it *
@@ -1306,7 +1385,7 @@ pkgdb_query_downgrades(struct pkgdb *db)
		return (NULL);
	}

-
	return (pkgdb_it_new(db, stmt, IT_UPGRADE));
+
	return (pkgdb_it_new(db, stmt, PKG_UPGRADE));
}

struct pkgdb_it *
@@ -1326,5 +1405,5 @@ pkgdb_query_autoremove(struct pkgdb *db)
		return (NULL);
	}

-
	return (pkgdb_it_new(db, stmt, IT_LOCAL));
+
	return (pkgdb_it_new(db, stmt, PKG_INSTALLED));
}
modified libpkg/pkgdb.h
@@ -11,9 +11,6 @@ struct pkgdb {
	pkgdb_t type;
};

-
#define IT_LOCAL 0
-
#define IT_UPGRADE 1
-

struct pkgdb_it {
	struct pkgdb *db;
	sqlite3_stmt *stmt;
modified libpkg/scripts.c
@@ -3,206 +3,56 @@
#include <pkg_error.h>

int
-
pkg_script_pre_install(struct pkg *pkg)
+
pkg_script_run(struct pkg *pkg, pkg_script_t type)
{
	struct pkg_script *script = NULL;
+
	pkg_script_t stype;
	struct sbuf *script_cmd = sbuf_new_auto();
-

-
	while (pkg_scripts(pkg, &script) == EPKG_OK) {
-
		switch (pkg_script_type(script)) {
-
			case PKG_SCRIPT_INSTALL:
-
				sbuf_reset(script_cmd);
-
				sbuf_printf(script_cmd, "PKG_PREFIX=%s\nset -- %s-%s PRE-INSTALL\n%s",
-
					pkg_get(pkg, PKG_PREFIX), pkg_get(pkg, PKG_NAME),
-
					pkg_get(pkg, PKG_VERSION), pkg_script_data(script));
-
				sbuf_finish(script_cmd);
-
				system(sbuf_data(script_cmd));
-
				break;
-
			case PKG_SCRIPT_PRE_INSTALL:
-
				sbuf_reset(script_cmd);
-
				sbuf_printf(script_cmd, "PKG_PREFIX=%s\nset -- %s-%s\n%s",
-
				  pkg_get(pkg, PKG_PREFIX), pkg_get(pkg, PKG_NAME),
-
				  pkg_get(pkg, PKG_VERSION), pkg_script_data(script));
-
				sbuf_finish(script_cmd);
-
				system(sbuf_data(script_cmd));
-
				break;
-
			default:
-
				/* ignored to prevent warning */
-
				break;
-
		}
-
	}
-

-
	sbuf_delete(script_cmd);
-

-
	return (EPKG_OK);
-
}
-

-
int
-
pkg_script_post_install(struct pkg *pkg)
-
{
-
	struct pkg_script *script = NULL;
-
	struct sbuf *script_cmd = sbuf_new_auto();
-

-
	while (pkg_scripts(pkg, &script) == EPKG_OK) {
-
		switch (pkg_script_type(script)) {
-
			case PKG_SCRIPT_INSTALL:
-
				sbuf_reset(script_cmd);
-
				sbuf_printf(script_cmd, "PKG_PREFIX=%s\nset -- %s-%s POST-INSTALL\n%s",
-
				  pkg_get(pkg, PKG_PREFIX), pkg_get(pkg, PKG_NAME),
-
				  pkg_get(pkg, PKG_VERSION), pkg_script_data(script));
-
				sbuf_finish(script_cmd);
-
				system(sbuf_data(script_cmd));
-
				break;
-
			case PKG_SCRIPT_POST_INSTALL:
-
				sbuf_reset(script_cmd);
-
				sbuf_printf(script_cmd, "PKG_PREFIX=%s\nset -- %s-%s\n%s",
-
				  pkg_get(pkg, PKG_PREFIX), pkg_get(pkg, PKG_NAME),
-
				  pkg_get(pkg, PKG_VERSION), pkg_script_data(script));
-
				sbuf_finish(script_cmd);
-
				system(sbuf_data(script_cmd));
-
				break;
-
			default:
-
				/* ignored to prevent warning */
-
				break;
-
		}
-
	}
-

-
	sbuf_delete(script_cmd);
-

-
	return (EPKG_OK);
-
}
-

-
int
-
pkg_script_pre_upgrade(struct pkg *pkg)
-
{
-
	struct pkg_script *script = NULL;
-
	struct sbuf *script_cmd = sbuf_new_auto();
-

-
	while (pkg_scripts(pkg, &script) == EPKG_OK) {
-
		switch (pkg_script_type(script)) {
-
			case PKG_SCRIPT_UPGRADE:
-
				sbuf_reset(script_cmd);
-
				sbuf_printf(script_cmd, "PKG_PREFIX=%s\nset -- %s-%s PRE-UPGRADE\n%s",
-
				  pkg_get(pkg, PKG_PREFIX), pkg_get(pkg, PKG_NAME),
-
				  pkg_get(pkg, PKG_VERSION), pkg_script_data(script));
-
				sbuf_finish(script_cmd);
-
				system(sbuf_data(script_cmd));
-
				break;
-
			case PKG_SCRIPT_PRE_UPGRADE:
-
				sbuf_reset(script_cmd);
-
				sbuf_printf(script_cmd, "PKG_PREFIX=%s\nset -- %s-%s\n%s",
-
				  pkg_get(pkg, PKG_PREFIX), pkg_get(pkg, PKG_NAME),
-
				  pkg_get(pkg, PKG_VERSION), pkg_script_data(script));
-
				sbuf_finish(script_cmd);
-
				system(sbuf_data(script_cmd));
-
				break;
-
			default:
-
				/* ignored to prevent warning */
-
				break;
-
		}
-
	}
-

-
	sbuf_delete(script_cmd);
-

-
	return (EPKG_OK);
-
}
-

-
int
-
pkg_script_post_upgrade(struct pkg *pkg)
-
{
-
	struct pkg_script *script = NULL;
-
	struct sbuf *script_cmd = sbuf_new_auto();
-

-
	while (pkg_scripts(pkg, &script) == EPKG_OK) {
-
		switch (pkg_script_type(script)) {
-
			case PKG_SCRIPT_UPGRADE:
-
				sbuf_reset(script_cmd);
-
				sbuf_printf(script_cmd, "PKG_PREFIX=%s\nset -- %s-%s POST-UPGRADE\n%s",
-
				  pkg_get(pkg, PKG_PREFIX), pkg_get(pkg, PKG_NAME),
-
				  pkg_get(pkg, PKG_VERSION), pkg_script_data(script));
-
				sbuf_finish(script_cmd);
-
				system(sbuf_data(script_cmd));
-
				break;
-
			case PKG_SCRIPT_POST_UPGRADE:
-
				sbuf_reset(script_cmd);
-
				sbuf_printf(script_cmd, "PKG_PREFIX=%s\nset -- %s-%s\n%s",
-
				  pkg_get(pkg, PKG_PREFIX), pkg_get(pkg, PKG_NAME),
-
				  pkg_get(pkg, PKG_VERSION), pkg_script_data(script));
-
				sbuf_finish(script_cmd);
-
				system(sbuf_data(script_cmd));
-
				break;
-
			default:
-
				/* ignored to prevent warning */
-
				break;
-
		}
+
	size_t i;
+

+
	struct {
+
		const char *arg;
+
		const pkg_script_t b;
+
		const pkg_script_t a;
+
	} const map[] = {
+
		/* a implies b with argument arg */
+
		{"PRE-INSTALL",    PKG_SCRIPT_INSTALL,   PKG_SCRIPT_PRE_INSTALL},
+
		{"POST-INSTALL",   PKG_SCRIPT_INSTALL,   PKG_SCRIPT_POST_INSTALL},
+
		{"PRE-UPGRADE",    PKG_SCRIPT_UPGRADE,   PKG_SCRIPT_PRE_UPGRADE},
+
		{"POST-UPGRADE",   PKG_SCRIPT_UPGRADE,   PKG_SCRIPT_POST_UPGRADE},
+
		{"DEINSTALL",      PKG_SCRIPT_DEINSTALL, PKG_SCRIPT_PRE_DEINSTALL},
+
		{"POST-DEINSTALL", PKG_SCRIPT_DEINSTALL, PKG_SCRIPT_POST_DEINSTALL},
+
	};
+

+
	for (i = 0; i < sizeof(map) / sizeof(map[0]); i++) {
+
		if (map[i].a == type)
+
			break;
	}

-
	sbuf_delete(script_cmd);
-

-
	return (EPKG_OK);
-
}
-

-
int
-
pkg_script_pre_deinstall(struct pkg *pkg)
-
{
-
	struct pkg_script *script = NULL;
-
	struct sbuf *script_cmd = sbuf_new_auto();
+
	if (map[i].a != type)
+
		return (pkg_error_set(EPKG_FATAL, "bad type arg (%d)", type));

	while (pkg_scripts(pkg, &script) == EPKG_OK) {
-
		switch (pkg_script_type(script)) {
-
			case PKG_SCRIPT_DEINSTALL:
-
				sbuf_reset(script_cmd);
-
				sbuf_printf(script_cmd, "PKG_PREFIX=%s\nset -- %s-%s DEINSTALL\n%s",
-
				  pkg_get(pkg, PKG_PREFIX), pkg_get(pkg, PKG_NAME),
-
				  pkg_get(pkg, PKG_VERSION), pkg_script_data(script));
-
				sbuf_finish(script_cmd);
-
				system(sbuf_data(script_cmd));
-
				break;
-
			case PKG_SCRIPT_PRE_DEINSTALL:
-
				sbuf_reset(script_cmd);
-
				sbuf_printf(script_cmd, "PKG_PREFIX=%s\nset -- %s-%s\n%s",
-
				  pkg_get(pkg, PKG_PREFIX), pkg_get(pkg, PKG_NAME),
-
				  pkg_get(pkg, PKG_VERSION), pkg_script_data(script));
-
				sbuf_finish(script_cmd);
-
				system(sbuf_data(script_cmd));
-
				break;
-
			default:
-
				/* ignored to prevent warning */
-
				break;
-
		}
-
	}

-
	sbuf_delete(script_cmd);
-

-
	return (EPKG_OK);
-
}
-

-
int
-
pkg_script_post_deinstall(struct pkg *pkg)
-
{
-
	struct pkg_script *script = NULL;
-
	struct sbuf *script_cmd = sbuf_new_auto();
+
		stype = pkg_script_type(script);

-
	/* two loops because the order matters */
-
	while (pkg_scripts(pkg, &script) == EPKG_OK) {
-
		if (pkg_script_type(script) == PKG_SCRIPT_DEINSTALL) {
+
		if (stype == map[i].a || stype == map[i].b) {
			sbuf_reset(script_cmd);
-
			sbuf_printf(script_cmd, "PKG_PREFIX=%s\nset -- %s-%s POST-DEINSTALL\n%s",
-
					pkg_get(pkg, PKG_PREFIX), pkg_get(pkg, PKG_NAME),
-
					pkg_get(pkg, PKG_VERSION), pkg_script_data(script));
+
			sbuf_printf(script_cmd, "PKG_PREFIX=%s\nset -- %s-%s",
+
				pkg_get(pkg, PKG_PREFIX), pkg_get(pkg, PKG_NAME),
+
				pkg_get(pkg, PKG_VERSION));
+

+
			if (stype == map[i].b) {
+
				/* add arg **/
+
				sbuf_cat(script_cmd, " ");
+
				sbuf_cat(script_cmd, map[i].arg);
+
			}
+

+
			sbuf_cat(script_cmd, "\n");
+
			sbuf_cat(script_cmd, pkg_script_data(script));
			sbuf_finish(script_cmd);
			system(sbuf_data(script_cmd));
-
		}
-
	}

-
	while (pkg_scripts(pkg, &script) == EPKG_OK) {
-
		if (pkg_script_type(script) == PKG_SCRIPT_POST_DEINSTALL) {
-
			sbuf_reset(script_cmd);
-
			sbuf_printf(script_cmd, "PKG_PREFIX=%s\nset -- %s-%s\n%s",
-
					pkg_get(pkg, PKG_PREFIX), pkg_get(pkg, PKG_NAME),
-
					pkg_get(pkg, PKG_VERSION), pkg_script_data(script));
-
			sbuf_finish(script_cmd);
-
			system(sbuf_data(script_cmd));
		}
	}

modified pkg/add.c
@@ -13,13 +13,11 @@
#include "add.h"

static void
-
fetch_status(void *data, const char *url, off_t total, off_t done, time_t elapsed)
+
fetch_status(__unused void *data, const char *url, off_t total, off_t done,
+
			 __unused time_t elapsed)
{
	unsigned int percent;

-
	data = NULL;
-
	elapsed = 0;
-

	percent = ((float)done / (float)total) * 100;
	printf("\rFetching %s... %d%%", url, percent);

@@ -35,56 +33,91 @@ is_url(const char *pattern)
	if (strncmp(pattern, "http://", 7) == 0 ||
		strncmp(pattern, "https://", 8) == 0 ||
		strncmp(pattern, "ftp://", 6) == 0)
-
		return (0);
+
		return (EPKG_OK);

-
	return (-1);
+
	return (EPKG_FATAL);
}

-
void
-
usage_add(void)
+
static void
+
install_status(__unused void *data, struct pkg *pkg)
{
-
	fprintf(stderr, "usage: pkg add <pkg-name>\n");
-
	fprintf(stderr, "       pkg add <url>://<pkg-name>\n\n");
-
	fprintf(stderr, "For more information see 'pkg help add'.\n");
+
	const char *message;
+
	pkg_t type = pkg_type(pkg);
+

+
	if (type == PKG_REMOTE)
+
		printf("Installing %s-%s...", pkg_get(pkg, PKG_NAME),
+
			   pkg_get(pkg, PKG_VERSION));
+
	if (type == PKG_FILE) {
+
		printf(" Done!\n");
+
		message = pkg_get(pkg, PKG_MESSAGE);
+
		if (message != NULL)
+
			printf("----\n%s----\n", message);
+
	}
+
	fflush(stdout);
}

-
int
-
exec_add(int argc, char **argv)
+
static int
+
add_from_repo(const char *name)
{
-
	struct pkgdb *db = NULL;
	struct pkg *pkg = NULL;
-
	char *file;
-
	const char *message;
-
	int retcode = 0;
+
	struct pkgdb *db = NULL;
+
	struct pkg_jobs *jobs = NULL;
+
	int retcode = EPKG_OK;

-
	if (argc != 2) {
-
		usage_add();
-
		return (-1);
+
	if (pkgdb_open(&db, PKGDB_REMOTE) != EPKG_OK) {
+
		pkg_error_warn("can not open database");
+
		retcode = EPKG_FATAL;
+
		goto cleanup;
	}

-
	if (geteuid() != 0) {
-
		warnx("adding packages can only be done as root");
-
		return (EX_NOPERM);
+
	if (pkg_jobs_new(&jobs, db) != EPKG_OK) {
+
		pkg_error_warn("pkg_jobs_new()");
+
		retcode = EPKG_FATAL;
+
		goto cleanup;
+
	}
+

+
	if ((pkg = pkgdb_query_remote(db, name)) == NULL) {
+
		retcode = pkg_error_number();
+
		pkg_error_warn("can query the database");
+
		goto cleanup;
+
	}
+

+
	pkg_jobs_add(jobs, pkg);
+

+
	/* 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));
	}

+
	if (pkg_jobs_apply(jobs, NULL, fetch_status, install_status) != EPKG_OK)
+
		pkg_error_warn("can not install");
+

+
	cleanup:
+
	if (db != NULL)
+
		pkgdb_close(db);
+
	if (jobs != NULL)
+
		pkg_jobs_free(jobs);
+
	return (EPKG_OK);
+
}
+

+
static int
+
add_from_file(const char *file)
+
{
+
	struct pkgdb *db = NULL;
+
	struct pkg *pkg = NULL;
+
	const char *message;
+
	int retcode = EPKG_OK;
+

	if (pkgdb_open(&db, PKGDB_DEFAULT) != EPKG_OK) {
		pkg_error_warn("can not open database");
-
		return (1);
+
		retcode = EPKG_FATAL;
	}

-
	if (is_url(argv[1]) == 0) {
-
		asprintf(&file, "./%s", basename(argv[1]));
-
		if (pkg_fetch_file(argv[1], file, NULL, &fetch_status) != EPKG_OK) {
-
			pkg_error_warn("can not fetch %s", argv[1]);
-
			retcode = 1;
-
			goto cleanup;
-
		}
-
	} else
-
		file = argv[1];
-

	if (pkg_add(db, file, &pkg) != EPKG_OK) {
		pkg_error_warn("can not install %s", file);
-
		retcode = 1;
+
		retcode = EPKG_FATAL;
		goto cleanup;
	}

@@ -93,13 +126,58 @@ exec_add(int argc, char **argv)
		printf("%s", message);

	cleanup:
-

	if (db != NULL)
		pkgdb_close(db);
-

	if (pkg != NULL)
		pkg_free(pkg);

	return (retcode);
}

+
void
+
usage_add(void)
+
{
+
	fprintf(stderr, "usage: pkg add <pkg-name>\n");
+
	fprintf(stderr, "       pkg add <url>://<pkg-name>\n\n");
+
	fprintf(stderr, "For more information see 'pkg help add'.\n");
+
}
+

+
int
+
exec_add(int argc, char **argv)
+
{
+
	char *name;
+
	int retcode = 0;
+

+
	if (argc != 2) {
+
		usage_add();
+
		return (-1);
+
	}
+

+
	if (geteuid() != 0) {
+
		warnx("adding packages can only be done as root");
+
		return (EX_NOPERM);
+
	}
+

+
	if (is_url(argv[1]) == EPKG_OK) {
+
		asprintf(&name, "./%s", basename(argv[1]));
+
		if (pkg_fetch_file(argv[1], name, NULL, &fetch_status) != EPKG_OK) {
+
			pkg_error_warn("can not fetch %s", argv[1]);
+
			return (1);
+
		}
+
	} else
+
		name = argv[1];
+

+
	/* if it is a file  */
+
	if (name[0] == '/' || name[0] == '.') {
+
		if (access(name, F_OK) == 0) {
+
			retcode = add_from_file(name);
+
		} else {
+
			warn("%s", name);
+
		}
+
	} else {
+
		retcode = add_from_repo(name);
+
	}
+

+
	return (retcode == EPKG_OK ? 0 : 1);
+
}
+