diff --git a/include/xbps_api.h b/include/xbps_api.h index b8e68482..74b5d9ea 100644 --- a/include/xbps_api.h +++ b/include/xbps_api.h @@ -55,7 +55,7 @@ */ #define XBPS_PKGINDEX_VERSION "1.2" -#define XBPS_API_VERSION "20111019" +#define XBPS_API_VERSION "20111020" #define XBPS_VERSION "0.10.0" /** diff --git a/include/xbps_api_impl.h b/include/xbps_api_impl.h index 8ccc4f7f..bc5acd47 100644 --- a/include/xbps_api_impl.h +++ b/include/xbps_api_impl.h @@ -172,10 +172,9 @@ int HIDDEN xbps_file_chdir_exec(const char *, const char *, ...); /** * @private - * From lib/package_replaces.c + * From lib/transaction_package_replace.c */ -int HIDDEN xbps_repository_pkg_replaces(prop_dictionary_t, - prop_dictionary_t); +int HIDDEN xbps_transaction_package_replace(prop_dictionary_t); /** * @private diff --git a/lib/Makefile b/lib/Makefile index 46203783..729a167d 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -40,7 +40,7 @@ endif 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_purge.o package_replaces.o transaction_commit.o +OBJS += package_purge.o transaction_commit.o transaction_package_replace.o OBJS += transaction_dictionary.o transaction_sortdeps.o OBJS += download.o fexec.o humanize_number.o plist.o OBJS += plist_archive_entry.o plist_find.o plist_match.o plist_remove.o diff --git a/lib/package_replaces.c b/lib/package_replaces.c deleted file mode 100644 index 24f67a89..00000000 --- a/lib/package_replaces.c +++ /dev/null @@ -1,131 +0,0 @@ -/*- - * Copyright (c) 2011 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 "xbps_api_impl.h" - -int HIDDEN -xbps_repository_pkg_replaces(prop_dictionary_t transd, - prop_dictionary_t pkg_repod) -{ - prop_array_t replaces, unsorted, instd_reqby; - prop_dictionary_t instd, reppkgd; - prop_object_t obj; - prop_object_iterator_t iter; - const char *pattern, *pkgname, *curpkgname; - bool instd_auto = false; - - assert(prop_object_type(transd) == PROP_TYPE_DICTIONARY); - assert(prop_object_type(pkg_repod) == PROP_TYPE_DICTIONARY); - - replaces = prop_dictionary_get(pkg_repod, "replaces"); - if (replaces == NULL || prop_array_count(replaces) == 0) - return 0; - - iter = prop_array_iterator(replaces); - if (iter == NULL) - return ENOMEM; - - while ((obj = prop_object_iterator_next(iter)) != NULL) { - pattern = prop_string_cstring_nocopy(obj); - assert(pattern != NULL); - /* - * Find the installed package that matches the pattern - * to be replaced. - */ - instd = xbps_find_pkg_dict_installed(pattern, true); - if (instd == NULL) { - /* - * No package installed has been matched, try looking - * for a virtual package. - */ - instd = xbps_find_virtualpkg_dict_installed(pattern, true); - if (instd == NULL) - continue; - } - /* - * Check that we are not replacing the same package, due - * to virtual packages. - */ - prop_dictionary_get_cstring_nocopy(pkg_repod, "pkgname", &pkgname); - prop_dictionary_get_cstring_nocopy(instd, "pkgname", &curpkgname); - if (strcmp(pkgname, curpkgname) == 0) { - prop_object_release(instd); - continue; - } - /* - * Package contains replaces="pkgpattern", but the - * package that should be replaced is also in the - * transaction and it's going to be updated. - */ - unsorted = prop_dictionary_get(transd, "unsorted_deps"); - reppkgd = xbps_find_pkg_in_array_by_pattern(unsorted, pattern); - if (reppkgd) { - prop_dictionary_set_bool(reppkgd, - "remove-and-update", true); - prop_object_release(instd); - continue; - } - /* - * 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. - */ - if (xbps_match_virtual_pkg_in_dict(pkg_repod, pattern, true) || - xbps_match_virtual_pkg_in_dict(instd, pkgname, false)) { - instd_reqby = prop_dictionary_get(instd, "requiredby"); - if (instd_reqby && prop_array_count(instd_reqby)) { - prop_dictionary_set(pkg_repod, - "requiredby", instd_reqby); - } - if (prop_dictionary_get_bool(instd, - "automatic-install", &instd_auto)) { - prop_dictionary_set_bool(pkg_repod, - "automatic-install", instd_auto); - } - } - /* - * Add package dictionary into the transaction and mark it - * as to be "removed". - */ - prop_dictionary_set_cstring_nocopy(instd, - "transaction", "remove"); - if (!xbps_add_obj_to_array(unsorted, instd)) { - prop_object_release(instd); - prop_object_iterator_release(iter); - return EINVAL; - } - } - prop_object_iterator_release(iter); - - return 0; -} diff --git a/lib/repository_finddeps.c b/lib/repository_finddeps.c index 7bb445a1..42d1ed55 100644 --- a/lib/repository_finddeps.c +++ b/lib/repository_finddeps.c @@ -33,7 +33,6 @@ static int store_dependency(prop_dictionary_t transd, prop_dictionary_t repo_pkgd) { - prop_dictionary_t dict; prop_array_t array; const char *pkgname, *pkgver, *repoloc, *reason; int rv = 0; @@ -47,37 +46,19 @@ store_dependency(prop_dictionary_t transd, prop_dictionary_t repo_pkgd) prop_dictionary_get_cstring_nocopy(repo_pkgd, "pkgname", &pkgname); prop_dictionary_get_cstring_nocopy(repo_pkgd, "pkgver", &pkgver); prop_dictionary_get_cstring_nocopy(repo_pkgd, "repository", &repoloc); - /* - * Check if this package should replace other installed packages. - */ - if ((rv = xbps_repository_pkg_replaces(transd, repo_pkgd)) != 0) - return rv; - dict = prop_dictionary_copy(repo_pkgd); - if (dict == NULL) - return errno; - - array = prop_dictionary_get(transd, "unsorted_deps"); - if (array == NULL) { - prop_object_release(dict); - return errno; - } /* * Overwrite package state in dictionary with same state than the * package currently uses, otherwise not-installed. */ if ((rv = xbps_pkg_state_installed(pkgname, &state)) != 0) { - if (rv != ENOENT) { - prop_object_release(dict); + if (rv != ENOENT) return rv; - } /* pkg not installed */ state = XBPS_PKG_STATE_NOT_INSTALLED; } - if ((rv = xbps_set_pkg_state_dictionary(dict, state)) != 0) { - prop_object_release(dict); + if ((rv = xbps_set_pkg_state_dictionary(repo_pkgd, state)) != 0) return rv; - } /* * If pkg dependency is already installed, skip it if the transaction * reason is "install". @@ -88,24 +69,24 @@ store_dependency(prop_dictionary_t transd, prop_dictionary_t repo_pkgd) if (strcmp(reason, "install") == 0) { xbps_dbg_printf("%s: skipping, already installed.\n", pkgver); - prop_object_release(dict); return 0; } } /* * Add required objects into package dep's dictionary. */ - if (!prop_dictionary_set_bool(dict, "automatic-install", true)) { - prop_object_release(dict); + if (!prop_dictionary_set_bool(repo_pkgd, "automatic-install", true)) return errno; - } /* * Add the dictionary into the array. */ - if (!xbps_add_obj_to_array(array, dict)) { - prop_object_release(dict); + array = prop_dictionary_get(transd, "unsorted_deps"); + if (array == NULL) + return errno; + + if (!prop_array_add(array, repo_pkgd)) return EINVAL; - } + xbps_dbg_printf("Added package '%s' into " "the transaction (%s).\n", pkgver, repoloc); diff --git a/lib/repository_findpkg.c b/lib/repository_findpkg.c index 4fd9f02c..9297115d 100644 --- a/lib/repository_findpkg.c +++ b/lib/repository_findpkg.c @@ -54,7 +54,7 @@ static int repository_find_pkg(const char *pattern, const char *reason) { - prop_dictionary_t pkg_repod = NULL, origin_pkgrd = NULL; + prop_dictionary_t pkg_repod = NULL; prop_dictionary_t transd; prop_array_t mdeps, unsorted; const char *pkgname; @@ -108,13 +108,12 @@ repository_find_pkg(const char *pattern, const char *reason) goto out; } - origin_pkgrd = prop_dictionary_copy(pkg_repod); prop_dictionary_get_cstring_nocopy(pkg_repod, "pkgname", &pkgname); /* * Prepare required package dependencies and add them into the * "unsorted" array in transaction dictionary. */ - rv = xbps_repository_find_pkg_deps(transd, mdeps, origin_pkgrd); + rv = xbps_repository_find_pkg_deps(transd, mdeps, pkg_repod); if (rv != 0) goto out; @@ -128,7 +127,7 @@ repository_find_pkg(const char *pattern, const char *reason) /* Package not installed, don't error out */ state = XBPS_PKG_STATE_NOT_INSTALLED; } - if ((rv = xbps_set_pkg_state_dictionary(origin_pkgrd, state)) != 0) + if ((rv = xbps_set_pkg_state_dictionary(pkg_repod, state)) != 0) goto out; if (state == XBPS_PKG_STATE_UNPACKED) @@ -141,7 +140,7 @@ repository_find_pkg(const char *pattern, const char *reason) * Set transaction obj in pkg dictionary to "install", "configure" * or "update". */ - if (!prop_dictionary_set_cstring_nocopy(origin_pkgrd, + if (!prop_dictionary_set_cstring_nocopy(pkg_repod, "transaction", reason)) { rv = EINVAL; goto out; @@ -154,17 +153,11 @@ repository_find_pkg(const char *pattern, const char *reason) rv = EINVAL; goto out; } - /* - * Check if this package should replace other installed packages. - */ - if ((rv = xbps_repository_pkg_replaces(transd, origin_pkgrd)) != 0) - goto out; - /* * Add the pkg dictionary from repository's index dictionary into * the "unsorted" array in transaction dictionary. */ - if (!prop_array_add(unsorted, origin_pkgrd)) { + if (!prop_array_add(unsorted, pkg_repod)) { rv = errno; goto out; } @@ -172,8 +165,6 @@ repository_find_pkg(const char *pattern, const char *reason) out: if (pkg_repod) prop_object_release(pkg_repod); - if (origin_pkgrd) - prop_object_release(origin_pkgrd); return rv; } diff --git a/lib/transaction_commit.c b/lib/transaction_commit.c index c402ad73..5be17689 100644 --- a/lib/transaction_commit.c +++ b/lib/transaction_commit.c @@ -205,6 +205,7 @@ xbps_transaction_commit(prop_dictionary_t transd) "[*] Running transaction tasks", NULL, NULL, NULL); while ((obj = prop_object_iterator_next(iter)) != NULL) { + update = false; prop_dictionary_get_cstring_nocopy(obj, "transaction", &tract); prop_dictionary_get_cstring_nocopy(obj, "pkgname", &pkgname); prop_dictionary_get_cstring_nocopy(obj, "version", &version); @@ -215,7 +216,6 @@ xbps_transaction_commit(prop_dictionary_t transd) /* * Remove a package. */ - update = false; prop_dictionary_get_bool(obj, "remove-and-update", &update); RUN_TRANS_CB(XBPS_TRANS_STATE_REMOVE, diff --git a/lib/transaction_dictionary.c b/lib/transaction_dictionary.c index 18af3a8f..ba471729 100644 --- a/lib/transaction_dictionary.c +++ b/lib/transaction_dictionary.c @@ -235,6 +235,15 @@ xbps_transaction_prepare(void) errno = ENODEV; return NULL; } + /* + * Check for packages to be replaced. + */ + if ((rv = xbps_transaction_package_replace(transd)) != 0) { + errno = rv; + prop_object_release(transd); + prop_object_release(trans_mdeps); + return NULL; + } /* * Sort package dependencies if necessary. */ diff --git a/lib/transaction_package_replace.c b/lib/transaction_package_replace.c new file mode 100644 index 00000000..d74d1b04 --- /dev/null +++ b/lib/transaction_package_replace.c @@ -0,0 +1,154 @@ +/*- + * Copyright (c) 2011 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 "xbps_api_impl.h" + +int HIDDEN +xbps_transaction_package_replace(prop_dictionary_t transd) +{ + prop_array_t replaces, instd_reqby, transd_unsorted; + prop_dictionary_t instd, pkg_repod, reppkgd; + prop_object_t obj; + prop_object_iterator_t iter; + const char *pattern, *pkgname, *curpkgname; + bool instd_auto; + size_t idx; + + assert(prop_object_type(transd) == PROP_TYPE_DICTIONARY); + + transd_unsorted = prop_dictionary_get(transd, "unsorted_deps"); + + for (idx = 0; idx < prop_array_count(transd_unsorted); idx++) { + pkg_repod = prop_array_get(transd_unsorted, idx); + replaces = prop_dictionary_get(pkg_repod, "replaces"); + if (replaces == NULL || prop_array_count(replaces) == 0) + continue; + + iter = prop_array_iterator(replaces); + if (iter == NULL) + return ENOMEM; + + while ((obj = prop_object_iterator_next(iter)) != NULL) { + pattern = prop_string_cstring_nocopy(obj); + assert(pattern != NULL); + /* + * Find the installed package that matches the pattern + * to be replaced. + */ + instd = xbps_find_pkg_dict_installed(pattern, true); + if (instd == NULL) { + /* + * No package installed has been matched, + * try looking for a virtual package. + */ + instd = xbps_find_virtualpkg_dict_installed( + pattern, true); + if (instd == NULL) + continue; + } + xbps_dbg_printf("installed pkg to be replaced " + "matched with `%s'\n", pattern); + /* + * Check that we are not replacing the same package, + * due to virtual packages. + */ + prop_dictionary_get_cstring_nocopy(pkg_repod, + "pkgname", &pkgname); + prop_dictionary_get_cstring_nocopy(instd, + "pkgname", &curpkgname); + if (strcmp(pkgname, curpkgname) == 0) { + xbps_dbg_printf("replaced and new package " + "are equal (%s)\n", pkgname); + prop_object_release(instd); + continue; + } + instd_reqby = prop_dictionary_get(instd, "requiredby"); + instd_auto = false; + prop_dictionary_get_bool(instd, + "automatic-install", &instd_auto); + /* + * Package contains replaces="pkgpattern", but the + * package that should be replaced is also in the + * transaction and it's going to be updated. + */ + reppkgd = xbps_find_pkg_in_array_by_name( + transd_unsorted, curpkgname); + if (reppkgd) { + xbps_dbg_printf("found replaced pkg " + "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); + xbps_array_replace_dict_by_name(transd_unsorted, + reppkgd, curpkgname); + } + /* + * 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. + */ + if (xbps_match_virtual_pkg_in_dict(pkg_repod, + pattern, true) || + xbps_match_virtual_pkg_in_dict(instd, + pkgname, false)) { + if (instd_reqby && + prop_array_count(instd_reqby)) { + prop_dictionary_set(pkg_repod, + "requiredby", instd_reqby); + } + prop_dictionary_set_bool(pkg_repod, + "automatic-install", instd_auto); + } + /* + * Add package dictionary into the transaction and mark + * it as to be "removed". + */ + prop_dictionary_set_cstring_nocopy(instd, + "transaction", "remove"); + if (!xbps_add_obj_to_array(transd_unsorted, instd)) { + prop_object_release(instd); + prop_object_iterator_release(iter); + return EINVAL; + } + } + prop_object_iterator_release(iter); + } + + return 0; +}