Radish alpha
H
rad:z3QDZAW2FAfuLvihrhiyDC9fAD8G9
HardenedBSD Package Manager
Radicle
Git
Add utilities to handle provides and conflicts.
Vsevolod Stakhov committed 12 years ago
commit 6d17dbfa4ce075a79d691218efbfb31f948c6fd1
parent c385c9b
6 files changed +237 -3
modified libpkg/pkg.c
@@ -471,6 +471,14 @@ pkg_conflicts(const struct pkg *pkg, struct pkg_conflict **c)
}

int
+
pkg_provides(const struct pkg *pkg, struct pkg_provide **c)
+
{
+
	assert(pkg != NULL);
+

+
	HASH_NEXT(pkg->provides, (*c));
+
}
+

+
int
pkg_annotations(const struct pkg *pkg, struct pkg_note **an)
{
	assert(pkg != NULL);
@@ -930,6 +938,29 @@ pkg_addconflict(struct pkg *pkg, const char *name)
}

int
+
pkg_addprovide(struct pkg *pkg, const char *name)
+
{
+
	struct pkg_provide *p = NULL;
+

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

+
	HASH_FIND_STR(pkg->provides, __DECONST(char *, name), p);
+
	/* silently ignore duplicates in case of conflicts */
+
	if (p != NULL)
+
		return (EPKG_OK);
+

+
	pkg_provide_new(&p);
+
	sbuf_set(&p->provide, name);
+

+
	HASH_ADD_KEYPTR(hh, pkg->provides,
+
	    __DECONST(char *, pkg_provide_name(p)),
+
	    sbuf_size(p->provide), p);
+

+
	return (EPKG_OK);
+
}
+

+
int
pkg_addannotation(struct pkg *pkg, const char *tag, const char *value)
{
	struct pkg_note *an = NULL;
@@ -1020,6 +1051,10 @@ pkg_list_count(const struct pkg *pkg, pkg_list list)
		return (HASH_COUNT(pkg->shlibs_provided));
	case PKG_ANNOTATIONS:
		return (HASH_COUNT(pkg->annotations));
+
	case PKG_CONFLICTS:
+
		return (HASH_COUNT(pkg->conflicts));
+
	case PKG_PROVIDES:
+
		return (HASH_COUNT(pkg->provides));
	}
	
	return (0);
@@ -1076,6 +1111,14 @@ pkg_list_free(struct pkg *pkg, pkg_list list) {
		HASH_FREE(pkg->annotations, pkg_note, pkg_annotation_free);
		pkg->flags &= ~PKG_LOAD_ANNOTATIONS;
		break;
+
	case PKG_CONFLICTS:
+
		HASH_FREE(pkg->conflicts, pkg_conflict, pkg_conflict_free);
+
		pkg->flags &= ~PKG_LOAD_CONFLICTS;
+
		break;
+
	case PKG_PROVIDES:
+
		HASH_FREE(pkg->provides, pkg_provide, pkg_provide_free);
+
		pkg->flags &= ~PKG_LOAD_PROVIDES;
+
		break;
	}
}

modified libpkg/pkg.h.in
@@ -68,6 +68,7 @@ struct pkg_user;
struct pkg_group;
struct pkg_shlib;
struct pkg_note;
+
struct pkg_provide;

struct pkgdb;
struct pkgdb_it;
@@ -271,6 +272,8 @@ typedef enum {
	PKG_SHLIBS_REQUIRED,
	PKG_SHLIBS_PROVIDED,
	PKG_ANNOTATIONS,
+
	PKG_CONFLICTS,
+
	PKG_PROVIDES
} pkg_list;

