Radish alpha
H
rad:z3QDZAW2FAfuLvihrhiyDC9fAD8G9
HardenedBSD Package Manager
Radicle
Git
Add support for provides/requires
Baptiste Daroussin committed 11 years ago
commit a8b55d0cef9e4d95f06afa95dcd5476cd553b668
parent e1410de
18 files changed +476 -10
modified libpkg/libpkg.ver
@@ -181,6 +181,8 @@ global:
	pkgdb_open;
	pkgdb_open_all;
	pkgdb_query;
+
	pkgdb_query_provide;
+
	pkgdb_query_require;
	pkgdb_query_shlib_provide;
	pkgdb_query_shlib_require;
	pkgdb_query_which;
modified libpkg/pkg.h.in
@@ -922,6 +922,8 @@ struct pkgdb_it * pkgdb_query_which(struct pkgdb *db, const char *path, bool glo

struct pkgdb_it * pkgdb_query_shlib_require(struct pkgdb *db, const char *shlib);
struct pkgdb_it * pkgdb_query_shlib_provide(struct pkgdb *db, const char *shlib);
+
struct pkgdb_it * pkgdb_query_require(struct pkgdb *db, const char *req);
+
struct pkgdb_it * pkgdb_query_provide(struct pkgdb *db, const char *req);

struct pkgdb_it * pkgdb_rquery_provide(struct pkgdb *db,
    const char *provide, const char *repo);
modified libpkg/pkg_jobs.c
@@ -788,6 +788,7 @@ pkg_jobs_try_remote_candidate(struct pkg_jobs *j, const char *pattern,
	struct pkg *p = NULL;
	struct pkgdb_it *it;
	unsigned flags = PKG_LOAD_BASIC|PKG_LOAD_OPTIONS|PKG_LOAD_DEPS|
+
				PKG_LOAD_REQUIRES|PKG_LOAD_PROVIDES|
				PKG_LOAD_SHLIBS_REQUIRED|PKG_LOAD_SHLIBS_PROVIDED|
				PKG_LOAD_ANNOTATIONS|PKG_LOAD_CONFLICTS;
	int rc = EPKG_FATAL;
@@ -903,6 +904,7 @@ pkg_jobs_find_upgrade(struct pkg_jobs *j, const char *pattern, match_t m)
	int rc = EPKG_FATAL;
	struct pkg_dep *rdep = NULL;
	unsigned flags = PKG_LOAD_BASIC|PKG_LOAD_OPTIONS|PKG_LOAD_DEPS|
+
			PKG_LOAD_REQUIRES|PKG_LOAD_PROVIDES|
			PKG_LOAD_SHLIBS_REQUIRED|PKG_LOAD_SHLIBS_PROVIDED|
			PKG_LOAD_ANNOTATIONS|PKG_LOAD_CONFLICTS;
	struct pkg_job_universe_item *unit = NULL;
@@ -1451,7 +1453,7 @@ jobs_solve_install_upgrade(struct pkg_jobs *j)
	size_t jcount = 0;
	struct job_pattern *jp, *jtmp;
	struct pkg_job_request *req, *rtmp;
-
	unsigned flags = PKG_LOAD_BASIC|PKG_LOAD_OPTIONS|PKG_LOAD_DEPS|
+
	unsigned flags = PKG_LOAD_BASIC|PKG_LOAD_OPTIONS|PKG_LOAD_DEPS|PKG_LOAD_REQUIRES|
			PKG_LOAD_SHLIBS_REQUIRED|PKG_LOAD_ANNOTATIONS|PKG_LOAD_CONFLICTS;
	struct pkg_jobs_install_candidate *candidates, *c;

modified libpkg/pkg_jobs_universe.c
@@ -59,6 +59,7 @@ pkg_jobs_universe_get_local(struct pkg_jobs_universe *universe,
	if (flag == 0) {
		if (!IS_DELETE(universe->j))
			flag = PKG_LOAD_BASIC|PKG_LOAD_DEPS|PKG_LOAD_RDEPS|PKG_LOAD_OPTIONS|
+
				PKG_LOAD_REQUIRES|
				PKG_LOAD_SHLIBS_REQUIRED|PKG_LOAD_ANNOTATIONS|
				PKG_LOAD_CONFLICTS;
		else
@@ -105,6 +106,7 @@ pkg_jobs_universe_get_remote(struct pkg_jobs_universe *universe,

	if (flag == 0) {
		flag = PKG_LOAD_BASIC|PKG_LOAD_DEPS|PKG_LOAD_OPTIONS|
+
			PKG_LOAD_PROVIDES|PKG_LOAD_REQUIRES|
				PKG_LOAD_SHLIBS_REQUIRED|PKG_LOAD_SHLIBS_PROVIDED|
				PKG_LOAD_ANNOTATIONS|PKG_LOAD_CONFLICTS;
	}
@@ -337,7 +339,6 @@ pkg_jobs_universe_process_conflicts(struct pkg_jobs_universe *universe,
	return (EPKG_OK);
}

-

static int
pkg_jobs_universe_process_shlibs(struct pkg_jobs_universe *universe,
	struct pkg *pkg)
@@ -348,6 +349,7 @@ pkg_jobs_universe_process_shlibs(struct pkg_jobs_universe *universe,
	struct pkgdb_it *it;
	struct pkg *npkg, *rpkg;
	unsigned flags = PKG_LOAD_BASIC|PKG_LOAD_OPTIONS|PKG_LOAD_DEPS|
+
				PKG_LOAD_REQUIRES|PKG_LOAD_PROVIDES|
				PKG_LOAD_SHLIBS_REQUIRED|PKG_LOAD_SHLIBS_PROVIDED|
				PKG_LOAD_ANNOTATIONS|PKG_LOAD_CONFLICTS;

@@ -380,8 +382,9 @@ pkg_jobs_universe_process_shlibs(struct pkg_jobs_universe *universe,
					npkg = pkg_jobs_universe_get_local(universe, rpkg->uid, 0);
					if (npkg != NULL) {
						if (pkg_jobs_universe_process_item(universe, npkg,
-
							&unit) != EPKG_OK)
+
							&unit) != EPKG_OK) {
							return (EPKG_FATAL);
+
						}
						if (pkg_jobs_need_upgrade (rpkg, npkg)) {
							/* Remote provide is newer, so we can add it */
							if (pkg_jobs_universe_process_item(universe, rpkg,
@@ -448,6 +451,118 @@ pkg_jobs_universe_process_shlibs(struct pkg_jobs_universe *universe,
	return (EPKG_OK);
}

+
static int
+
pkg_jobs_universe_process_provides_requires(struct pkg_jobs_universe *universe,
+
	struct pkg *pkg)
+
{
+
	struct pkg_provide *p = NULL;
+
	struct pkg_job_universe_item *unit;
+
	struct pkg_job_provide *pr, *prhead;
+
	struct pkgdb_it *it;
+
	struct pkg *npkg, *rpkg;
+
	unsigned flags = PKG_LOAD_BASIC|PKG_LOAD_OPTIONS|PKG_LOAD_DEPS|
+
				PKG_LOAD_REQUIRES|PKG_LOAD_PROVIDES|
+
				PKG_LOAD_SHLIBS_REQUIRED|PKG_LOAD_SHLIBS_PROVIDED|
+
				PKG_LOAD_PROVIDES|
+
				PKG_LOAD_ANNOTATIONS|PKG_LOAD_CONFLICTS;
+

+
	while (pkg_requires(pkg, &p) == EPKG_OK) {
+
		HASH_FIND_STR(universe->provides, p->provide, pr);
+
		if (pr != NULL)
+
			continue;
+

+
		/* Not found, search in the repos */
+
		it = pkgdb_repo_provide(universe->j->db,
+
			p->provide, universe->j->reponame);
+
		if (it != NULL) {
+
			rpkg = NULL;
+
			prhead = NULL;
+
			while (pkgdb_it_next(it, &rpkg, flags) == EPKG_OK) {
+
				/* Check for local packages */
+
				HASH_FIND_STR(universe->items, rpkg->uid, unit);
+
				if (unit != NULL) {
+
					if (pkg_jobs_need_upgrade (rpkg, unit->pkg)) {
+
						/* Remote provide is newer, so we can add it */
+
						if (pkg_jobs_universe_process_item(universe, rpkg,
+
							&unit) != EPKG_OK)
+
							continue;
+

+
						rpkg = NULL;
+
					}
+
				}
+
				else {
+
					/* Maybe local package has just been not added */
+
					npkg = pkg_jobs_universe_get_local(universe, rpkg->uid, 0);
+
					if (npkg != NULL) {
+
						if (pkg_jobs_universe_process_item(universe, npkg,
+
							&unit) != EPKG_OK)
+
							return (EPKG_FATAL);
+
						if (pkg_jobs_need_upgrade (rpkg, npkg)) {
+
							/* Remote provide is newer, so we can add it */
+
							if (pkg_jobs_universe_process_item(universe, rpkg,
+
								&unit) != EPKG_OK)
+
								continue;
+
						}
+
					}
+
				}
+

+
				/* Skip seen packages */
+
				if (unit == NULL) {
+
					struct pkg_job_seen *seen;
+

+
					if (rpkg->digest == NULL) {
+
						pkg_debug(3, "no digest found for package %s", rpkg->uid);
+
						if (pkg_checksum_calculate(pkg, universe->j->db) != EPKG_OK) {
+
							return (EPKG_FATAL);
+
						}
+
					}
+
					HASH_FIND_STR(universe->seen, rpkg->digest, seen);
+
					if (seen == NULL) {
+
						pkg_jobs_universe_process_item(universe, rpkg,
+
							&unit);
+

+
						/* Reset package to avoid freeing */
+
						rpkg = NULL;
+
					}
+
					else {
+
						unit = seen->un;
+
					}
+
				}
+

+
				pr = calloc (1, sizeof (*pr));
+
				if (pr == NULL) {
+
					pkg_emit_errno("pkg_jobs_add_universe", "calloc: "
+
						"struct pkg_job_provide");
+
					return (EPKG_FATAL);
+
				}
+

+
				pr->un = unit;
+
				pr->provide = p->provide;
+

+
				if (prhead == NULL) {
+
					DL_APPEND(prhead, pr);
+
					HASH_ADD_KEYPTR(hh, universe->provides, pr->provide,
+
						strlen(pr->provide), prhead);
+
				}
+
				else {
+
					DL_APPEND(prhead, pr);
+
				}
+
			}
+
			pkgdb_it_free(it);
+
			if (prhead == NULL) {
+
				pkg_debug(1, "cannot find packages that provide %s required for %s",
+
				    p->provide, pkg->name);
+
				/*
+
				 * XXX: this is not normal but it is very common for the existing
+
				 * repos, hence we just ignore this stale dependency
+
				 */
+
			}
+
		}
+
	}
+

+
	return (EPKG_OK);
+
}
+

int
pkg_jobs_universe_process_item(struct pkg_jobs_universe *universe, struct pkg *pkg,
		struct pkg_job_universe_item **result)
@@ -509,6 +624,9 @@ pkg_jobs_universe_process_item(struct pkg_jobs_universe *universe, struct pkg *p
			rc = pkg_jobs_universe_process_shlibs(universe, pkg);
			if (rc != EPKG_OK)
				return (rc);
+
			rc = pkg_jobs_universe_process_provides_requires(universe, pkg);
+
			if (rc != EPKG_OK)
+
				return (rc);
		}
		break;
	case PKG_JOBS_AUTOREMOVE:
@@ -1047,6 +1165,7 @@ pkg_jobs_universe_get_upgrade_candidates(struct pkg_jobs_universe *universe,
	struct pkgdb_it *it;
	struct pkg_job_universe_item *unit, *ucur;
	int flag = PKG_LOAD_BASIC|PKG_LOAD_DEPS|PKG_LOAD_OPTIONS|
+
					PKG_LOAD_REQUIRES|PKG_LOAD_PROVIDES|
					PKG_LOAD_SHLIBS_REQUIRED|PKG_LOAD_SHLIBS_PROVIDED|
					PKG_LOAD_ANNOTATIONS|PKG_LOAD_CONFLICTS;
	UT_array *candidates;
modified libpkg/pkg_solve.c
@@ -486,6 +486,8 @@ pkg_solve_add_require_rule(struct pkg_solve_problem *problem,
		 */
		pkg_debug(1, "solver: cannot find provide for requirement: %s",
		    requirement);
+
		pkg_emit_error("Solver: cannot find a provide for requirement:"
+
		    "    %s", requirement);
	}

	return (EPKG_OK);
modified libpkg/pkgdb_iterator.c
@@ -664,13 +664,15 @@ pkgdb_load_provides(sqlite3 *sqlite, struct pkg *pkg)
{
	const char	sql[] = ""
		"SELECT provide"
-
		"  FROM provides"
-
		"  WHERE package_id = ?1";
+
		"  FROM pkg_provides, provides AS s"
+
		"  WHERE package_id = ?1"
+
		"    AND provide_id = s.id"
+
		"  ORDER by provide DESC";

	assert(pkg != NULL);

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

static int
@@ -678,13 +680,15 @@ pkgdb_load_requires(sqlite3 *sqlite, struct pkg *pkg)
{
	const char	sql[] = ""
		"SELECT require"
-
		" FROM requires"
-
		" WHERE package_id = ?1";
+
		"  FROM pkg_requires, requires AS s"
+
		"  WHERE package_id = ?1"
+
		"    AND require_id = s.id"
+
		"  ORDER by require DESC";

	assert(pkg != NULL);

	return (load_val(sqlite, pkg, sql, PKG_LOAD_REQUIRES,
-
	    pkg_addconflict, PKG_REQUIRES));
+
	    pkg_addrequire, PKG_REQUIRES));
}

static void
@@ -836,6 +840,7 @@ static struct load_on_flag {
	{ PKG_LOAD_ANNOTATIONS,		pkgdb_load_annotations },
	{ PKG_LOAD_CONFLICTS,		pkgdb_load_conflicts },
	{ PKG_LOAD_PROVIDES,		pkgdb_load_provides },
+
	{ PKG_LOAD_REQUIRES,		pkgdb_load_requires },
	{ -1,			        NULL }
};

modified libpkg/pkgdb_query.c
@@ -256,6 +256,59 @@ pkgdb_query_shlib_provide(struct pkgdb *db, const char *shlib)
	return (pkgdb_it_new_sqlite(db, stmt, PKG_INSTALLED, PKGDB_IT_FLAG_ONCE));
}

+
struct pkgdb_it *
+
pkgdb_query_require(struct pkgdb *db, const char *req)
+
{
+
	sqlite3_stmt	*stmt;
+
	const char	 sql[] = ""
+
		"SELECT p.id, p.origin, p.name, p.name as uniqueid, "
+
			"p.version, p.comment, p.desc, "
+
			"p.message, p.arch, p.maintainer, p.www, "
+
			"p.prefix, p.flatsize, p.time "
+
			"FROM packages AS p, pkg_requires AS ps, require AS s "
+
			"WHERE p.id = ps.package_id "
+
				"AND ps.require_id = s.id "
+
				"AND s.name = ?1;";
+

+
	assert(db != NULL);
+

+
	pkg_debug(4, "Pkgdb: running '%s'", sql);
+
	if (sqlite3_prepare_v2(db->sqlite, sql, -1, &stmt, NULL) != SQLITE_OK) {
+
		ERROR_SQLITE(db->sqlite, sql);
+
		return (NULL);
+
	}
+

+
	sqlite3_bind_text(stmt, 1, req, -1, SQLITE_TRANSIENT);
+

+
	return (pkgdb_it_new_sqlite(db, stmt, PKG_INSTALLED, PKGDB_IT_FLAG_ONCE));
+
}
+

+
struct pkgdb_it *
+
pkgdb_query_provide(struct pkgdb *db, const char *req)
+
{
+
	sqlite3_stmt	*stmt;
+
	const char	 sql[] = ""
+
		"SELECT p.id, p.origin, p.name, p.name as uniqueid, "
+
			"p.version, p.comment, p.desc, "
+
			"p.message, p.arch, p.maintainer, p.www, "
+
			"p.prefix, p.flatsize, p.time "
+
			"FROM packages AS p, pkg_provides AS ps, provide AS s "
+
			"WHERE p.id = ps.package_id "
+
				"AND ps.provide_id = s.id "
+
				"AND s.name = ?1;";
+

+
	assert(db != NULL);
+

+
	pkg_debug(4, "Pkgdb: running '%s'", sql);
+
	if (sqlite3_prepare_v2(db->sqlite, sql, -1, &stmt, NULL) != SQLITE_OK) {
+
		ERROR_SQLITE(db->sqlite, sql);
+
		return (NULL);
+
	}
+

+
	sqlite3_bind_text(stmt, 1, req, -1, SQLITE_TRANSIENT);
+

+
	return (pkgdb_it_new_sqlite(db, stmt, PKG_INSTALLED, PKGDB_IT_FLAG_ONCE));
+
}

struct pkgdb_it *
pkgdb_repo_query(struct pkgdb *db, const char *pattern, match_t match,
@@ -329,6 +382,53 @@ pkgdb_repo_shlib_provide(struct pkgdb *db, const char *require, const char *repo
}

struct pkgdb_it *
+
pkgdb_repo_require(struct pkgdb *db, const char *require, const char *repo)
+
{
+
	struct pkgdb_it *it;
+
	struct pkg_repo_it *rit;
+
	struct _pkg_repo_list_item *cur;
+

+
	it = pkgdb_it_new_repo(db);
+
	if (it == NULL)
+
		return (NULL);
+

+
	LL_FOREACH(db->repos, cur) {
+
		if (repo == NULL || strcasecmp(cur->repo->name, repo) == 0) {
+
			if (cur->repo->ops->required != NULL) {
+
				rit = cur->repo->ops->required(cur->repo, require);
+
				if (rit != NULL)
+
					pkgdb_it_repo_attach(it, rit);
+
			}
+
		}
+
	}
+

+
	return (it);
+
}
+

+
struct pkgdb_it *
+
pkgdb_repo_provide(struct pkgdb *db, const char *require, const char *repo)
+
{
+
	struct pkgdb_it *it;
+
	struct pkg_repo_it *rit;
+
	struct _pkg_repo_list_item *cur;
+

+
	it = pkgdb_it_new_repo(db);
+
	if (it == NULL)
+
		return (NULL);
+

+
	LL_FOREACH(db->repos, cur) {
+
		if (repo == NULL || strcasecmp(cur->repo->name, repo) == 0) {
+
			if (cur->repo->ops->required != NULL) {
+
				rit = cur->repo->ops->provided(cur->repo, require);
+
				if (rit != NULL)
+
					pkgdb_it_repo_attach(it, rit);
+
			}
+
		}
+
	}
+

+
	return (it);
+
}
+
struct pkgdb_it *
pkgdb_repo_search(struct pkgdb *db, const char *pattern, match_t match,
    pkgdb_field field, pkgdb_field sort, const char *repo)
{
modified libpkg/private/pkg.h
@@ -344,6 +344,10 @@ struct pkg_repo_ops {
					const char *);
	struct pkg_repo_it * (*shlib_provided)(struct pkg_repo *,
					const char *);
+
	struct pkg_repo_it * (*required)(struct pkg_repo *,
+
					const char *);
+
	struct pkg_repo_it * (*provided)(struct pkg_repo *,
+
					const char *);
	struct pkg_repo_it * (*search)(struct pkg_repo *, const char *, match_t,
					pkgdb_field field, pkgdb_field sort);

modified libpkg/private/pkgdb.h
@@ -135,6 +135,12 @@ struct pkgdb_it *pkgdb_repo_shlib_require(struct pkgdb *db,
struct pkgdb_it *pkgdb_repo_shlib_provide(struct pkgdb *db,
		const char *require, const char *repo);

+
struct pkgdb_it *pkgdb_repo_provide(struct pkgdb *db, const char *require,
+
    const char *repo);
+

+
struct pkgdb_it *pkgdb_repo_require(struct pkgdb *db, const char *provide,
+
    const char *repo);
+

/**
 * Unregister a package from the database
 * @return An error code.
modified libpkg/repo/binary/binary.c
@@ -34,6 +34,8 @@ struct pkg_repo_ops pkg_repo_binary_ops = {
	.query = pkg_repo_binary_query,
	.shlib_provided = pkg_repo_binary_shlib_provide,
	.shlib_required = pkg_repo_binary_shlib_require,
+
	.provided = pkg_repo_binary_provide,
+
	.required = pkg_repo_binary_require,
	.search = pkg_repo_binary_search,
	.fetch_pkg = pkg_repo_binary_fetch,
	.mirror_pkg = pkg_repo_binary_mirror,
modified libpkg/repo/binary/binary.h
@@ -43,8 +43,12 @@ struct pkg_repo_it *pkg_repo_binary_query(struct pkg_repo *repo,
	const char *pattern, match_t match);
struct pkg_repo_it *pkg_repo_binary_shlib_provide(struct pkg_repo *repo,
	const char *require);
+
struct pkg_repo_it *pkg_repo_binary_provide(struct pkg_repo *repo,
+
	const char *require);
struct pkg_repo_it *pkg_repo_binary_shlib_require(struct pkg_repo *repo,
	const char *provide);
+
struct pkg_repo_it *pkg_repo_binary_require(struct pkg_repo *repo,
+
	const char *provide);
struct pkg_repo_it *pkg_repo_binary_search(struct pkg_repo *repo,
	const char *pattern, match_t match,
    pkgdb_field field, pkgdb_field sort);
modified libpkg/repo/binary/binary_private.h
@@ -553,6 +553,10 @@ typedef enum _sql_prstmt_index {
	REPO_VERSION,
	DELETE,
	FTS_APPEND,
+
	PROVIDE,
+
	PROVIDES,
+
	REQUIRE,
+
	REQUIRES,
	PRSTMT_LAST,
} sql_prstmt_index;

modified libpkg/repo/binary/common.c
@@ -137,7 +137,29 @@ static sql_prstmt sql_prepared_statements[PRSTMT_LAST] = {
		"INSERT OR IGNORE INTO pkg_search(id, name, origin) "
		"VALUES (?1, ?2 || '-' || ?3, ?4);",
		"ITTT"
-
	}
+
	},
+
	[PROVIDE] = {
+
		NULL,
+
		"INSERT OR IGNORE INTO provides(provide) VALUES(?1)",
+
		"T",
+
	},
+
	[PROVIDES] = {
+
		NULL,
+
		"INSERT OR IGNORE INTO pkg_provides(package_id, provide_id) "
+
		"VALUES (?1, (SELECT id FROM provides WHERE provide = ?2))",
+
		"IT",
+
	},
+
	[REQUIRE] = {
+
		NULL,
+
		"INSERT OR IGNORE INTO requires(require) VALUES(?1)",
+
		"T",
+
	},
+
	[REQUIRES] = {
+
		NULL,
+
		"INSERT OR IGNORE INTO pkg_requires(package_id, require_id) "
+
		"VALUES (?1, (SELECT id FROM requires WHERE require = ?2))",
+
		"IT",
+
	},
	/* PRSTMT_LAST */
};

modified libpkg/repo/binary/query.c
@@ -184,6 +184,44 @@ pkg_repo_binary_shlib_provide(struct pkg_repo *repo, const char *require)
}

struct pkg_repo_it *
+
pkg_repo_binary_provide(struct pkg_repo *repo, const char *require)
+
{
+
	sqlite3_stmt	*stmt;
+
	sqlite3 *sqlite = PRIV_GET(repo);
+
	struct sbuf	*sql = NULL;
+
	int		 ret;
+
	const char	 basesql[] = ""
+
			"SELECT p.id, p.origin, p.name, p.version, p.comment, "
+
			"p.name as uniqueid, "
+
			"p.prefix, p.desc, p.arch, p.maintainer, p.www, "
+
			"p.licenselogic, p.flatsize, p.pkgsize, "
+
			"p.cksum, p.manifestdigest, p.path AS repopath, '%s' AS dbname "
+
			"FROM packages AS p INNER JOIN pkg_provides AS ps ON "
+
			"p.id = ps.package_id "
+
			"WHERE ps.provide_id IN (SELECT id from provides WHERE "
+
			"name BETWEEN ?1 AND ?1 || '.9');";
+

+
	sql = sbuf_new_auto();
+
	sbuf_printf(sql, basesql, repo->name);
+

+
	sbuf_finish(sql);
+

+
	pkg_debug(4, "Pkgdb: running '%s'", sbuf_get(sql));
+
	ret = sqlite3_prepare_v2(sqlite, sbuf_get(sql), -1, &stmt, NULL);
+
	if (ret != SQLITE_OK) {
+
		ERROR_SQLITE(sqlite, sbuf_get(sql));
+
		sbuf_delete(sql);
+
		return (NULL);
+
	}
+

+
	sbuf_delete(sql);
+

+
	sqlite3_bind_text(stmt, 1, require, -1, SQLITE_TRANSIENT);
+

+
	return (pkg_repo_binary_it_new(repo, stmt, PKGDB_IT_FLAG_ONCE));
+
}
+

+
struct pkg_repo_it *
pkg_repo_binary_shlib_require(struct pkg_repo *repo, const char *provide)
{
	sqlite3_stmt	*stmt;
@@ -215,11 +253,48 @@ pkg_repo_binary_shlib_require(struct pkg_repo *repo, const char *provide)

	sbuf_delete(sql);

+
	pkg_debug(1, "> loading provides");
	sqlite3_bind_text(stmt, 1, provide, -1, SQLITE_TRANSIENT);

	return (pkg_repo_binary_it_new(repo, stmt, PKGDB_IT_FLAG_ONCE));
}

+
struct pkg_repo_it *
+
pkg_repo_binary_require(struct pkg_repo *repo, const char *provide)
+
{
+
	sqlite3_stmt	*stmt;
+
	sqlite3 *sqlite = PRIV_GET(repo);
+
	struct sbuf	*sql = NULL;
+
	int		 ret;
+
	const char	 basesql[] = ""
+
			"SELECT p.id, p.origin, p.name, p.version, p.comment, "
+
			"p.name as uniqueid, "
+
			"p.prefix, p.desc, p.arch, p.maintainer, p.www, "
+
			"p.licenselogic, p.flatsize, p.pkgsize, "
+
			"p.cksum, p.manifestdigest, p.path AS repopath, '%s' AS dbname "
+
			"FROM packages AS p INNER JOIN pkg_requires AS ps ON "
+
			"p.id = ps.package_id "
+
			"WHERE ps.require_id = (SELECT id FROM requires WHERE name=?1);";
+

+
	sql = sbuf_new_auto();
+
	sbuf_printf(sql, basesql, repo->name);
+

+
	sbuf_finish(sql);
+

+
	pkg_debug(4, "Pkgdb: running '%s'", sbuf_get(sql));
+
	ret = sqlite3_prepare_v2(sqlite, sbuf_get(sql), -1, &stmt, NULL);
+
	if (ret != SQLITE_OK) {
+
		ERROR_SQLITE(sqlite, sbuf_get(sql));
+
		sbuf_delete(sql);
+
		return (NULL);
+
	}
+

+
	sbuf_delete(sql);
+

+
	sqlite3_bind_text(stmt, 1, provide, -1, SQLITE_TRANSIENT);
+

+
	return (pkg_repo_binary_it_new(repo, stmt, PKGDB_IT_FLAG_ONCE));
+
}
static const char *
pkg_repo_binary_search_how(match_t match)
{
modified libpkg/repo/binary/update.c
@@ -139,6 +139,7 @@ pkg_repo_binary_add_pkg(struct pkg *pkg, const char *pkg_path,
	struct pkg_dep		*dep      = NULL;
	struct pkg_option	*option   = NULL;
	struct pkg_shlib	*shlib    = NULL;
+
	struct pkg_provide	*provide  = NULL;
	struct pkg_strel	*el;
	struct pkg_kv		*kv;
	const char		*arch;
@@ -247,6 +248,30 @@ try_again:
		}
	}

+
	provide = NULL;
+
	while (pkg_provides(pkg, &provide) == EPKG_OK) {
+
		ret = pkg_repo_binary_run_prstatement(PROVIDE, provide->provide);
+
		if (ret == SQLITE_DONE)
+
			ret = pkg_repo_binary_run_prstatement(PROVIDES, package_id,
+
			    provide->provide);
+
		if (ret != SQLITE_DONE) {
+
			ERROR_SQLITE(sqlite, pkg_repo_binary_sql_prstatement(PROVIDES));
+
			return (EPKG_FATAL);
+
		}
+
	}
+

+
	provide = NULL;
+
	while (pkg_requires(pkg, &provide) == EPKG_OK) {
+
		ret = pkg_repo_binary_run_prstatement(REQUIRE, provide->provide);
+
		if (ret == SQLITE_DONE)
+
			ret = pkg_repo_binary_run_prstatement(REQUIRES, package_id,
+
			    provide->provide);
+
		if (ret != SQLITE_DONE) {
+
			ERROR_SQLITE(sqlite, pkg_repo_binary_sql_prstatement(REQUIRES));
+
			return (EPKG_FATAL);
+
		}
+
	}
+

	LL_FOREACH(pkg->annotations, kv) {
		ret = pkg_repo_binary_run_prstatement(ANNOTATE1, kv->key);
		if (ret == SQLITE_DONE)
modified src/create.c
@@ -83,6 +83,7 @@ pkg_create_matches(int argc, char **argv, match_t match, pkg_formats fmt,
	    PKG_LOAD_CATEGORIES | PKG_LOAD_DIRS | PKG_LOAD_SCRIPTS |
	    PKG_LOAD_OPTIONS | PKG_LOAD_LICENSES |
	    PKG_LOAD_USERS | PKG_LOAD_GROUPS | PKG_LOAD_SHLIBS_REQUIRED |
+
	    PKG_LOAD_PROVIDES | PKG_LOAD_REQUIRES |
	    PKG_LOAD_SHLIBS_PROVIDED | PKG_LOAD_ANNOTATIONS;
	struct pkg_head head = STAILQ_HEAD_INITIALIZER(head);
	struct pkg_entry *e = NULL;
modified tests/frontend/Kyuafile
@@ -12,6 +12,7 @@ atf_test_program{name='lock.sh'}
atf_test_program{name='packagesplit.sh'}
atf_test_program{name='pkg.sh'}
atf_test_program{name='register.sh'}
+
atf_test_program{name='requires.sh'}
atf_test_program{name='rubypuppet.sh'}
atf_test_program{name='search.sh'}
atf_test_program{name='set.sh'}
added tests/frontend/requires.shin
@@ -0,0 +1,90 @@
+
#! /usr/bin/env atf-sh
+

+
atf_test_case requires
+
requires_head() {
+
	atf_set "descr" "Testings requires"
+
}
+

+
requires_body() {
+
	export PKG_DBDIR=.
+
	export INSTALL_AS_USER=yes
+

+
	cat << EOF >> repo.conf
+
local1: {
+
	url: file://${TMPDIR},
+
	enabled: true
+
}
+
EOF
+

+
	cat << EOF > a.ucl
+
name: a
+
origin: a
+
version: "1.0"
+
maintainer: test
+
categories: [test]
+
comment: a test
+
www: http://test
+
prefix: /usr/local
+
desc: <<EOD
+
Yet another test
+
EOD
+
provides: [a]
+
EOF
+

+
	cat << EOF > b.ucl
+
name: b
+
origin: b
+
version: "1.0"
+
maintainer: test
+
categories: [test]
+
comment: a test
+
www: http://test
+
prefix: /usr/local
+
desc: <<EOD
+
Yet another test
+
EOD
+
requires: [a]
+
EOF
+
	for p in a b; do
+
		atf_check \
+
			-o ignore \
+
			-e empty \
+
			-s exit:0 \
+
			pkg create -M ./${p}.ucl
+
	done
+

+
	atf_check \
+
		-o ignore \
+
		-e empty \
+
		-s exit:0 \
+
		pkg repo .
+

+
	if [ "$jailed" = "1" ]; then
+
		JAILED="[`hostname`] "
+
	fi
+
OUTPUT="Updating local1 repository catalogue...
+
${JAILED}Fetching meta.txz... done
+
${JAILED}Fetching packagesite.txz... done
+
Processing entries... done
+
local1 repository update completed. 2 packages processed.
+
Checking integrity... done (0 conflicting)
+
The following 2 packages will be affected (of 0 checked):
+

+
New packages to be INSTALLED:
+
	b: 1.0
+
	a: 1.0
+
"
+

+
	atf_check \
+
		-o inline:"${OUTPUT}" \
+
		-e empty \
+
		-s exit:0 \
+
		pkg -o REPOS_DIR="${TMPDIR}" install -n b
+
}
+

+
atf_init_test_cases() {
+
        . $(atf_get_srcdir)/test_environment.sh
+

+
	atf_add_test_case requires
+
}
+