From f45352dbf881f8f825869470192c16b8eacd4041 Mon Sep 17 00:00:00 2001 From: Juan RP Date: Fri, 30 Nov 2012 17:40:52 +0100 Subject: [PATCH] Added support for dynamic generation of revdeps for installed packages. --- NEWS | 24 ++++ bin/xbps-pkgdb/Makefile | 2 +- bin/xbps-pkgdb/check.c | 29 ++-- bin/xbps-pkgdb/check_pkg_requiredby.c | 188 -------------------------- bin/xbps-pkgdb/defs.h | 1 - bin/xbps-query/show-deps.c | 21 ++- bin/xbps-query/show-info-files.c | 1 - bin/xbps-remove/main.c | 7 +- include/xbps_api.h.in | 15 +- include/xbps_api_impl.h | 7 - lib/Makefile | 3 +- lib/package_orphans.c | 5 +- lib/package_register.c | 42 +++--- lib/package_remove.c | 18 +-- lib/package_requiredby.c | 177 ------------------------ lib/pkgdb.c | 74 +++++++++- lib/transaction_ops.c | 2 +- lib/transaction_package_replace.c | 28 +--- 18 files changed, 165 insertions(+), 479 deletions(-) delete mode 100644 bin/xbps-pkgdb/check_pkg_requiredby.c delete mode 100644 lib/package_requiredby.c diff --git a/NEWS b/NEWS index 945b2ad3..5b221642 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,27 @@ +xbps-0.19 (???): + + * Added support for dynamic generation of reverse dependencies for + installed packages. pkgdb no longer keeps track of them statically. + A new object must be present in pkgdb for this to work in fast mode, + which is available if 'xbps-pkgdb(8) -a' is run; otherwise the + fallback mode will be used which is a bit slower. + + * xbps-query(8): added support to specify any of the three supported + methods to match package expressions: + + - by package name (foo) + - by exact package version (foo-2.0_1) + - by package version comparators (foo>2.1<2.5) + + * Multiple API/ABI changes to improve performance; The libxbps SONAME + major has been bumped to 1. This helped to fix some regressions + introduced in 0.18 and really simplifies the API. + + * New repository index format (1.6). The index files are now dictionaries + that won't allow to add duplicate entries; also the files are now + "architecture" dependent and only packages for target arch and + noarch will be registered on it. + xbps-0.18.1 (2012-11-26): * Fixed execution of pre/post install/remove scripts due to using old diff --git a/bin/xbps-pkgdb/Makefile b/bin/xbps-pkgdb/Makefile index 2c81ce52..d9d1f390 100644 --- a/bin/xbps-pkgdb/Makefile +++ b/bin/xbps-pkgdb/Makefile @@ -3,7 +3,7 @@ TOPDIR = ../.. BIN = xbps-pkgdb OBJS = main.o check.o check_pkg_files.o -OBJS += check_pkg_requiredby.o check_pkg_rundeps.o +OBJS += check_pkg_rundeps.o OBJS += check_pkg_symlinks.o check_pkg_unneeded.o OBJS += convert.o diff --git a/bin/xbps-pkgdb/check.c b/bin/xbps-pkgdb/check.c index 0d5bf10c..b9f79891 100644 --- a/bin/xbps-pkgdb/check.c +++ b/bin/xbps-pkgdb/check.c @@ -91,6 +91,7 @@ check_pkg_integrity(struct xbps_handle *xhp, prop_dictionary_t pkgd, const char *pkgname) { + prop_array_t rundeps; prop_dictionary_t opkgd, propsd; const char *sha256; char *buf; @@ -100,13 +101,9 @@ check_pkg_integrity(struct xbps_handle *xhp, /* find real pkg by name */ opkgd = pkgd; - if (pkgd == NULL) { - opkgd = xbps_pkgdb_get_pkg(xhp, pkgname); - if (opkgd == NULL) { - /* find virtual pkg by name */ - opkgd = xbps_pkgdb_get_virtualpkg(xhp, pkgname); - } - if (opkgd == NULL) { + if (opkgd == NULL) { + if (((opkgd = xbps_pkgdb_get_pkg(xhp, pkgname)) == NULL) && + ((opkgd = xbps_pkgdb_get_virtualpkg(xhp, pkgname)) == NULL)) { printf("Package %s is not installed.\n", pkgname); return 0; } @@ -127,7 +124,24 @@ check_pkg_integrity(struct xbps_handle *xhp, xbps_error_printf("%s: incomplete metadata file.\n", pkgname); return 1; } + /* + * Check if pkgdb pkg has been converted to 0.19 format, + * which adds "run_depends" array object. + */ + rundeps = prop_dictionary_get(opkgd, "run_depends"); + if (rundeps == NULL) { + rundeps = prop_dictionary_get(propsd, "run_depends"); + if (rundeps == NULL) + rundeps = prop_array_create(); + prop_dictionary_set(opkgd, "run_depends", rundeps); + /* remove requiredby object, unneeded since 0.19 */ + prop_dictionary_remove(opkgd, "requiredby"); + } + + /* + * Check pkg metadata signature. + */ prop_dictionary_get_cstring_nocopy(opkgd, "metafile-sha256", &sha256); if (sha256 != NULL) { buf = xbps_xasprintf("%s/.%s.plist", @@ -155,7 +169,6 @@ do { \ RUN_PKG_CHECK(xhp, files, propsd); RUN_PKG_CHECK(xhp, symlinks, propsd); RUN_PKG_CHECK(xhp, rundeps, propsd); - RUN_PKG_CHECK(xhp, requiredby, opkgd); RUN_PKG_CHECK(xhp, unneeded, opkgd); #undef RUN_PKG_CHECK diff --git a/bin/xbps-pkgdb/check_pkg_requiredby.c b/bin/xbps-pkgdb/check_pkg_requiredby.c deleted file mode 100644 index 7b5881ca..00000000 --- a/bin/xbps-pkgdb/check_pkg_requiredby.c +++ /dev/null @@ -1,188 +0,0 @@ -/*- - * Copyright (c) 2011-2012 Juan Romero Pardines. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include -#include -#include -#include -#include -#include -#include - -#include -#include "defs.h" - -static int -check_reqby_pkg_cb(struct xbps_handle *xhp, - prop_object_t obj, - void *arg, - bool *done) -{ - prop_dictionary_t pkgd = arg; - prop_array_t curpkg_rdeps, provides, pkgd_reqby; - prop_dictionary_t curpkg_propsd; - prop_string_t curpkgver; - const char *curpkgn, *pkgname, *pkgver; - - (void)done; - - prop_dictionary_get_cstring_nocopy(pkgd, "pkgname", &pkgname); - prop_dictionary_get_cstring_nocopy(pkgd, "pkgver", &pkgver); - prop_dictionary_get_cstring_nocopy(obj, "pkgname", &curpkgn); - /* skip same pkg */ - if (strcmp(curpkgn, pkgname) == 0) - return 0; - - /* - * Internalize current pkg props dictionary from its - * installed metadata directory. - */ - curpkg_propsd = xbps_pkgdb_get_pkg_metadata(xhp, curpkgn); - if (curpkg_propsd == NULL) { - xbps_error_printf("%s: missing %s metadata file!\n", - curpkgn, XBPS_PKGPROPS); - return -1; - } - curpkg_rdeps = - prop_dictionary_get(curpkg_propsd, "run_depends"); - if (curpkg_rdeps == NULL) { - /* package has no rundeps, skip */ - return 0; - } - /* - * Check for pkgpattern match with real packages... - */ - if (!xbps_match_pkgdep_in_array(curpkg_rdeps, pkgver)) { - /* - * ... otherwise check if package provides any virtual - * package and is matched against any object in - * run_depends. - */ - provides = prop_dictionary_get(pkgd, "provides"); - if (provides == NULL) { - /* doesn't provide any virtual pkg */ - return 0; - } - if (!xbps_match_any_virtualpkg_in_rundeps(curpkg_rdeps, - provides)) { - /* doesn't match any virtual pkg */ - return 0; - } - } - pkgd_reqby = prop_dictionary_get(pkgd, "requiredby"); - curpkgver = prop_dictionary_get(curpkg_propsd, "pkgver"); - if (pkgd_reqby != NULL) { - /* - * Now check that current pkgver has been registered into - * its requiredby array. - */ - if (xbps_match_string_in_array(pkgd_reqby, - prop_string_cstring_nocopy(curpkgver))) { - /* - * Current package already requires our package, - * this is good so skip it. - */ - return 0; - } - } else { - /* - * Missing requiredby array object, create it. - */ - pkgd_reqby = prop_array_create(); - assert(pkgd_reqby); - } - /* - * Added pkgdep into pkg's requiredby array. - */ - if (!prop_array_add(pkgd_reqby, curpkgver)) - return -1; - - prop_dictionary_set(pkgd, "requiredby", pkgd_reqby); - - printf("%s: added requiredby entry for %s.\n", - pkgver, prop_string_cstring_nocopy(curpkgver)); - - return 0; -} - -/* - * Removes unused entries in pkg's requiredby array. - */ -static void -remove_stale_entries_in_reqby(struct xbps_handle *xhp, prop_dictionary_t pkgd) -{ - prop_array_t reqby; - const char *pkgver; - char *str; - size_t i; - - prop_dictionary_get_cstring_nocopy(pkgd, "pkgver", &pkgver); - -again: - reqby = prop_dictionary_get(pkgd, "requiredby"); - if (reqby == NULL || prop_array_count(reqby) == 0) - return; - - for (i = 0; i < prop_array_count(reqby); i++) { - prop_array_get_cstring(reqby, i, &str); - if ((pkgd = xbps_pkgdb_get_pkg(xhp, str)) != NULL) - continue; - - prop_array_remove(reqby, i); - printf("%s: removed stale entry in requiredby `%s'\n", - pkgver, str); - prop_dictionary_set(pkgd, "requiredby", reqby); - free(str); - goto again; - } -} - -/* - * Checks package integrity of an installed package. - * The following task is accomplished in this file: - * - * o Check for missing reverse dependencies (aka requiredby) - * entries in pkg's pkgdb dictionary. - * - * Returns 0 if test ran successfully, 1 otherwise and -1 on error. - */ -int -check_pkg_requiredby(struct xbps_handle *xhp, const char *pkgname, void *arg) -{ - prop_dictionary_t pkgd = arg; - int rv; - - (void)pkgname; - - /* missing reqby entries in pkgs */ - rv = xbps_pkgdb_foreach_cb(xhp, check_reqby_pkg_cb, pkgd); - if (rv != 0) - return rv; - - /* remove stale entries in pkg's reqby */ - remove_stale_entries_in_reqby(xhp, pkgd); - - return 0; -} diff --git a/bin/xbps-pkgdb/defs.h b/bin/xbps-pkgdb/defs.h index b43a71b4..24102650 100644 --- a/bin/xbps-pkgdb/defs.h +++ b/bin/xbps-pkgdb/defs.h @@ -40,7 +40,6 @@ CHECK_PKG_DECL(unneeded); CHECK_PKG_DECL(files); CHECK_PKG_DECL(rundeps); CHECK_PKG_DECL(symlinks); -CHECK_PKG_DECL(requiredby); /* from convert.c */ int convert_pkgd_metadir(struct xbps_handle *, prop_dictionary_t); diff --git a/bin/xbps-query/show-deps.c b/bin/xbps-query/show-deps.c index 1e739923..59e4c50f 100644 --- a/bin/xbps-query/show-deps.c +++ b/bin/xbps-query/show-deps.c @@ -54,19 +54,18 @@ show_pkg_deps(struct xbps_handle *xhp, const char *pkgname) int show_pkg_revdeps(struct xbps_handle *xhp, const char *pkg) { - prop_dictionary_t pkgd; - int rv = 0; + prop_array_t reqby; + const char *pkgdep; + size_t i; - pkgd = xbps_pkgdb_get_virtualpkg(xhp, pkg); - if (pkgd == NULL) { - pkgd = xbps_pkgdb_get_pkg(xhp, pkg); - if (pkgd == NULL) - return ENOENT; + reqby = xbps_pkgdb_get_pkg_revdeps(xhp, pkg); + if (reqby) { + for (i = 0; i < prop_array_count(reqby); i++) { + prop_array_get_cstring_nocopy(reqby, i, &pkgdep); + printf("%s\n", pkgdep); + } } - rv = xbps_callback_array_iter_in_dict(xhp, pkgd, "requiredby", - list_strings_sep_in_array, NULL); - - return rv; + return 0; } int diff --git a/bin/xbps-query/show-info-files.c b/bin/xbps-query/show-info-files.c index c260afad..9fe96a9a 100644 --- a/bin/xbps-query/show-info-files.c +++ b/bin/xbps-query/show-info-files.c @@ -162,7 +162,6 @@ show_pkg_info(prop_dictionary_t dict) obj = prop_dictionary_get_keysym(dict, keysym); /* ignore objs shown by other targets */ if ((strcmp(keyname, "run_depends") == 0) || - (strcmp(keyname, "requiredby") == 0) || (strcmp(keyname, "files") == 0) || (strcmp(keyname, "dirs") == 0) || (strcmp(keyname, "links") == 0)) diff --git a/bin/xbps-remove/main.c b/bin/xbps-remove/main.c index c4dd1651..21518a56 100644 --- a/bin/xbps-remove/main.c +++ b/bin/xbps-remove/main.c @@ -204,7 +204,6 @@ static int remove_pkg(struct xbps_handle *xhp, const char *pkgname, size_t cols, bool recursive) { - prop_dictionary_t pkgd; prop_array_t reqby; const char *pkgver; size_t x; @@ -213,11 +212,9 @@ remove_pkg(struct xbps_handle *xhp, const char *pkgname, size_t cols, rv = xbps_transaction_remove_pkg(xhp, pkgname, recursive); if (rv == EEXIST) { /* pkg has revdeps */ - pkgd = xbps_pkgdb_get_pkg(xhp, pkgname); - prop_dictionary_get_cstring_nocopy(pkgd, "pkgver", &pkgver); - reqby = prop_dictionary_get(pkgd, "requiredby"); + reqby = xbps_pkgdb_get_pkg_revdeps(xhp, pkgname); printf("WARNING: %s IS REQUIRED BY %u PACKAGE%s:\n\n", - pkgver, prop_array_count(reqby), + pkgname, prop_array_count(reqby), prop_array_count(reqby) > 1 ? "S" : ""); for (x = 0; x < prop_array_count(reqby); x++) { prop_array_get_cstring_nocopy(reqby, x, &pkgver); diff --git a/include/xbps_api.h.in b/include/xbps_api.h.in index 351a8444..a9f7b584 100644 --- a/include/xbps_api.h.in +++ b/include/xbps_api.h.in @@ -774,13 +774,26 @@ prop_dictionary_t xbps_pkgdb_get_virtualpkg(struct xbps_handle *xhp, * Returns the package dictionary with all metadata info for \a pkg. * * @param[in] xhp The pointer to the xbps_handle struct. - * @param[in] Package expression to match. + * @param[in] pkg Package expression to match. * * @return The matching package metadata dictionary, NULL otherwise. */ prop_dictionary_t xbps_pkgdb_get_pkg_metadata(struct xbps_handle *xhp, const char *pkg); +/** + * Returns a proplib array of strings with reverse dependencies + * for \a pkg. The array is generated dynamically based on the list + * of packages currently installed. + * + * @param[in] xhp The pointer to the xbps_handle struct. + * @param[in] pkg Package expression to match. + * + * @return A proplib array of strings with reverse dependencies for \a pkg. + */ +prop_array_t xbps_pkgdb_get_pkg_revdeps(struct xbps_handle *xhp, + const char *pkg); + /** * Removes a package dictionary from master package database (pkgdb) plist, * matching pkgname or pkgver object in \a pkg. diff --git a/include/xbps_api_impl.h b/include/xbps_api_impl.h index 9ade48b6..766bdee0 100644 --- a/include/xbps_api_impl.h +++ b/include/xbps_api_impl.h @@ -143,13 +143,6 @@ int HIDDEN xbps_repository_find_deps(struct xbps_handle *, prop_array_t, prop_dictionary_t); -/** - * @private - * From lib/package_requiredby.c - */ -int HIDDEN xbps_requiredby_pkg_add(struct xbps_handle *, prop_dictionary_t); -int HIDDEN xbps_requiredby_pkg_remove(struct xbps_handle *, const char *); - /** * @private * From lib/plist_find.c diff --git a/lib/Makefile b/lib/Makefile index 907f6f80..30fc0644 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -43,8 +43,7 @@ EXTOBJS += external/mkpath.o # libxbps OBJS = package_configure.o package_config_files.o package_orphans.o OBJS += package_remove.o package_remove_obsoletes.o package_state.o -OBJS += package_unpack.o package_requiredby.o package_register.o -OBJS += package_script.o +OBJS += package_unpack.o package_register.o package_script.o OBJS += transaction_commit.o transaction_package_replace.o OBJS += transaction_dictionary.o transaction_sortdeps.o transaction_ops.o OBJS += download.o initend.o pkgdb.o package_conflicts.o diff --git a/lib/package_orphans.c b/lib/package_orphans.c index a110d992..10b41706 100644 --- a/lib/package_orphans.c +++ b/lib/package_orphans.c @@ -74,7 +74,7 @@ find_orphan_pkg(struct xbps_handle *xhp, prop_array_t reqby; prop_object_t obj2; prop_object_iterator_t iter; - const char *pkgdep, *curpkgname; + const char *pkgdep, *curpkgname, *curpkgver; char *pkgdepname; unsigned int ndep = 0, cnt = 0; bool automatic = false; @@ -89,7 +89,8 @@ find_orphan_pkg(struct xbps_handle *xhp, if (!automatic) return 0; - reqby = prop_dictionary_get(obj, "requiredby"); + prop_dictionary_get_cstring_nocopy(obj, "pkgver", &curpkgver); + reqby = xbps_pkgdb_get_pkg_revdeps(xhp, curpkgver); if (reqby == NULL || ((cnt = prop_array_count(reqby)) == 0)) { /* * Add packages with empty or missing "requiredby" arrays. diff --git a/lib/package_register.c b/lib/package_register.c index 971ffcc8..d78d0be3 100644 --- a/lib/package_register.c +++ b/lib/package_register.c @@ -44,7 +44,7 @@ int xbps_register_pkg(struct xbps_handle *xhp, prop_dictionary_t pkgrd, bool flush) { prop_dictionary_t pkgd; - prop_array_t provides, reqby; + prop_array_t provides, rundeps; char outstr[64]; time_t t; struct tm *tmp; @@ -61,7 +61,7 @@ xbps_register_pkg(struct xbps_handle *xhp, prop_dictionary_t pkgrd, bool flush) prop_dictionary_get_cstring_nocopy(pkgrd, "pkgver", &pkgver); prop_dictionary_get_bool(pkgrd, "automatic-install", &autoinst); provides = prop_dictionary_get(pkgrd, "provides"); - reqby = prop_dictionary_get(pkgrd, "requiredby"); + rundeps = prop_dictionary_get(pkgrd, "run_depends"); xbps_set_cb_state(xhp, XBPS_STATE_REGISTER, 0, pkgname, version, NULL); @@ -96,12 +96,6 @@ xbps_register_pkg(struct xbps_handle *xhp, prop_dictionary_t pkgrd, bool flush) rv = EINVAL; goto out; } - if (reqby && !prop_dictionary_set(pkgd, "requiredby", reqby)) { - xbps_dbg_printf(xhp, "%s: invalid requiredby for %s\n", - __func__, pkgname); - rv = EINVAL; - goto out; - } prop_dictionary_get_bool(pkgd, "automatic-install", &autoinst); if (xhp->flags & XBPS_FLAG_INSTALL_AUTO) autoinst = true; @@ -137,26 +131,22 @@ xbps_register_pkg(struct xbps_handle *xhp, prop_dictionary_t pkgrd, bool flush) goto out; } - if (provides) { - if (!prop_dictionary_set(pkgd, "provides", provides)) { - xbps_dbg_printf(xhp, - "%s: invalid provides for %s\n", - __func__, pkgname); - rv = EINVAL; - goto out; - } + if (provides && !prop_dictionary_set(pkgd, "provides", provides)) { + xbps_dbg_printf(xhp, "%s: failed to set provides for %s\n", + __func__, pkgname); + rv = EINVAL; + goto out; } - /* - * Add the requiredby objects for dependent packages. - */ - if (pkgrd && xbps_pkg_has_rundeps(pkgrd)) { - if ((rv = xbps_requiredby_pkg_add(xhp, pkgrd)) != 0) { - xbps_dbg_printf(xhp, - "%s: requiredby add failed for %s\n", - __func__, pkgname); - goto out; - } + if (rundeps == NULL) + rundeps = prop_array_create(); + + if (!prop_dictionary_set(pkgd, "run_depends", rundeps)) { + xbps_dbg_printf(xhp, "%s: failed to set rundeps for %s\n", + __func__, pkgname); + rv = EINVAL; + goto out; } + /* * Create a hash for the pkg's metafile. */ diff --git a/lib/package_remove.c b/lib/package_remove.c index 84c0a347..0b6fc03b 100644 --- a/lib/package_remove.c +++ b/lib/package_remove.c @@ -47,8 +47,6 @@ * XBPS_FLAG_FORCE_REMOVE_FILES flag is set via xbps_init::flags member. * -# Its post-remove target specified in the REMOVE script * will be executed. - * -# Its requiredby objects will be removed from the installed packages - * database. * -# Its state will be changed to XBPS_PKG_STATE_HALF_REMOVED. * -# Its purge-remove target specified in the REMOVE script * will be executed. @@ -274,14 +272,14 @@ xbps_remove_pkg(struct xbps_handle *xhp, } /* * If updating a package, we just need to execute the current - * pre-remove action target, unregister its requiredby entries and - * continue. Its files will be overwritten later in unpack phase. + * pre-remove action target and we are done. Its files will be + * overwritten later in unpack phase. */ if (update) { if (pkgd) prop_object_release(pkgd); free(pkgname); - return xbps_requiredby_pkg_remove(xhp, pkgname); + return 0; } else if (soft_replace) { /* * Soft replace a package. Do not remove its files, but @@ -317,16 +315,6 @@ xbps_remove_pkg(struct xbps_handle *xhp, goto out; } } - /* - * Update the requiredby array of all required dependencies. - */ - if ((rv = xbps_requiredby_pkg_remove(xhp, pkgname)) != 0) { - xbps_set_cb_state(xhp, XBPS_STATE_REMOVE_FAIL, - rv, pkgname, version, - "%s: [remove] failed to remove requiredby entries: %s", - pkgver, strerror(rv)); - goto out; - } softreplace: /* diff --git a/lib/package_requiredby.c b/lib/package_requiredby.c deleted file mode 100644 index c26c5a75..00000000 --- a/lib/package_requiredby.c +++ /dev/null @@ -1,177 +0,0 @@ -/*- - * Copyright (c) 2009-2012 Juan Romero Pardines. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include -#include -#include -#include -#include - -#include "xbps_api_impl.h" - -static int -add_pkg_into_reqby(struct xbps_handle *xhp, - prop_dictionary_t pkgd, - const char *pkgver) -{ - prop_array_t reqby; - prop_string_t reqstr; - const char *curpkgver; - char *pkgname; - bool alloc = false; - - assert(prop_object_type(pkgd) == PROP_TYPE_DICTIONARY); - - if ((reqby = prop_dictionary_get(pkgd, "requiredby")) == NULL) { - alloc = true; - if ((reqby = prop_array_create()) == NULL) - return ENOMEM; - } - /* - * If the same entry already exist we are done. - */ - if (xbps_match_string_in_array(reqby, pkgver)) - return 0; - /* - * If an existing entry matching pkgname exists remove it - * and add new pkgver object. - */ - pkgname = xbps_pkg_name(pkgver); - if (pkgname == NULL) - return ENOMEM; - - if (xbps_match_pkgname_in_array(reqby, pkgname)) { - if (!xbps_remove_pkgname_from_array(reqby, pkgname)) { - xbps_dbg_printf(xhp, "%s: failed to remove %s reqby entry: " - "%s\n", __func__, pkgname, strerror(errno)); - free(pkgname); - return EINVAL; - } - } - free(pkgname); - - reqstr = prop_string_create_cstring(pkgver); - if (reqstr == NULL) { - if (alloc) - prop_object_release(reqby); - - return ENOMEM; - } - - prop_dictionary_get_cstring_nocopy(pkgd, "pkgver", &curpkgver); - xbps_dbg_printf(xhp, "%s: added reqby entry `%s'\n", curpkgver, pkgver); - - if (!xbps_add_obj_to_array(reqby, reqstr)) { - if (alloc) - prop_object_release(reqby); - - prop_object_release(reqstr); - return EINVAL; - } - - if (!alloc) - return 0; - - if (!xbps_add_obj_to_dict(pkgd, reqby, "requiredby")) { - if (alloc) - prop_object_release(reqby); - - return EINVAL; - } - - return 0; -} - -static int -remove_pkg_from_reqby(struct xbps_handle *xhp, - prop_object_t obj, - void *arg, - bool *loop_done) -{ - prop_array_t reqby; - const char *pkgname = arg; - - (void)xhp; - (void)loop_done; - - reqby = prop_dictionary_get(obj, "requiredby"); - if (reqby == NULL || prop_array_count(reqby) == 0) - return 0; - - if (xbps_match_pkgname_in_array(reqby, pkgname)) - if (!xbps_remove_pkgname_from_array(reqby, pkgname)) - return EINVAL; - - return 0; -} - -int HIDDEN -xbps_requiredby_pkg_remove(struct xbps_handle *xhp, const char *pkgname) -{ - assert(pkgname != NULL); - return xbps_pkgdb_foreach_cb(xhp, remove_pkg_from_reqby, __UNCONST(pkgname)); -} - -int HIDDEN -xbps_requiredby_pkg_add(struct xbps_handle *xhp, prop_dictionary_t pkgd) -{ - prop_array_t pkg_rdeps; - prop_object_t obj, pkgdbd; - prop_object_iterator_t iter; - const char *pkgver, *str; - int rv = 0; - - assert(prop_object_type(pkgd) == PROP_TYPE_DICTIONARY); - - prop_dictionary_get_cstring_nocopy(pkgd, "pkgver", &pkgver); - pkg_rdeps = prop_dictionary_get(pkgd, "run_depends"); - if (pkg_rdeps == NULL || prop_array_count(pkg_rdeps) == 0) - return EINVAL; - - iter = prop_array_iterator(pkg_rdeps); - if (iter == NULL) - return ENOMEM; - - while ((obj = prop_object_iterator_next(iter)) != NULL) { - str = prop_string_cstring_nocopy(obj); - if (str == NULL) { - rv = EINVAL; - break; - } - if (((pkgdbd = xbps_find_pkg_in_array(xhp->pkgdb, str)) == NULL) && - ((pkgdbd = xbps_find_virtualpkg_in_array(xhp, xhp->pkgdb, str)) == NULL)) { - rv = ENOENT; - xbps_dbg_printf(xhp, "%s: couldnt find `%s' " - "entry in pkgdb\n", __func__, str); - break; - } - rv = add_pkg_into_reqby(xhp, pkgdbd, pkgver); - if (rv != 0) - break; - } - prop_object_iterator_release(iter); - - return rv; -} diff --git a/lib/pkgdb.c b/lib/pkgdb.c index ec62c299..29dbfd74 100644 --- a/lib/pkgdb.c +++ b/lib/pkgdb.c @@ -186,17 +186,13 @@ xbps_pkgdb_get_virtualpkg(struct xbps_handle *xhp, const char *vpkg) return xbps_find_virtualpkg_in_array(xhp, xhp->pkgdb, vpkg); } -prop_dictionary_t -xbps_pkgdb_get_pkg_metadata(struct xbps_handle *xhp, const char *pkg) +static prop_dictionary_t +get_pkg_metadata(struct xbps_handle *xhp, prop_dictionary_t pkgd) { - prop_dictionary_t pkgd, pkg_metad; + prop_dictionary_t pkg_metad; const char *pkgname; char *plist; - pkgd = xbps_pkgdb_get_pkg(xhp, pkg); - if (pkgd == NULL) - return NULL; - prop_dictionary_get_cstring_nocopy(pkgd, "pkgname", &pkgname); if ((pkg_metad = prop_dictionary_get(xhp->pkg_metad, pkgname)) != NULL) @@ -221,6 +217,70 @@ xbps_pkgdb_get_pkg_metadata(struct xbps_handle *xhp, const char *pkg) return pkg_metad; } +prop_array_t +xbps_pkgdb_get_pkg_revdeps(struct xbps_handle *xhp, const char *pkg) +{ + prop_array_t rundeps, provides, result = NULL; + prop_dictionary_t pkgd, pkgdep_metad; + prop_object_t obj; + prop_object_iterator_t iter; + const char *pkgver, *curpkgver; + + if (xbps_pkgdb_init(xhp) != 0) + return NULL; + + pkgd = xbps_find_pkg_in_array(xhp->pkgdb, pkg); + if (pkgd == NULL) + return NULL; + + prop_dictionary_get_cstring_nocopy(pkgd, "pkgver", &pkgver); + provides = prop_dictionary_get(pkgd, "provides"); + + iter = prop_array_iterator(xhp->pkgdb); + assert(iter); + + while ((obj = prop_object_iterator_next(iter))) { + prop_dictionary_get_cstring_nocopy(obj, "pkgver", &curpkgver); + /* + * If run_depends is in pkgdb use it, otherwise fallback to + * the slower pkg metadata method. + */ + rundeps = prop_dictionary_get(obj, "run_depends"); + if (rundeps == NULL) { + pkgdep_metad = get_pkg_metadata(xhp, obj); + assert(pkgdep_metad); + rundeps = prop_dictionary_get(pkgdep_metad, + "run_depends"); + } + if (rundeps == NULL || !prop_array_count(rundeps)) + continue; + + if (xbps_match_pkgdep_in_array(rundeps, pkgver) || + (provides && + xbps_match_any_virtualpkg_in_rundeps(rundeps, provides))) { + if (result == NULL) + result = prop_array_create(); + + prop_array_add_cstring_nocopy(result, curpkgver); + } + } + prop_object_iterator_release(iter); + + return result; +} + +prop_dictionary_t +xbps_pkgdb_get_pkg_metadata(struct xbps_handle *xhp, const char *pkg) +{ + prop_dictionary_t pkgd; + + pkgd = xbps_pkgdb_get_pkg(xhp, pkg); + if (pkgd == NULL) + return NULL; + + return get_pkg_metadata(xhp, pkgd); +} + bool xbps_pkgdb_remove_pkg(struct xbps_handle *xhp, const char *pkg, bool flush) { diff --git a/lib/transaction_ops.c b/lib/transaction_ops.c index 32f9342e..e25f1c40 100644 --- a/lib/transaction_ops.c +++ b/lib/transaction_ops.c @@ -304,7 +304,7 @@ rmpkg: prop_dictionary_set_cstring_nocopy(pkgd, "transaction", "remove"); prop_array_add(unsorted, pkgd); xbps_dbg_printf(xhp, "%s: added into transaction (remove).\n", pkgver); - reqby = prop_dictionary_get(pkgd, "requiredby"); + reqby = xbps_pkgdb_get_pkg_revdeps(xhp, pkgver); /* * If target pkg is required by any installed pkg, the client must be aware * of this to take appropiate action. diff --git a/lib/transaction_package_replace.c b/lib/transaction_package_replace.c index 141aabff..98f43a5a 100644 --- a/lib/transaction_package_replace.c +++ b/lib/transaction_package_replace.c @@ -36,7 +36,7 @@ int HIDDEN xbps_transaction_package_replace(struct xbps_handle *xhp) { - prop_array_t replaces, instd_reqby, unsorted; + prop_array_t replaces, unsorted; prop_dictionary_t instd, reppkgd, filesd; prop_object_t obj, obj2; prop_object_iterator_t iter; @@ -84,7 +84,6 @@ xbps_transaction_package_replace(struct xbps_handle *xhp) xbps_dbg_printf(xhp, "Package `%s' will be replaced by `%s', " "matched with `%s'\n", curpkgver, pkgver, pattern); - instd_reqby = prop_dictionary_get(instd, "requiredby"); instd_auto = false; prop_dictionary_get_bool(instd, "automatic-install", &instd_auto); @@ -100,11 +99,6 @@ xbps_transaction_package_replace(struct xbps_handle *xhp) "in transaction\n"); prop_dictionary_set_bool(instd, "remove-and-update", true); - if (instd_reqby && - prop_array_count(instd_reqby)) { - prop_dictionary_set(reppkgd, - "requiredby", instd_reqby); - } prop_dictionary_set_bool(reppkgd, "automatic-install", instd_auto); prop_dictionary_set_bool(reppkgd, @@ -115,36 +109,18 @@ xbps_transaction_package_replace(struct xbps_handle *xhp) /* * If new package is providing a virtual package to the * package that we want to replace we should respect - * its requiredby and automatic-install objects, so copy - * them to the pkg's dictionary in transaction. + * the automatic-install object. */ if (xbps_match_virtual_pkg_in_dict(obj, pattern, true) || xbps_match_virtual_pkg_in_dict(instd, pkgname, false)) { - if (instd_reqby && - prop_array_count(instd_reqby)) { - prop_dictionary_set(obj, - "requiredby", instd_reqby); - } prop_dictionary_set_bool(obj, "automatic-install", instd_auto); } - /* - * Copy requiredby and automatic-install objects - * from replaced package into pkg's dictionary - * for "softreplace" packages. Also externalize - * PKGFILES from package being replaced to remove - * obsolete files. - */ sr = false; prop_dictionary_get_bool(obj, "softreplace", &sr); if (sr) { - if (instd_reqby && - prop_array_count(instd_reqby)) { - prop_dictionary_set(obj, - "requiredby", instd_reqby); - } prop_dictionary_set_bool(obj, "automatic-install", instd_auto); prop_dictionary_set_bool(instd,