Radish alpha
H
rad:z3QDZAW2FAfuLvihrhiyDC9fAD8G9
HardenedBSD Package Manager
Radicle
Git
Finish handling license, database bump to version 3
Baptiste Daroussin committed 14 years ago
commit 577f506e18256cb79b04d95b9452ecc9ef1fe9f7
parent cae2576
9 files changed +337 -25
modified libpkg/dump.c
@@ -15,7 +15,7 @@ pkgdb_dump(struct pkgdb *db, char *dest)
	int ret;
	int query_flags = PKG_LOAD_DEPS | PKG_LOAD_CONFLICTS | PKG_LOAD_FILES | PKG_LOAD_CATEGORIES |
					  PKG_LOAD_DIRS | PKG_LOAD_SCRIPTS | PKG_LOAD_OPTIONS |
-
					  PKG_LOAD_MTREE;
+
					  PKG_LOAD_MTREE | PKG_LOAD_LICENSES;

	packing_init(&pack, dest ? dest : "./pkgdump", TXZ);

modified libpkg/pkg.c
@@ -46,6 +46,7 @@ pkg_new(struct pkg **pkg, pkg_t type)
		(*pkg)->fields[fields[i].id].optional = fields[i].optional;
	}

+
	STAILQ_INIT(&(*pkg)->licenses);
	STAILQ_INIT(&(*pkg)->categories);
	STAILQ_INIT(&(*pkg)->deps);
	STAILQ_INIT(&(*pkg)->rdeps);
@@ -58,6 +59,7 @@ pkg_new(struct pkg **pkg, pkg_t type)

	(*pkg)->automatic = false;
	(*pkg)->type = type;
+
	(*pkg)->licenselogic = 1;

	return (EPKG_OK);
}
@@ -76,7 +78,9 @@ pkg_reset(struct pkg *pkg, pkg_t type)
	pkg->new_pkgsize = 0;
	pkg->flags = 0;
	pkg->rowid = 0;
+
	pkg->licenselogic = 1;

+
	pkg_freelicenses(pkg);
	pkg_freecategories(pkg);
	pkg_freedeps(pkg);
	pkg_freerdeps(pkg);
@@ -99,6 +103,7 @@ pkg_free(struct pkg *pkg)
	for (int i = 0; i < PKG_NUM_FIELDS; i++)
		sbuf_free(pkg->fields[i].value);

+
	pkg_freelicenses(pkg);
	pkg_freecategories(pkg);
	pkg_freedeps(pkg);
	pkg_freerdeps(pkg);
@@ -255,6 +260,37 @@ pkg_setnewpkgsize(struct pkg *pkg, int64_t size)
}

int
+
pkg_set_licenselogic(struct pkg *pkg, lic_t logic)
+
{
+
	pkg->licenselogic = logic;
+
	return (EPKG_OK);
+
}
+

+
lic_t
+
pkg_licenselogic(struct pkg *pkg)
+
{
+
	assert(pkg != NULL);
+

+
	return (pkg->licenselogic);
+
}
+

+
int
+
pkg_licenses(struct pkg *pkg, struct pkg_license **l)
+
{
+
	assert(pkg != NULL);
+

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

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

+
int
pkg_deps(struct pkg *pkg, struct pkg_dep **d)
{
	assert(pkg != NULL);
@@ -383,6 +419,28 @@ pkg_options(struct pkg *pkg, struct pkg_option **o)
}

int
+
pkg_addlicense(struct pkg *pkg, const char *name)
+
{
+
	struct pkg_license *l;
+

+
	assert(pkg != NULL);
+
	assert(name != NULL && name[0] != '\0');
+

+
	if (pkg->licenselogic == LICENSE_SINGLE && !STAILQ_EMPTY(&pkg->licenses)) {
+
		EMIT_PKG_ERROR("%s is said a have a single license which is already set", pkg_get(pkg, PKG_NAME));
+
		return (EPKG_FATAL);
+
	}
+

+
	pkg_license_new(&l);
+

+
	sbuf_set(&l->name, name);
+

+
	STAILQ_INSERT_TAIL(&pkg->licenses, l, next);
+

+
	return (EPKG_OK);
+
}
+

+
int
pkg_adddep(struct pkg *pkg, const char *name, const char *origin, const char *version)
{
	struct pkg_dep *d;
@@ -474,7 +532,9 @@ pkg_addcategory(struct pkg *pkg, const char *name)
	}

	pkg_category_new(&c);
-
	strlcpy(c->name, name, sizeof(c->name));
+

+
	sbuf_set(&c->name, name);
+

	STAILQ_INSERT_TAIL(&pkg->categories, c, next);

	return (EPKG_OK);
@@ -697,6 +757,20 @@ pkg_freefiles(struct pkg *pkg)
}

