Radish alpha
H
rad:z3QDZAW2FAfuLvihrhiyDC9fAD8G9
HardenedBSD Package Manager
Radicle
Git
Real support for categories
Baptiste Daroussin committed 14 years ago
commit cf0dc8f3213bddf731c0691a95a5cb89146b82af
parent 135214e
9 files changed +199 -13
modified libpkg/dump.c
@@ -13,7 +13,7 @@ pkgdb_dump(struct pkgdb *db, char *dest)
	struct packing *pack;
	char *m;
	int ret;
-
	int query_flags = PKG_LOAD_DEPS | PKG_LOAD_CONFLICTS | PKG_LOAD_FILES |
+
	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;

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)->categories);
	STAILQ_INIT(&(*pkg)->deps);
	STAILQ_INIT(&(*pkg)->rdeps);
	STAILQ_INIT(&(*pkg)->files);
@@ -75,6 +76,7 @@ pkg_reset(struct pkg *pkg, pkg_t type)
	pkg->flags = 0;
	pkg->rowid = 0;

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

+
	pkg_freecategories(pkg);
	pkg_freedeps(pkg);
	pkg_freerdeps(pkg);
	pkg_freefiles(pkg);
@@ -295,6 +298,22 @@ pkg_files(struct pkg *pkg, struct pkg_file **f)
}

