diff --git a/bin/xbps-query/show-deps.c b/bin/xbps-query/show-deps.c index 8be38e6d..6e52612c 100644 --- a/bin/xbps-query/show-deps.c +++ b/bin/xbps-query/show-deps.c @@ -127,95 +127,21 @@ repo_show_pkg_deps(struct xbps_handle *xhp, const char *pattern, bool full) return 0; } -static int -repo_revdeps_cb(struct xbps_repo *repo, void *arg, bool *done) -{ - prop_dictionary_t pkgd; - prop_array_t pkgdeps; - prop_object_iterator_t iter; - prop_object_t obj; - const char *pkgver, *arch, *pattern = arg; - int rv = 0; - - (void)done; - - iter = prop_dictionary_iterator(repo->idx); - assert(iter); - while ((obj = prop_object_iterator_next(iter))) { - pkgd = prop_dictionary_get_keysym(repo->idx, obj); - pkgdeps = prop_dictionary_get(pkgd, "run_depends"); - if (pkgdeps == NULL || prop_array_count(pkgdeps) == 0) - continue; - - if (xbps_match_pkgdep_in_array(pkgdeps, pattern)) { - prop_dictionary_get_cstring_nocopy(pkgd, - "architecture", &arch); - if (xbps_pkg_arch_match(repo->xhp, arch, NULL)) { - prop_dictionary_get_cstring_nocopy(pkgd, - "pkgver", &pkgver); - printf("%s\n", pkgver); - rv = EEXIST; - } - } - } - prop_object_iterator_release(iter); - return rv; -} - int repo_show_pkg_revdeps(struct xbps_handle *xhp, const char *pkg) { - prop_array_t vdeps; - prop_dictionary_t pkgd = NULL; - const char *pkgver, *vpkg; + prop_array_t revdeps; + const char *pkgver; unsigned int i; - int rv = 0; - bool matched = false; + int rv; - if (xbps_pkg_version(pkg)) - pkgver = pkg; - else { - if (((pkgd = xbps_rpool_get_pkg(xhp, pkg)) == NULL) && - ((pkgd = xbps_rpool_get_virtualpkg(xhp, pkg)) == NULL)) - return ENOENT; + revdeps = xbps_rpool_get_pkg_revdeps(xhp, pkg); + rv = errno; + + for (i = 0; i < prop_array_count(revdeps); i++) { + prop_array_get_cstring_nocopy(revdeps, i, &pkgver); + printf("%s\n", pkgver); } - /* - * If pkg is a virtual pkg let's match it instead of the real pkgver. - */ - if (pkgd) { - if ((vdeps = prop_dictionary_get(pkgd, "provides"))) { - for (i = 0; i < prop_array_count(vdeps); i++) { - char *buf, *vpkgn; - prop_array_get_cstring_nocopy(vdeps, i, &vpkg); - if (strchr(vpkg, '_') == NULL) - buf = xbps_xasprintf("%s_1", vpkg); - else - buf = strdup(vpkg); - - vpkgn = xbps_pkg_name(buf); - assert(vpkgn); - if (strcmp(vpkgn, pkg)) { - free(vpkgn); - free(buf); - continue; - } - free(vpkgn); - rv = xbps_rpool_foreach(xhp, repo_revdeps_cb, - __UNCONST(buf)); - free(buf); - if (rv == EEXIST) { - rv = 0; - matched = true; - } - } - } - if (!matched) { - prop_dictionary_get_cstring_nocopy(pkgd, - "pkgver", &pkgver); - rv = xbps_rpool_foreach(xhp, repo_revdeps_cb, - __UNCONST(pkgver)); - } - } return rv; } diff --git a/include/xbps_api.h.in b/include/xbps_api.h.in index 45315516..d9e693b3 100644 --- a/include/xbps_api.h.in +++ b/include/xbps_api.h.in @@ -41,7 +41,7 @@ * * This header documents the full API for the XBPS Library. */ -#define XBPS_API_VERSION "20130609" +#define XBPS_API_VERSION "20130614" #ifndef XBPS_VERSION #define XBPS_VERSION "UNSET" @@ -1219,6 +1219,18 @@ prop_dictionary_t xbps_rpool_get_pkg(struct xbps_handle *xhp, const char *pkg); prop_dictionary_t xbps_rpool_get_virtualpkg(struct xbps_handle *xhp, const char *pkg); +/** + * Returns a proplib array of strings with reverse dependencies of all + * registered repositories matching the expression \a pkg. + * + * @param[in] xhp Pointer to the xbps_handle structure. + * @param[in] pkg Package expression to match in this repository index. + * + * @return The array of strings on success, NULL otherwise and errno is + * set appropiately. + */ +prop_array_t xbps_rpool_get_pkg_revdeps(struct xbps_handle *xhp, const char *pkg); + /** * Iterate over the the repository pool and search for a metadata plist * file in a binary package matching `pattern'. If a package is matched @@ -1310,6 +1322,18 @@ prop_dictionary_t xbps_repo_get_pkg(struct xbps_repo *repo, const char *pkg); prop_dictionary_t xbps_repo_get_virtualpkg(struct xbps_repo *repo, const char *pkg); +/** + * Returns a proplib array of strings with reverse dependencies from + * repository \a repo matching the expression \a pkg. + * + * @param[in] repo Pointer to an xbps_repo structure. + * @param[in] pkg Package expression to match in this repository index. + * + * @return The array of strings on success, NULL otherwise and errno is + * set appropiately. + */ +prop_array_t xbps_repo_get_pkg_revdeps(struct xbps_repo *repo, const char *pkg); + /*@}*/ /** @addtogroup archive_util */ diff --git a/lib/repo.c b/lib/repo.c index 3896eed6..15469dac 100644 --- a/lib/repo.c +++ b/lib/repo.c @@ -189,3 +189,149 @@ xbps_repo_get_pkg(struct xbps_repo *repo, const char *pkg) return NULL; } + +static prop_array_t +revdeps_match(struct xbps_repo *repo, prop_dictionary_t tpkgd, const char *str) +{ + prop_dictionary_t pkgd; + prop_array_t revdeps = NULL, pkgdeps, provides; + prop_object_iterator_t iter; + prop_object_t obj; + const char *pkgver, *tpkgver, *arch, *vpkg; + char *buf; + unsigned int i; + + iter = prop_dictionary_iterator(repo->idx); + assert(iter); + + while ((obj = prop_object_iterator_next(iter))) { + pkgd = prop_dictionary_get_keysym(repo->idx, obj); + if (prop_dictionary_equals(pkgd, tpkgd)) + continue; + + pkgdeps = prop_dictionary_get(pkgd, "run_depends"); + if (pkgdeps == NULL || !prop_array_count(pkgdeps)) + continue; + /* + * Try to match passed in string. + */ + if (str) { + if (!xbps_match_pkgdep_in_array(pkgdeps, str)) + continue; + prop_dictionary_get_cstring_nocopy(pkgd, + "architecture", &arch); + if (!xbps_pkg_arch_match(repo->xhp, arch, NULL)) + continue; + + prop_dictionary_get_cstring_nocopy(pkgd, + "pkgver", &tpkgver); + /* match */ + if (revdeps == NULL) + revdeps = prop_array_create(); + + if (!xbps_match_string_in_array(revdeps, tpkgver)) + prop_array_add_cstring_nocopy(revdeps, tpkgver); + + continue; + } + /* + * Try to match any virtual package. + */ + provides = prop_dictionary_get(tpkgd, "provides"); + for (i = 0; i < prop_array_count(provides); i++) { + prop_array_get_cstring_nocopy(provides, i, &vpkg); + if (strchr(vpkg, '_') == NULL) + buf = xbps_xasprintf("%s_1", vpkg); + else + buf = strdup(vpkg); + + if (!xbps_match_pkgdep_in_array(pkgdeps, buf)) { + free(buf); + continue; + } + free(buf); + prop_dictionary_get_cstring_nocopy(pkgd, + "architecture", &arch); + if (!xbps_pkg_arch_match(repo->xhp, arch, NULL)) + continue; + + prop_dictionary_get_cstring_nocopy(pkgd, "pkgver", + &tpkgver); + /* match */ + if (revdeps == NULL) + revdeps = prop_array_create(); + + if (!xbps_match_string_in_array(revdeps, tpkgver)) + prop_array_add_cstring_nocopy(revdeps, tpkgver); + } + /* + * Try to match by pkgver. + */ + prop_dictionary_get_cstring_nocopy(tpkgd, "pkgver", &pkgver); + if (!xbps_match_pkgdep_in_array(pkgdeps, pkgver)) + continue; + + prop_dictionary_get_cstring_nocopy(pkgd, + "architecture", &arch); + if (!xbps_pkg_arch_match(repo->xhp, arch, NULL)) + continue; + + prop_dictionary_get_cstring_nocopy(pkgd, "pkgver", &tpkgver); + /* match */ + if (revdeps == NULL) + revdeps = prop_array_create(); + + if (!xbps_match_string_in_array(revdeps, tpkgver)) + prop_array_add_cstring_nocopy(revdeps, tpkgver); + } + prop_object_iterator_release(iter); + return revdeps; +} + +prop_array_t +xbps_repo_get_pkg_revdeps(struct xbps_repo *repo, const char *pkg) +{ + prop_array_t revdeps = NULL, vdeps = NULL; + prop_dictionary_t pkgd; + const char *vpkg; + char *buf = NULL; + unsigned int i; + + if (((pkgd = xbps_rpool_get_pkg(repo->xhp, pkg)) == NULL) && + ((pkgd = xbps_rpool_get_virtualpkg(repo->xhp, pkg)) == NULL)) { + errno = ENOENT; + return NULL; + } + /* + * If pkg is a virtual pkg let's match it instead of the real pkgver. + */ + if ((vdeps = prop_dictionary_get(pkgd, "provides"))) { + for (i = 0; i < prop_array_count(vdeps); i++) { + char *vpkgn; + + prop_array_get_cstring_nocopy(vdeps, i, &vpkg); + if (strchr(vpkg, '_') == NULL) + buf = xbps_xasprintf("%s_1", vpkg); + else + buf = strdup(vpkg); + + vpkgn = xbps_pkg_name(buf); + assert(vpkgn); + if (strcmp(vpkgn, pkg) == 0) { + free(vpkgn); + break; + } + free(vpkgn); + free(buf); + buf = NULL; + } + if (buf) { + revdeps = revdeps_match(repo, pkgd, buf); + free(buf); + } + } + if (!prop_array_count(revdeps)) + revdeps = revdeps_match(repo, pkgd, NULL); + + return revdeps; +} diff --git a/lib/rpool_get.c b/lib/rpool_get.c index 07658ab3..08905c7f 100644 --- a/lib/rpool_get.c +++ b/lib/rpool_get.c @@ -37,6 +37,7 @@ * @defgroup repopool Repository pool functions */ struct rpool_fpkg { + prop_array_t revdeps; prop_dictionary_t pkgd; const char *pattern; const char *bestpkgver; @@ -73,6 +74,30 @@ find_pkg_cb(struct xbps_repo *repo, void *arg, bool *done) return 0; } +static int +find_pkg_revdeps_cb(struct xbps_repo *repo, void *arg, bool *done) +{ + struct rpool_fpkg *rpf = arg; + prop_array_t revdeps = NULL; + const char *pkgver; + unsigned int i; + + (void)done; + + revdeps = xbps_repo_get_pkg_revdeps(repo, rpf->pattern); + if (prop_array_count(revdeps)) { + /* found */ + if (rpf->revdeps == NULL) + rpf->revdeps = prop_array_create(); + for (i = 0; i < prop_array_count(revdeps); i++) { + prop_array_get_cstring_nocopy(revdeps, i, &pkgver); + prop_array_add_cstring_nocopy(rpf->revdeps, pkgver); + } + prop_object_release(revdeps); + } + return 0; +} + static int find_best_pkg_cb(struct xbps_repo *repo, void *arg, bool *done) { @@ -123,10 +148,11 @@ find_best_pkg_cb(struct xbps_repo *repo, void *arg, bool *done) typedef enum { BEST_PKG = 1, VIRTUAL_PKG, - REAL_PKG + REAL_PKG, + REVDEPS_PKG } pkg_repo_type_t; -static prop_dictionary_t +static prop_object_t repo_find_pkg(struct xbps_handle *xhp, const char *pkg, pkg_repo_type_t type) @@ -136,6 +162,7 @@ repo_find_pkg(struct xbps_handle *xhp, rpf.pattern = pkg; rpf.pkgd = NULL; + rpf.revdeps = NULL; rpf.bestpkgver = NULL; switch (type) { @@ -157,11 +184,18 @@ repo_find_pkg(struct xbps_handle *xhp, */ rv = xbps_rpool_foreach(xhp, find_pkg_cb, &rpf); break; + case REVDEPS_PKG: + /* + * Find revdeps for pkg. + */ + rv = xbps_rpool_foreach(xhp, find_pkg_revdeps_cb, &rpf); } if (rv != 0) { errno = rv; return NULL; } + if (type == REVDEPS_PKG) + return rpf.revdeps; return rpf.pkgd; } @@ -187,6 +221,15 @@ xbps_rpool_get_pkg(struct xbps_handle *xhp, const char *pkg) return repo_find_pkg(xhp, pkg, REAL_PKG); } +prop_array_t +xbps_rpool_get_pkg_revdeps(struct xbps_handle *xhp, const char *pkg) +{ + assert(xhp); + assert(pkg); + + return repo_find_pkg(xhp, pkg, REVDEPS_PKG); +} + prop_dictionary_t xbps_rpool_get_pkg_plist(struct xbps_handle *xhp, const char *pkg,