void
+
pkg_freelicenses(struct pkg *pkg)
+
{
+
	struct pkg_license *l;
+

+
	while (!STAILQ_EMPTY(&pkg->licenses)) {
+
		l = STAILQ_FIRST(&pkg->licenses);
+
		STAILQ_REMOVE_HEAD(&pkg->licenses, next);
+
		pkg_license_free(l);
+
	}
+

+
	pkg->flags &= ~PKG_LOAD_LICENSES;
+
}
+

+
void
pkg_freecategories(struct pkg *pkg)
{
	struct pkg_category *c;
modified libpkg/pkg.h
@@ -13,6 +13,7 @@ struct pkg_category;
struct pkg_conflict;
struct pkg_script;
struct pkg_option;
+
struct pkg_license;

struct pkgdb;
struct pkgdb_it;
@@ -24,6 +25,21 @@ struct pkg_repos;
struct pkg_repos_entry;

typedef enum {
+
	/**
+
	 * The license logic is OR (dual in the ports)
+
	 */
+
	LICENSE_OR='|',
+
	/**
+
	 * The license logic is AND (multi in the ports)
+
	 */
+
	LICENSE_AND='&',
+
	/**
+
	 * The licen logic un single (default in the ports)
+
	 */
+
	LICENSE_SINGLE=1
+
} lic_t;
+

+
typedef enum {
	PKGDB_DEFAULT=0,
	PKGDB_REMOTE
} pkgdb_t;
@@ -244,6 +260,13 @@ int pkg_dirs(struct pkg *pkg, struct pkg_dir **dir);
int pkg_categories(struct pkg *pkg, struct pkg_category **category);

/**
+
 * Iterates over the licenses of the package.
+
 * @param Must be set to NULL for the first call.
+
 * @return An error code.
+
 */
+
int pkg_licenses(struct pkg *pkg, struct pkg_license **license);
+

+
/**
 * Iterates over the conflicts of the package.
 * @param conflict Must be set to NULL for the first call.
 * @return An error code.
@@ -283,6 +306,16 @@ int pkg_setautomatic(struct pkg *pkg);
int pkg_isautomatic(struct pkg *pkg);

/**
+
 * set the logic for license combinaison
+
 */
+
int pkg_set_licenselogic(struct pkg *pkg, lic_t licenselogic);
+

+
/**
+
 * get the logic for license combinaison
+
 */
+
lic_t pkg_licenselogic(struct pkg *pkg);
+

+
/**
 * Set the uncompressed size of the package.
 * @return An error code.
 */
@@ -350,6 +383,12 @@ int pkg_adddir_attr(struct pkg *pkg, const char *path, const char *uname, const
int pkg_addcategory(struct pkg *pkg, const char *name);

/**
+
 * Add a license
+
 * @return An error code.
+
 */
+
int pkg_addlicense(struct pkg *pkg, const char *name);
+

+
/**
 * Allocate a new struct pkg_conflict and add it to the conflicts of pkg.
 * @return An error code.
 */
@@ -404,6 +443,8 @@ const char *pkg_dir_path(struct pkg_dir *);

const char *pkg_category_name(struct pkg_category *);

+
const char *pkg_license_name(struct pkg_license *);
+

/* pkg_conflict */
const char * pkg_conflict_glob(struct pkg_conflict *);

@@ -510,6 +551,7 @@ struct pkgdb_it * pkgdb_query_which(struct pkgdb *db, const char *path);
#define PKG_LOAD_MTREE (1<<7)
#define PKG_LOAD_DIRS (1<<8)
#define PKG_LOAD_CATEGORIES (1<<9)
+
#define PKG_LOAD_LICENSES (1<<10)

#define REPO_SEARCH_NAME 0
#define REPO_SEARCH_COMMENT (1<<0)
@@ -539,6 +581,7 @@ int pkgdb_loadscripts(struct pkgdb *db, struct pkg *pkg);
int pkgdb_loadoptions(struct pkgdb *db, struct pkg *pkg);
int pkgdb_loadmtree(struct pkgdb *db, struct pkg *pkg);
int pkgdb_loadcategory(struct pkgdb *db, struct pkg *pkg);
+
int pkgdb_loadlicense(struct pkgdb *db, struct pkg *pkg);

/**
 * Compact the database to save space.
modified libpkg/pkg_attributes.c
@@ -113,12 +113,17 @@ pkg_category_new(struct pkg_category **c)
const char *
pkg_category_name(struct pkg_category *c)
{
-
	return (c->name);
+
	return (sbuf_get(c->name));
}

void
pkg_category_free(struct pkg_category *c)
{
+

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

+
	sbuf_free(c->name);
	free(c);
}

@@ -154,6 +159,37 @@ pkg_conflict_glob(struct pkg_conflict *c)
}

/*
+
 * License
+
 */
+
int
+
pkg_license_new(struct pkg_license **l)
+
{
+
	if ((*l = calloc(1, sizeof(struct pkg_license))) == NULL) {
+
		EMIT_ERRNO("calloc", "pkg_license");
+
		return (EPKG_FATAL);
+
	}
+

+
	return (EPKG_OK);
+
}
+

+
void
+
pkg_license_free(struct pkg_license *l)
+
{
+
	if (l == NULL)
+
		return;
+

+
	sbuf_free(l->name);
+
	free(l);
+
}
+

+
const char *
+
pkg_license_name(struct pkg_license *l)
+
{
+
	return (sbuf_get(l->name));
+
}
+

+

+
/*
 * Script
 */

modified libpkg/pkg_create.c
@@ -151,7 +151,7 @@ pkg_create_installed(const char *outdir, pkg_formats format, const char *rootdir
	struct packing *pkg_archive;
	int required_flags = PKG_LOAD_DEPS | PKG_LOAD_CONFLICTS | PKG_LOAD_FILES | PKG_LOAD_CATEGORIES |
						 PKG_LOAD_DIRS | PKG_LOAD_SCRIPTS | PKG_LOAD_OPTIONS |
-
						 PKG_LOAD_MTREE;
+
						 PKG_LOAD_MTREE | PKG_LOAD_LICENSES;

	assert(pkg->type == PKG_INSTALLED);

modified libpkg/pkg_manifest.c
@@ -23,6 +23,8 @@
#define PKG_FLATSIZE -6
#define PKG_SCRIPTS -7
#define PKG_CATEGORIES -8
+
#define PKG_LICENSELOGIC -9
+
#define PKG_LICENSES -10

static void parse_mapping(struct pkg *, yaml_node_pair_t *, yaml_document_t *, int);
static void parse_node(struct pkg *, yaml_node_t *, yaml_document_t *, int);
@@ -45,6 +47,8 @@ static struct manifest_key {
	{ "files", PKG_FILES},
	{ "dirs", PKG_DIRS},
	{ "flatsize", PKG_FLATSIZE},
+
	{ "licenselogic", PKG_LICENSELOGIC },
+
	{ "licenses", PKG_LICENSES },
	{ "desc", PKG_DESC },
	{ "scripts", PKG_SCRIPTS},
	{ "message", PKG_MESSAGE},
@@ -191,20 +195,33 @@ parse_mapping(struct pkg *pkg, yaml_node_pair_t *pair, yaml_document_t *document
				if (val->data.scalar.length <= 0)
					break;
				type = manifest_type(key->data.scalar.value);
-
				if (type == -1) {
-
					EMIT_PKG_ERROR("Unknown line: (%s: %s)\n",
-
								   key->data.scalar.value,
-
								   val->data.scalar.value);
-
				} else if (type == PKG_FLATSIZE)
-
					pkg_setflatsize(pkg, strtoimax(val->data.scalar.value, NULL, 10));
-
				else {
-
					while (val->data.scalar.length > 0 &&
-
						   val->data.scalar.value[val->data.scalar.length - 1] == '\n') {
-
						val->data.scalar.value[val->data.scalar.length - 1] = '\0';
-
						val->data.scalar.length--;
-
					}
-

-
					pkg_set(pkg, type, val->data.scalar.value);
+
				switch (type) {
+
					case -1:
+
						EMIT_PKG_ERROR("Unknown line: (%s: %s)\n",
+
								key->data.scalar.value,
+
								val->data.scalar.value);
+
						break;
+
					case PKG_FLATSIZE:
+
						pkg_setflatsize(pkg, strtoimax(val->data.scalar.value, NULL, 10));
+
						break;
+
					case PKG_LICENSELOGIC:
+
						if (!strcmp(val->data.scalar.value, "single"))
+
							pkg_set_licenselogic(pkg, LICENSE_SINGLE);
+
						else if ( !strcmp(val->data.scalar.value, "and"))
+
							pkg_set_licenselogic(pkg, LICENSE_AND);
+
						else if ( !strcmp(val->data.scalar.value, "or"))
+
							pkg_set_licenselogic(pkg, LICENSE_OR);
+
						else
+
							EMIT_PKG_ERROR("Unknown license logic: %s", val->data.scalar.value);
+
						break;
+
					default:
+
						while (val->data.scalar.length > 0 &&
+
								val->data.scalar.value[val->data.scalar.length - 1] == '\n') {
+
							val->data.scalar.value[val->data.scalar.length - 1] = '\0';
+
							val->data.scalar.length--;
+
						}
+
						pkg_set(pkg, type, val->data.scalar.value);
+
						break;
				}
			} else {
				parse_node(pkg, val, document, type);
@@ -284,6 +301,13 @@ parse_node(struct pkg *pkg, yaml_node_t *node, yaml_document_t *document, int pk
						++item;
					}
					break;
+
				case PKG_LICENSES:
+
					item = node->data.sequence.items.start;
+
					while (item < node->data.sequence.items.top) {
+
						nd = yaml_document_get_node(document, *item);
+
						pkg_addlicense(pkg, nd->data.scalar.value);
+
						++item;
+
					}
			}
			break;
		case YAML_MAPPING_NODE:
@@ -344,6 +368,7 @@ pkg_emit_manifest(struct pkg *pkg, char **dest)
	struct pkg_dir *dir = NULL;
	struct pkg_script *script = NULL;
	struct pkg_category *category = NULL;
+
	struct pkg_license *license = NULL;
	int rc = EPKG_OK;
	int mapping;
	int depsmap = -1;
@@ -354,6 +379,7 @@ pkg_emit_manifest(struct pkg *pkg, char **dest)
	int options = -1;
	int scripts = -1;
	int categories = -1;
+
	int licenses = -1;
	const char *script_types;
	struct sbuf *destbuf = sbuf_new_auto();

@@ -380,6 +406,28 @@ pkg_emit_manifest(struct pkg *pkg, char **dest)
	manifest_append_kv(mapping, "www", pkg_get(pkg, PKG_WWW));
	manifest_append_kv(mapping, "maintainer", pkg_get(pkg, PKG_MAINTAINER));
	manifest_append_kv(mapping, "prefix", pkg_get(pkg, PKG_PREFIX));
+
	switch (pkg_licenselogic(pkg)) {
+
		case LICENSE_SINGLE:
+
			manifest_append_kv(mapping, "licenselogic", "single");
+
			break;
+
		case LICENSE_AND:
+
			manifest_append_kv(mapping, "licenselogic", "and");
+
			break;
+
		case LICENSE_OR:
+
			manifest_append_kv(mapping, "licenselogic", "or");
+
			break;
+
	}
+

+
	while (pkg_licenses(pkg, &license) == EPKG_OK) {
+
		if (licenses == -1) {
+
			licenses = yaml_document_add_sequence(&doc, NULL, YAML_FLOW_SEQUENCE_STYLE);
+
			yaml_document_append_mapping_pair(&doc, mapping,
+
					yaml_document_add_scalar(&doc, NULL, __DECONST(yaml_char_t*, "licenses"), 8, YAML_PLAIN_SCALAR_STYLE), licenses);
+
		}
+
		yaml_document_append_sequence_item(&doc, licenses,
+
				yaml_document_add_scalar(&doc, NULL, __DECONST(yaml_char_t*, pkg_license_name(license)), strlen(pkg_license_name(license)), YAML_PLAIN_SCALAR_STYLE));
+
	}
+

	snprintf(tmpbuf, BUFSIZ, "%" PRId64, pkg_flatsize(pkg));
	manifest_append_kv(mapping, "flatsize", tmpbuf);
	manifest_append_kv_literal(mapping, "desc", pkg_get(pkg, PKG_DESC));
modified libpkg/pkg_private.h
@@ -28,6 +28,7 @@ struct pkg {
	int64_t new_flatsize;
	int64_t new_pkgsize;
	STAILQ_HEAD(categories, pkg_category) categories;
+
	STAILQ_HEAD(licenses, pkg_license) licenses;
	STAILQ_HEAD(deps, pkg_dep) deps;
	STAILQ_HEAD(rdeps, pkg_dep) rdeps;
	STAILQ_HEAD(files, pkg_file) files;
@@ -38,6 +39,7 @@ struct pkg {
	STAILQ_HEAD(repos_entry, pkg_repos_entry) repos;
	int flags;
	int64_t rowid;
+
	lic_t licenselogic;
	pkg_t type;
	STAILQ_ENTRY(pkg) next;
};
@@ -49,8 +51,13 @@ struct pkg_dep {
	STAILQ_ENTRY(pkg_dep) next;
};

+
struct pkg_license {
+
	struct sbuf *name;
+
	STAILQ_ENTRY(pkg_license) next;
+
};
+

struct pkg_category {
-
	char name[BUFSIZ];
+
	struct sbuf *name;
	STAILQ_ENTRY(pkg_category) next;
};

@@ -122,6 +129,7 @@ struct pkg_repos {
};

int pkg_open2(struct pkg **p, struct archive **a, struct archive_entry **ae, const char *path);
+
void pkg_freelicenses(struct pkg *pkg);
void pkg_freecategories(struct pkg *pkg);
void pkg_freedeps(struct pkg *pkg);
void pkg_freerdeps(struct pkg *pkg);
@@ -143,6 +151,9 @@ void pkg_dir_free(struct pkg_dir *);
int pkg_category_new(struct pkg_category **);
void pkg_category_free(struct pkg_category *);

+
int pkg_license_new(struct pkg_license **);
+
void pkg_license_free(struct pkg_license *);
+

int pkg_conflict_new(struct pkg_conflict **);
void pkg_conflict_free(struct pkg_conflict *);

modified libpkg/pkgdb.c
@@ -17,7 +17,7 @@
#include "pkgdb.h"
#include "pkg_util.h"

-
#define DBVERSION 1
+
#define DBVERSION 3

static struct pkgdb_it * pkgdb_it_new(struct pkgdb *, sqlite3_stmt *, int);
static void pkgdb_regex(sqlite3_context *, int, sqlite3_value **, int);
@@ -150,13 +150,34 @@ pkgdb_upgrade(sqlite3 *sdb)
		sbuf_finish(sql);
	}

+
	if (db_version < 2) {
+
		sbuf_cat(sql, "ALTER TABLE packages ADD licenselogic INTEGER NOT NULL DEFAULT(1);"
+
				"PRAGMA user_version = 2;");
+
		sbuf_finish(sql);
+
	}
+
	if (db_version < 3) {
+
		sbuf_cat(sql, "DROP VIEW pkg_licenses;"
+
				"ALTER TABLE licenses RENAME TO todelete;"
+
				"CREATE TABLE licenses (id INTERGER PRIMARY KEY, name TEXT NOT NULL UNIQUE);"
+
				"INSERT INTO licenses(id, name) SELECT id, license FROM todelete;"
+
				"CREATE VIEW pkg_licenses AS SELECT origin, licenses.name FROM packages "
+
				"INNER JOIN pkg_licenses_assoc ON packages.id = pkg_licenses_assoc.package_id "
+
				"INNER JOIN licenses ON pkg_licenses_assoc.license_id = licenses.id;"
+
				"DROP TABLE todelete;"
+
				"PRAGMA user_version = 3;"
+
			);
+
		sbuf_finish(sql);
+
	}

	if (sqlite3_exec(sdb, sbuf_data(sql), NULL, NULL, &errmsg) != SQLITE_OK) {
		EMIT_PKG_ERROR("sqlite: %s", errmsg);
+
		sbuf_delete(sql);
		sqlite3_free(errmsg);
		return (EPKG_FATAL);
	}

+
	sbuf_delete(sql);
+

	return (EPKG_OK);

}
@@ -197,6 +218,7 @@ pkgdb_init(sqlite3 *sdb)
		"prefix TEXT NOT NULL,"
		"flatsize INTEGER NOT NULL,"
		"automatic INTEGER NOT NULL,"
+
		"licenselogic INTEGER NOT NULL,"
		"pkg_format_version INTEGER"
	");"
	"CREATE TABLE mtree ("
@@ -298,7 +320,7 @@ pkgdb_init(sqlite3 *sdb)
	"END;"
	"CREATE TABLE licenses ("
		"id INTEGER PRIMARY KEY, "
-
		"license TEXT NOT NULL UNIQUE "
+
		"name TEXT NOT NULL UNIQUE "
	");"
	"CREATE TABLE pkg_licenses_assoc ("
		"package_id INTEGER REFERENCES packages(id) ON DELETE CASCADE"
@@ -317,7 +339,7 @@ pkgdb_init(sqlite3 *sdb)
			"((SELECT id FROM packages where origin = NEW.origin), "
			"(SELECT id FROM categories WHERE name = NEW.name));"
	"END;"
-
	"PRAGMA user_version = 1;"
+
	"PRAGMA user_version = 3;"
	;

	if (sqlite3_exec(sdb, sql, NULL, NULL, &errmsg) != SQLITE_OK) {
@@ -486,6 +508,8 @@ pkgdb_it_next(struct pkgdb_it *it, struct pkg **pkg_p, int flags)
		pkg_set(pkg, PKG_WWW, sqlite3_column_text(it->stmt, 10));
		pkg_set(pkg, PKG_PREFIX, sqlite3_column_text(it->stmt, 11));
		pkg_setflatsize(pkg, sqlite3_column_int64(it->stmt, 12));
+
		if (it->type != PKG_REMOTE && it->type != PKG_UPGRADE)
+
			pkg_set_licenselogic(pkg, sqlite3_column_int64(it->stmt, 13));

		if (it->type == PKG_REMOTE) {
			pkg->type = PKG_REMOTE;
@@ -540,6 +564,10 @@ pkgdb_it_next(struct pkgdb_it *it, struct pkg **pkg_p, int flags)
			if ((ret = pkgdb_loadcategory(it->db, pkg)) != EPKG_OK)
				return (ret);

+
		if (flags & PKG_LOAD_LICENSES)
+
			if ((ret == pkgdb_loadlicense(it->db, pkg)) != EPKG_OK)
+
				return (ret);
+

		return (EPKG_OK);
	case SQLITE_DONE:
		return (EPKG_END);
@@ -608,7 +636,7 @@ pkgdb_query(struct pkgdb *db, const char *pattern, match_t match)
	snprintf(sql, sizeof(sql),
			"SELECT p.rowid, p.origin, p.name, p.version, p.comment, p.desc, "
				"p.message, p.arch, p.osversion, p.maintainer, p.www, "
-
				"p.prefix, p.flatsize "
+
				"p.prefix, p.flatsize, p.licenselogic "
			"FROM packages AS p%s "
			"ORDER BY p.name;", comp);

@@ -870,6 +898,43 @@ pkgdb_loaddirs(struct pkgdb *db, struct pkg *pkg)
}

int
+
pkgdb_loadlicense(struct pkgdb *db, struct pkg *pkg)
+
{
+
	sqlite3_stmt *stmt;
+
	int ret;
+
	const char sql[] = ""
+
		"SELECT name "
+
		"FROM pkg_licenses "
+
		"WHERE origin = ?1 "
+
		"ORDER by name DESC";
+

+
	if (pkg->flags & PKG_LOAD_LICENSES)
+
		return (EPKG_OK);
+

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

+
	sqlite3_bind_text(stmt, 1, pkg_get(pkg, PKG_ORIGIN), -1, SQLITE_STATIC);
+

+
	while (( ret = sqlite3_step(stmt)) == SQLITE_ROW) {
+
		pkg_addlicense(pkg, sqlite3_column_text(stmt, 0));
+
	}
+

+
	sqlite3_finalize(stmt);
+

+
	if (ret != SQLITE_DONE) {
+
		pkg_freelicenses(pkg);
+
		ERROR_SQLITE(db->sqlite);
+
		return (EPKG_FATAL);
+
	}
+

+
	pkg->flags |= PKG_LOAD_LICENSES;
+
	return (EPKG_OK);
+
}
+

+
int
pkgdb_loadcategory(struct pkgdb *db, struct pkg *pkg)
{
	sqlite3_stmt *stmt;
@@ -1081,6 +1146,7 @@ pkgdb_register_pkg(struct pkgdb *db, struct pkg *pkg)
	struct pkg_script *script = NULL;
	struct pkg_option *option = NULL;
	struct pkg_category *category = NULL;
+
	struct pkg_license *license = NULL;

	sqlite3 *s;
	sqlite3_stmt *stmt_pkg = NULL;
@@ -1092,6 +1158,7 @@ pkgdb_register_pkg(struct pkgdb *db, struct pkg *pkg)
	sqlite3_stmt *stmt_option = NULL;
	sqlite3_stmt *stmt_dirs = NULL;
	sqlite3_stmt *stmt_cat = NULL;
+
	sqlite3_stmt *stmt_lic = NULL;

	int ret;
	int retcode = EPKG_FATAL;
@@ -1104,7 +1171,7 @@ pkgdb_register_pkg(struct pkgdb *db, struct pkg *pkg)
		"INSERT INTO pkg_mtree( "
			"origin, name, version, comment, desc, mtree, message, arch, "
			"osversion, maintainer, www, prefix, flatsize, automatic) "
-
		"VALUES( ?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11, ?12, ?13, ?14);";
+
		"VALUES( ?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11, ?12, ?13, ?14, ?15);";
	const char sql_sel_pkg[] = ""
		"SELECT id FROM packages "
		"WHERE origin = ?1;";
@@ -1129,6 +1196,9 @@ pkgdb_register_pkg(struct pkgdb *db, struct pkg *pkg)
	const char sql_category[] = ""
		"INSERT INTO pkg_categories(origin, name) "
		"VALUES (?1, ?2);";
+
	const char sql_license[] = ""
+
		"INSERT INTO pkg_licenses(origin, name) "
+
		"VALES (?1, ?2);";

	if (pkgdb_has_flag(db, PKGDB_FLAG_IN_FLIGHT)) {
		EMIT_PKG_ERROR("%s", "tried to register a package with an in-flight SQL command");
@@ -1165,6 +1235,7 @@ pkgdb_register_pkg(struct pkgdb *db, struct pkg *pkg)
	sqlite3_bind_text(stmt_pkg, 12, pkg_get(pkg, PKG_PREFIX), -1, SQLITE_STATIC);
	sqlite3_bind_int64(stmt_pkg, 13, pkg_flatsize(pkg));
	sqlite3_bind_int(stmt_pkg, 14, pkg_isautomatic(pkg));
+
	sqlite3_bind_int64(stmt_pkg, 15, pkg_licenselogic(pkg));

	if ((ret = sqlite3_step(stmt_pkg)) != SQLITE_DONE) {
		ERROR_SQLITE(s);
@@ -1303,6 +1374,28 @@ pkgdb_register_pkg(struct pkgdb *db, struct pkg *pkg)
	}

	/*
+
	 * Insert licenses
+
	 */
+
	if (sqlite3_prepare_v2(s, sql_license, -1, &stmt_lic, NULL) != SQLITE_OK) {
+
		ERROR_SQLITE(s);
+
		goto cleanup;
+
	}
+

+
	while (pkg_licenses(pkg, &license) == EPKG_OK) {
+
		sqlite3_bind_text(stmt_lic, 1, pkg_get(pkg, PKG_ORIGIN), -1, SQLITE_STATIC);
+
		sqlite3_bind_text(stmt_lic, 2, pkg_license_name(license), -1, SQLITE_STATIC);
+

+
		if ((ret = sqlite3_step(stmt_lic)) != SQLITE_DONE) {
+
			if (ret == SQLITE_CONSTRAINT) {
+
				EMIT_PKG_ERROR("sqlite: constraint violation on licenses.name: %s",
+
						pkg_license_name(license));
+
			} else
+
				ERROR_SQLITE(s);
+
			goto cleanup;
+
		}
+
	}
+

+
	/*
	 * Insert scripts
	 */

@@ -1441,6 +1534,13 @@ pkgdb_unregister_pkg(struct pkgdb *db, const char *origin)
		return (EPKG_FATAL);
	}

+
	ret = sqlite3_exec(db->sqlite, "DELETE from licenses WHERE id NOT IN (SELECT DISTINCT license_id FROM pkg_licenses_assoc);", NULL, NULL, &errmsg);
+
	if (ret != SQLITE_OK) {
+
		EMIT_PKG_ERROR("sqlite: %s", errmsg);
+
		sqlite3_free(errmsg);
+
		return (EPKG_FATAL);
+
	}
+

	return (EPKG_OK);
}

modified pkg/create.c
@@ -28,7 +28,7 @@ pkg_create_matches(int argc, char **argv, match_t match, pkg_formats fmt, const
	struct pkg *pkg = NULL;
	int query_flags = PKG_LOAD_DEPS | PKG_LOAD_CONFLICTS | PKG_LOAD_FILES | PKG_LOAD_CATEGORIES |
					  PKG_LOAD_DIRS | PKG_LOAD_SCRIPTS | PKG_LOAD_OPTIONS |
-
					  PKG_LOAD_MTREE;
+
					  PKG_LOAD_MTREE | PKG_LOAD_LICENSES;

	if (pkgdb_open(&db, PKGDB_DEFAULT, "local.sqlite") != EPKG_OK) {
		pkgdb_close(db);