int
+
pkg_categories(struct pkg *pkg, struct pkg_category **c)
+
{
+
	assert(pkg != NULL);
+

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

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

+
int
pkg_dirs(struct pkg *pkg, struct pkg_dir **d)
{
	assert(pkg != NULL);
@@ -421,6 +440,28 @@ pkg_addfile(struct pkg *pkg, const char *path, const char *sha256)
}

int
+
pkg_addcategory(struct pkg *pkg, const char *name)
+
{
+
	struct pkg_category *c = NULL;
+

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

+
	while (pkg_categories(pkg, &c) == EPKG_OK) {
+
		if (strcmp(name, pkg_category_name(c)) == 0) {
+
			EMIT_PKG_ERROR("Duplicate category listing: %s, ignoring", name);
+
			return (EPKG_OK);
+
		}
+
	}
+

+
	pkg_category_new(&c);
+
	strlcpy(c->name, name, sizeof(c->name));
+
	STAILQ_INSERT_TAIL(&pkg->categories, c, next);
+

+
	return (EPKG_OK);
+
}
+

+
int
pkg_adddir(struct pkg *pkg, const char *path)
{
	struct pkg_dir *d = NULL;
@@ -623,6 +664,20 @@ pkg_freefiles(struct pkg *pkg)
}

void
+
pkg_freecategories(struct pkg *pkg)
+
{
+
	struct pkg_category *c;
+

+
	while (!STAILQ_EMPTY(&pkg->categories)) {
+
		c = STAILQ_FIRST(&pkg->categories);
+
		STAILQ_REMOVE_HEAD(&pkg->categories, next);
+
		pkg_category_free(c);
+
	}
+

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

+
void
pkg_freedirs(struct pkg *pkg)
{
	struct pkg_dir *d;
modified libpkg/pkg.h
@@ -9,6 +9,7 @@ struct pkg;
struct pkg_dep;
struct pkg_file;
struct pkg_dir;
+
struct pkg_category;
struct pkg_conflict;
struct pkg_script;
struct pkg_option;
@@ -232,6 +233,13 @@ int pkg_files(struct pkg *, struct pkg_file **file);
int pkg_dirs(struct pkg *pkg, struct pkg_dir **dir);

/**
+
 * Iterates over the categories of the package.
+
 * @param Must be set to NULL for the first call.
+
 * @return An error code
+
 */
+
int pkg_categories(struct pkg *pkg, struct pkg_category **category);
+

+
/**
 * Iterates over the conflicts of the package.
 * @param conflict Must be set to NULL for the first call.
 * @return An error code.
@@ -311,6 +319,12 @@ int pkg_addfile(struct pkg *pkg, const char *path, const char *sha256);
int pkg_adddir(struct pkg *pkg, const char *path);

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

+
/**
 * Allocate a new struct pkg_conflict and add it to the conflicts of pkg.
 * @return An error code.
 */
@@ -363,6 +377,8 @@ const char * pkg_file_sha256(struct pkg_file *);

const char *pkg_dir_path(struct pkg_dir *);

+
const char *pkg_category_name(struct pkg_category *);
+

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

@@ -467,6 +483,7 @@ struct pkgdb_it * pkgdb_query_which(struct pkgdb *db, const char *path);
#define PKG_LOAD_OPTIONS (1<<6)
#define PKG_LOAD_MTREE (1<<7)
#define PKG_LOAD_DIRS (1<<8)
+
#define PKG_LOAD_CATEGORIES (1<<9)

#define REPO_SEARCH_NAME 0
#define REPO_SEARCH_COMMENT (1<<0)
@@ -495,6 +512,7 @@ int pkgdb_loaddirs(struct pkgdb *db, struct pkg *pkg);
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);

/**
 * Compact the database to save space.
modified libpkg/pkg_attributes.c
@@ -99,6 +99,27 @@ pkg_dir_path(struct pkg_dir *d)
	return (d->path);
}

+
int
+
pkg_category_new(struct pkg_category **c)
+
{
+
	if (( *c = calloc(1, sizeof(struct pkg_category))) == NULL)
+
		return (EPKG_FATAL);
+

+
	return (EPKG_OK);
+
}
+

+
const char *
+
pkg_category_name(struct pkg_category *c)
+
{
+
	return (c->name);
+
}
+

+
void
+
pkg_category_free(struct pkg_category *c)
+
{
+
	free(c);
+
}
+

/*
 * Conflict
 */
modified libpkg/pkg_create.c
@@ -119,7 +119,7 @@ int
pkg_create_installed(const char *outdir, pkg_formats format, const char *rootdir, struct pkg *pkg)
{
	struct packing *pkg_archive;
-
	int required_flags = PKG_LOAD_DEPS | PKG_LOAD_CONFLICTS | PKG_LOAD_FILES |
+
	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;

modified libpkg/pkg_manifest.c
@@ -22,6 +22,7 @@
#define PKG_DIRS -5
#define PKG_FLATSIZE -6
#define PKG_SCRIPTS -7
+
#define PKG_CATEGORIES -8

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);
@@ -200,6 +201,15 @@ parse_node(struct pkg *pkg, yaml_node_t *node, yaml_document_t *document, int pk
					}

					break;
+
				case PKG_CATEGORIES:
+
					item = node->data.sequence.items.start;
+
					while (item < node->data.sequence.items.top) {
+
						nd = yaml_document_get_node(document, *item);
+
						pkg_addcategory(pkg, nd->data.scalar.value);
+
						++item;
+
					}
+

+
					break;
				case PKG_CONFLICTS:
					item = node->data.sequence.items.start;
					while (item < node->data.sequence.items.top) {
@@ -267,6 +277,7 @@ pkg_emit_manifest(struct pkg *pkg, char **dest)
	struct pkg_file *file = NULL;
	struct pkg_dir *dir = NULL;
	struct pkg_script *script = NULL;
+
	struct pkg_category *category = NULL;
	int rc = EPKG_OK;
	int mapping;
	int depsmap = -1;
@@ -276,6 +287,7 @@ pkg_emit_manifest(struct pkg *pkg, char **dest)
	int dirs = -1;
	int options = -1;
	int scripts = -1;
+
	int categories = -1;
	const char *script_types;
	struct sbuf *destbuf = sbuf_new_auto();

@@ -365,6 +377,17 @@ pkg_emit_manifest(struct pkg *pkg, char **dest)
				yaml_document_add_scalar(&doc, NULL, __DECONST(yaml_char_t*, pkg_dir_path(dir)), strlen(pkg_dir_path(dir)), YAML_PLAIN_SCALAR_STYLE));
	}

+
	while (pkg_categories(pkg, &category) == EPKG_OK) {
+
		if (categories == -1) {
+
			categories = yaml_document_add_sequence(&doc, NULL, YAML_BLOCK_SEQUENCE_STYLE);
+
			yaml_document_append_mapping_pair(&doc, mapping,
+
					yaml_document_add_scalar(&doc, NULL, __DECONST(yaml_char_t*, "categories"), 10, YAML_PLAIN_SCALAR_STYLE),
+
					dirs);
+
		}
+
		yaml_document_append_sequence_item(&doc, categories,
+
				yaml_document_add_scalar(&doc, NULL, __DECONST(yaml_char_t*, pkg_category_name(category)), strlen(pkg_category_name(category)), YAML_PLAIN_SCALAR_STYLE));
+
	}
+

	while (pkg_scripts(pkg, &script) == EPKG_OK) {
		if (scripts == -1) {
			scripts = yaml_document_add_mapping(&doc, NULL, YAML_BLOCK_MAPPING_STYLE);
modified libpkg/pkg_private.h
@@ -27,6 +27,7 @@ struct pkg {
	int64_t flatsize;
	int64_t new_flatsize;
	int64_t new_pkgsize;
+
	STAILQ_HEAD(categories, pkg_category) categories;
	STAILQ_HEAD(deps, pkg_dep) deps;
	STAILQ_HEAD(rdeps, pkg_dep) rdeps;
	STAILQ_HEAD(files, pkg_file) files;
@@ -47,6 +48,11 @@ struct pkg_dep {
	STAILQ_ENTRY(pkg_dep) next;
};

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

struct pkg_file {
	char path[MAXPATHLEN];
	char sha256[65];
@@ -93,6 +99,7 @@ struct pkg_jobs_node {
};

int pkg_open2(struct pkg **p, struct archive **a, struct archive_entry **ae, const char *path);
+
void pkg_freecategories(struct pkg *pkg);
void pkg_freedeps(struct pkg *pkg);
void pkg_freerdeps(struct pkg *pkg);
void pkg_freefiles(struct pkg *pkg);
@@ -110,6 +117,9 @@ void pkg_file_free(struct pkg_file *);
int pkg_dir_new(struct pkg_dir **);
void pkg_dir_free(struct pkg_dir *);

+
int pkg_category_new(struct pkg_category **);
+
void pkg_category_free(struct pkg_category *);
+

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

modified libpkg/pkgdb.c
@@ -127,8 +127,6 @@ pkgdb_init(sqlite3 *sdb)
		"origin TEXT UNIQUE NOT NULL,"
		"name TEXT NOT NULL,"
		"version TEXT NOT NULL,"
-
		"category_id INTEGER REFERENCES categories(id) ON DELETE RESTRICT"
-
			" ON UPDATE CASCADE,"
		"comment TEXT NOT NULL,"
		"desc TEXT NOT NULL,"
		"mtree_id INTEGER REFERENCES mtree(id) ON DELETE RESTRICT"
@@ -143,13 +141,6 @@ pkgdb_init(sqlite3 *sdb)
		"automatic INTEGER NOT NULL,"
		"pkg_format_version INTEGER"
	");"
-
	"CREATE TABLE categories ("
-
		"id INTEGER PRIMARY KEY,"
-
		"name TEXT UNIQUE"
-
	");"
-
	"CREATE TRIGGER clean_categories AFTER DELETE ON packages BEGIN "
-
		"DELETE FROM categories WHERE id NOT IN (SELECT DISTINCT category_id FROM packages);"
-
	"END;"
	"CREATE TABLE mtree ("
		"id INTEGER PRIMARY KEY,"
		"content TEXT UNIQUE"
@@ -226,7 +217,27 @@ pkgdb_init(sqlite3 *sdb)
			"((SELECT id FROM packages WHERE origin = NEW.origin), "
			"(SELECT id FROM directories WHERE path = NEW.path));"
	"END;"
-
	;
+
	"CREATE TABLE categories ("
+
		"id INTEGER PRIMARY KEY, "
+
		"name TEXT NOT NULL"
+
	");"
+
	"CREATE TABLE pkg_categories_assoc ("
+
		"package_id INTEGER REFERENCES packages(id) ON DELETE CASCADE"
+
			" ON UPDATE CASCADE, "
+
		"category_id INTEGER REFERENCES categories(id) ON DELETE RESTRICT"
+
			" ON UPDATE RESTRICT, "
+
		"PRIMARY KEY (package_id, category_id)"
+
	");"
+
	"CREATE VIEW pkg_categories AS SELECT origin, path FROM packages "
+
	"INNER JOIN pkg_categories_assoc ON packages.id = pkg_categories_assoc.package_id "
+
	"INNER JOIN categories ON pkg_categories_assoc.category_id = categories.id;"
+
	"CREATE TRIGGER category_insert INSTEAD OF INSERT ON pkg_categories "
+
	"FOR EACH ROW BEGIN "
+
		"INSERT OR IGNORE INTO CATEGORIES (name) VALUES (NEW.name);"
+
		"INSERT INTO pkg_categories_assoc (package_id, directory_id) VALUES "
+
			"((SELECT id FROM packages where origin = NEW.origin), "
+
			"(SELECT id FROM categories WHERE name = NEW.name));"
+
	"END;";

	if (sqlite3_exec(sdb, sql, NULL, NULL, &errmsg) != SQLITE_OK) {
		EMIT_PKG_ERROR("sqlite: %s", errmsg);
@@ -442,6 +453,10 @@ pkgdb_it_next(struct pkgdb_it *it, struct pkg **pkg_p, int flags)
			if ((ret = pkgdb_loadmtree(it->db, pkg)) != EPKG_OK)
				return (ret);

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

		return (EPKG_OK);
	case SQLITE_DONE:
		return (EPKG_END);
@@ -772,6 +787,43 @@ pkgdb_loaddirs(struct pkgdb *db, struct pkg *pkg)
}

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

+
	if (pkg->flags & PKG_LOAD_CATEGORIES)
+
		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_addcategory(pkg, sqlite3_column_text(stmt, 0));
+
	}
+

+
	sqlite3_finalize(stmt);
+

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

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

+
int
pkgdb_loadconflicts(struct pkgdb *db, struct pkg *pkg)
{
	sqlite3_stmt *stmt;
@@ -1278,6 +1330,13 @@ pkgdb_unregister_pkg(struct pkgdb *db, const char *origin)
		return (EPKG_FATAL);
	}

+
	ret = sqlite3_exec(db->sqlite, "DELETE from categories WHERE id NOT IN (SELECT DISTINCT category_id FROM pkg_categories_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
@@ -26,7 +26,7 @@ pkg_create_matches(int argc, char **argv, match_t match, pkg_formats fmt, const
	struct pkgdb *db = NULL;
	struct pkgdb_it *it = NULL;
	struct pkg *pkg = NULL;
-
	int query_flags = PKG_LOAD_DEPS | PKG_LOAD_CONFLICTS | PKG_LOAD_FILES |
+
	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;