typedef enum {
@@ -616,6 +619,13 @@ int pkg_shlibs_provided(const struct pkg *pkg, struct pkg_shlib **shlib);
int pkg_conflicts(const struct pkg *pkg, struct pkg_conflict **conflict);

/**
+
 * Iterates over the provides registered in the package.
+
 * @param provide must be set to NULL for the first call.
+
 * @return An error code
+
 */
+
int pkg_provides(const struct pkg *pkg, struct pkg_provide **provide);
+

+
/**
 * Iterates over the annotations associated with the package.
 * @param note must be set to NULL for the first call.
 * @return An error code
@@ -798,6 +808,12 @@ int pkg_addshlib_provided(struct pkg *pkg, const char *name);
int pkg_addconflict(struct pkg *pkg, const char *name);

/**
+
 * Add a provide registered with this package
+
 * @return An error code.
+
 */
+
int pkg_addprovide(struct pkg *pkg, const char *name);
+

+
/**
 * Add annotation key+value pair
 * @return An error code
 */
@@ -893,6 +909,9 @@ const char *pkg_shlib_name(struct pkg_shlib const * const);
/* pkg_conflict */
const char *pkg_conflict_origin(const struct pkg_conflict *);

+
/* pkg_provide */
+
const char *pkg_provide_name(const struct pkg_provide *);
+

/* pkg_note */
const char *pkg_annotation_tag(struct pkg_note const * const);
const char *pkg_annotation_value(struct pkg_note const * const);
@@ -1043,6 +1062,8 @@ int pkgdb_delete_annotation(struct pkgdb *db, struct pkg *pkg,
#define PKG_LOAD_SHLIBS_REQUIRED	(1U << 11)
#define PKG_LOAD_SHLIBS_PROVIDED	(1U << 12)
#define PKG_LOAD_ANNOTATIONS		(1U << 13)
+
#define PKG_LOAD_CONFLICTS		(1U << 14)
+
#define PKG_LOAD_PROVIDES		(1U << 15)
/* Make sure new PKG_LOAD don't conflict with PKG_CONTAINS_* */

/**
modified libpkg/pkg_attributes.c
@@ -463,6 +463,37 @@ pkg_conflict_origin(const struct pkg_conflict *c)
}

/*
+
 * Provides
+
 */
+
int
+
pkg_provide_new(struct pkg_provide **c)
+
{
+
	if ((*c = calloc(1, sizeof(struct pkg_provide))) == NULL)
+
		return (EPKG_FATAL);
+

+
	return (EPKG_OK);
+
}
+

+
void
+
pkg_provide_free(struct pkg_provide *c)
+
{
+
	if (c == NULL)
+
		return;
+

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

+
const char *
+
pkg_provide_name(const struct pkg_provide *c)
+
{
+
	assert(c != NULL);
+

+
	return (sbuf_get(c->provide));
+
}
+

+

+
/*
 * Annotations
 */

modified libpkg/pkg_manifest.c
@@ -61,6 +61,7 @@
#define PKG_ANNOTATIONS -14
#define PKG_INFOS -15		/* Deprecated field: treat as an annotation for backwards compatibility */
#define PKG_CONFLICTS -16
+
#define PKG_PROVIDES -17

static int pkg_set_from_node(struct pkg *, yaml_node_t *, yaml_document_t *, int);
static int pkg_set_size_from_node(struct pkg *, yaml_node_t *, yaml_document_t *, int);
@@ -135,6 +136,7 @@ static struct manifest_key {
	{ "arch", PKG_ARCH, YAML_SCALAR_NODE, pkg_set_from_node},
	{ "categories", PKG_CATEGORIES, YAML_SEQUENCE_NODE, parse_sequence},
	{ "comment", PKG_COMMENT, YAML_SCALAR_NODE, pkg_set_from_node},
+
	{ "conflicts", PKG_CONFLICTS, YAML_SEQUENCE_NODE, parse_sequence},
	{ "deps", PKG_DEPS, YAML_MAPPING_NODE, parse_mapping},
	{ "desc", PKG_DESC, YAML_SCALAR_NODE, pkg_set_from_node},
	{ "directories", PKG_DIRECTORIES, YAML_MAPPING_NODE, parse_mapping},
@@ -154,11 +156,11 @@ static struct manifest_key {
	{ "path", PKG_REPOPATH, YAML_SCALAR_NODE, pkg_set_from_node},
	{ "pkgsize", PKG_PKGSIZE, YAML_SCALAR_NODE, pkg_set_size_from_node},
	{ "prefix", PKG_PREFIX, YAML_SCALAR_NODE, pkg_set_from_node},
+
	{ "provides", PKG_PROVIDES, YAML_SEQUENCE_NODE, parse_sequence},
	{ "scripts", PKG_SCRIPTS, YAML_MAPPING_NODE, parse_mapping},
	{ "shlibs", PKG_SHLIBS_REQUIRED, YAML_SEQUENCE_NODE, parse_sequence}, /* Backwards compat with 1.0.x packages */
	{ "shlibs_provided", PKG_SHLIBS_PROVIDED, YAML_SEQUENCE_NODE, parse_sequence},
	{ "shlibs_required", PKG_SHLIBS_REQUIRED, YAML_SEQUENCE_NODE, parse_sequence},
-
	{ "conflicts", PKG_CONFLICTS, YAML_SEQUENCE_NODE, parse_sequence},
	{ "sum", PKG_CKSUM, YAML_SCALAR_NODE, pkg_set_from_node},
	{ "users", PKG_USERS, YAML_MAPPING_NODE, parse_mapping},
	{ "users", PKG_USERS, YAML_SEQUENCE_NODE, parse_sequence},
@@ -839,6 +841,12 @@ parse_sequence(struct pkg * pkg, yaml_node_t *node, yaml_document_t *doc,
			else
				pkg_addconflict(pkg, val->data.scalar.value);
			break;
+
		case PKG_PROVIDES:
+
			if (!is_valid_yaml_scalar(val))
+
				pkg_emit_error("Skipping malformed conflict name");
+
			else
+
				pkg_addprovide(pkg, val->data.scalar.value);
+
			break;
		}
		++item;
	}
@@ -1507,6 +1515,7 @@ emit_manifest(struct pkg *pkg, yaml_emitter_t *emitter, short flags)
	struct pkg_shlib	*shlib    = NULL;
	struct pkg_note		*note     = NULL;
	struct pkg_conflict	*conflict = NULL;
+
	struct pkg_provide	*provide = NULL;
	struct sbuf		*tmpsbuf  = NULL;
	int rc = EPKG_OK;
	int mapping;
@@ -1620,6 +1629,11 @@ emit_manifest(struct pkg *pkg, yaml_emitter_t *emitter, short flags)
		manifest_append_seqval(&doc, mapping, &seq, "conflicts",
		    pkg_conflict_origin(conflict));

+
	seq = -1;
+
	while (pkg_provides(pkg, &provide) == EPKG_OK)
+
		manifest_append_seqval(&doc, mapping, &seq, "provides",
+
		    pkg_provide_name(provide));
+

	map = -1;
	while (pkg_options(pkg, &option) == EPKG_OK) {
		if (map == -1)
modified libpkg/pkgdb.c
@@ -7,6 +7,7 @@
 * Copyright (c) 2012-2013 Matthew Seaman <matthew@FreeBSD.org>
 * Copyright (c) 2012 Bryan Drewery <bryan@shatow.net>
 * Copyright (c) 2013 Gerald Pfeifer <gerald@pfeifer.com>
+
 * Copyright (c) 2013 Vsevolod Stakhov <vsevolod@FreeBSD.org>
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
@@ -635,7 +636,8 @@ pkgdb_init(sqlite3 *sdb)
	"CREATE INDEX pkg_directories_directory_id ON pkg_directories (directory_id);"
	"CREATE INDEX pkg_annotation_package_id ON pkg_annotation(package_id);"
	"CREATE INDEX pkg_digest_id ON packages(origin, manifestdigest);"
-
	"CREATE INDEX pkg_conflicts_id ON pkg_conflicts(package_id);"
+
	"CREATE INDEX pkg_conflicts_pid ON pkg_conflicts(package_id);"
+
	"CREATE INDEX pkg_conflicts_cid ON pkg_conflicts(conflict_id);"
	"CREATE INDEX pkg_provides_id ON pkg_provides(package_id);"

	"CREATE VIEW pkg_shlibs AS SELECT * FROM pkg_shlibs_required;"
@@ -683,6 +685,9 @@ pkgdb_remote_init(struct pkgdb *db, const char *repo)
	"BEGIN;"
	"CREATE INDEX IF NOT EXISTS '%s'.deps_origin ON deps(origin);"
	"CREATE INDEX IF NOT EXISTS '%s'.pkg_digest_id ON packages(origin, manifestdigest);"
+
	"CREATE INDEX IF NOT EXISTS '%s'.pkg_conflicts_pid ON pkg_conflicts(package_id);"
+
	"CREATE INDEX IF NOT EXISTS '%s'.pkg_conflicts_cid ON pkg_conflicts(conflict_id);"
+
	"CREATE INDEX IF NOT EXISTS '%s'.pkg_provides_id ON pkg_provides(package_id);"
	"COMMIT;"
	;

@@ -691,7 +696,7 @@ pkgdb_remote_init(struct pkgdb *db, const char *repo)
	}

	sql = sbuf_new_auto();
-
	sbuf_printf(sql, init_sql, reponame, reponame);
+
	sbuf_printf(sql, init_sql, reponame, reponame, reponame, reponame, reponame);

	ret = sql_exec(db->sqlite, sbuf_data(sql));
	sbuf_delete(sql);
@@ -1243,6 +1248,8 @@ static struct load_on_flag {
	{ PKG_LOAD_SHLIBS_REQUIRED,	pkgdb_load_shlib_required },
	{ PKG_LOAD_SHLIBS_PROVIDED,	pkgdb_load_shlib_provided },
	{ PKG_LOAD_ANNOTATIONS,		pkgdb_load_annotations },
+
	{ PKG_LOAD_CONFLICTS,		pkgdb_load_conflicts },
+
	{ PKG_LOAD_PROVIDES,		pkgdb_load_provides },
	{ -1,			        NULL }
};

@@ -2039,6 +2046,54 @@ pkgdb_load_mtree(struct pkgdb *db, struct pkg *pkg)
	return (load_val(db->sqlite, pkg, sql, PKG_LOAD_MTREE, pkg_set_mtree, -1));
}

+
int
+
pkgdb_load_conflicts(struct pkgdb *db, struct pkg *pkg)
+
{
+
	char		 sql[BUFSIZ];
+
	const char	*reponame = NULL;
+
	const char	*basesql = ""
+
			"SELECT packages.origin "
+
			"FROM %Q.conflicts "
+
			"LEFT JOIN %Q.packages ON "
+
			"packages.id = conflicts.conflict_id"
+
			"WHERE package_id = ?1";
+

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

+
	if (pkg->type == PKG_REMOTE) {
+
		assert(db->type == PKGDB_REMOTE);
+
		pkg_get(pkg, PKG_REPONAME, &reponame);
+
		sqlite3_snprintf(sizeof(sql), sql, basesql, reponame, reponame);
+
	} else
+
		sqlite3_snprintf(sizeof(sql), sql, basesql, "main", "main");
+

+
	return (load_val(db->sqlite, pkg, sql, PKG_LOAD_CONFLICTS,
+
			pkg_addconflict, PKG_CONFLICTS));
+
}
+

+
int
+
pkgdb_load_provides(struct pkgdb *db, struct pkg *pkg)
+
{
+
	char		 sql[BUFSIZ];
+
	const char	*reponame = NULL;
+
	const char	*basesql = ""
+
		"SELECT provide "
+
		"FROM %Q.provides "
+
		"WHERE package_id = ?1";
+

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

+
	if (pkg->type == PKG_REMOTE) {
+
		assert(db->type == PKGDB_REMOTE);
+
		pkg_get(pkg, PKG_REPONAME, &reponame);
+
		sqlite3_snprintf(sizeof(sql), sql, basesql, reponame, reponame);
+
	} else
+
		sqlite3_snprintf(sizeof(sql), sql, basesql, "main", "main");
+

+
	return (load_val(db->sqlite, pkg, sql, PKG_LOAD_PROVIDES,
+
			pkg_addconflict, PKG_PROVIDES));
+
}
+

typedef enum _sql_prstmt_index {
	MTREE = 0,
	PKG,
@@ -2066,6 +2121,9 @@ typedef enum _sql_prstmt_index {
	ANNOTATE_ADD1,
	ANNOTATE_DEL1,
	ANNOTATE_DEL2,
+
	CONFLICT,
+
	PKG_PROVIDE,
+
	PROVIDE,
	PRSTMT_LAST,
} sql_prstmt_index;

@@ -2232,6 +2290,24 @@ static sql_prstmt sql_prepared_statements[PRSTMT_LAST] = {
		" annotation_id NOT IN (SELECT value_id FROM pkg_annotation)",
		"",
	},
+
	[CONFLICT] = {
+
		NULL,
+
		"INSERT INTO pkg_conflicts(package_id, "
+
		"(SELECT id FROM packages WHERE origin = ?2)) "
+
		"VALUES (?1, ?2)",
+
		"IT",
+
	},
+
	[PKG_PROVIDE] = {
+
		NULL,
+
		"INSERT INTO pkg_provides(package_id, provide_id) "
+
		"VALUES (?1, (SELECT id FROM provides WHERE provide = ?2))",
+
		"IT",
+
	},
+
	{
+
		NULL,
+
		"INSERT OR IGNORE INTO provides(provide) VALUES(?1)",
+
		"T",
+
	}
	/* PRSTMT_LAST */
};

@@ -2324,6 +2400,7 @@ pkgdb_register_pkg(struct pkgdb *db, struct pkg *pkg, int complete, int forced)
	struct pkg_license	*license = NULL;
	struct pkg_user		*user = NULL;
	struct pkg_group	*group = NULL;
+
	struct pkg_conflict	*conflict = NULL;
	struct pkgdb_it		*it = NULL;

	sqlite3			*s;
@@ -2607,6 +2684,23 @@ pkgdb_register_pkg(struct pkgdb *db, struct pkg *pkg, int complete, int forced)
	if (pkgdb_insert_annotations(pkg, package_id, s) != EPKG_OK)
		goto cleanup;

+
	/*
+
	 * Insert conflicts
+
	 */
+
	while (pkg_conflicts(pkg, &conflict) == EPKG_OK) {
+
		if (run_prstmt(CONFLICT, package_id, pkg_conflict_origin(conflict))
+
				!= SQLITE_DONE) {
+
			ERROR_SQLITE(s);
+
			goto cleanup;
+
		}
+
	}
+

+
	/*
+
	 * Insert provides
+
	 */
+
	if (pkgdb_update_provides(pkg, package_id, s) != EPKG_OK)
+
		goto cleanup;
+

	retcode = EPKG_OK;

	cleanup:
@@ -2653,6 +2747,25 @@ pkgdb_update_shlibs_provided(struct pkg *pkg, int64_t package_id, sqlite3 *s)
}

int
+
pkgdb_update_provides(struct pkg *pkg, int64_t package_id, sqlite3 *s)
+
{
+
	struct pkg_provide	*provide;
+

+
	while (pkg_provides(pkg, &provide) == EPKG_OK) {
+
		if (run_prstmt(PROVIDE, pkg_provide_name(provide))
+
		    != SQLITE_DONE
+
		    ||
+
		    run_prstmt(PKG_PROVIDE, package_id, pkg_provide_name(provide))
+
		    != SQLITE_DONE) {
+
			ERROR_SQLITE(s);
+
			return (EPKG_FATAL);
+
		}
+
	}
+

+
	return (EPKG_OK);
+
}
+

+
int
pkgdb_insert_annotations(struct pkg *pkg, int64_t package_id, sqlite3 *s)
{
	struct pkg_note	*note = NULL;
modified libpkg/private/pkg.h
@@ -128,6 +128,7 @@ struct pkg {
	struct pkg_shlib	*shlibs_provided;
	struct pkg_note		*annotations;
	struct pkg_conflict *conflicts;
+
	struct pkg_provide	*provides;
	unsigned       	 flags;
	int64_t		 rowid;
	int64_t		 time;
@@ -150,6 +151,11 @@ struct pkg_conflict {
	UT_hash_handle	hh;
};

+
struct pkg_provide {
+
	struct sbuf		*provide;
+
	UT_hash_handle	hh;
+
};
+

struct pkg_license {
	/* should be enough to match a license name */
	char name[64];
@@ -356,6 +362,9 @@ void pkg_shlib_free(struct pkg_shlib *);
int pkg_conflict_new(struct pkg_conflict **);
void pkg_conflict_free(struct pkg_conflict *);

+
int pkg_provide_new(struct pkg_provide **);
+
void pkg_provide_free(struct pkg_provide *);
+

int pkg_annotation_new(struct pkg_note **);
void pkg_annotation_free(struct pkg_note *);

@@ -405,10 +414,13 @@ int pkgdb_load_group(struct pkgdb *db, struct pkg *pkg);
int pkgdb_load_shlib_required(struct pkgdb *db, struct pkg *pkg);
int pkgdb_load_shlib_provided(struct pkgdb *db, struct pkg *pkg);
int pkgdb_load_annotations(struct pkgdb *db, struct pkg *pkg);
+
int pkgdb_load_conflicts(struct pkgdb *db, struct pkg *pkg);
+
int pkgdb_load_provides(struct pkgdb *db, struct pkg *pkg);

int pkgdb_register_pkg(struct pkgdb *db, struct pkg *pkg, int complete, int forced);
int pkgdb_update_shlibs_required(struct pkg *pkg, int64_t package_id, sqlite3 *s);
int pkgdb_update_shlibs_provided(struct pkg *pkg, int64_t package_id, sqlite3 *s);
+
int pkgdb_update_provides(struct pkg *pkg, int64_t package_id, sqlite3 *s);
int pkgdb_insert_annotations(struct pkg *pkg, int64_t package_id, sqlite3 *s);
int pkgdb_register_finale(struct pkgdb *db, int retcode);