diff --git a/include/xbps_api_impl.h b/include/xbps_api_impl.h index 46349e8e..ade3d49c 100644 --- a/include/xbps_api_impl.h +++ b/include/xbps_api_impl.h @@ -198,6 +198,8 @@ bool HIDDEN xbps_transaction_shlibs(struct xbps_handle *, xbps_array_t, xbps_arr */ int HIDDEN xbps_transaction_init(struct xbps_handle *); +int HIDDEN xbps_transaction_store(struct xbps_handle *, xbps_array_t, xbps_dictionary_t, pkg_state_t); + /** * @private * From lib/repo_sync.c diff --git a/lib/Makefile b/lib/Makefile index b2f2fb63..9ec1f617 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -38,7 +38,7 @@ OBJS += package_remove.o package_find_obsoletes.o package_state.o OBJS += package_unpack.o package_register.o package_script.o verifysig.o OBJS += package_msg.o pkgdb_conversion.o transaction_shlibs.o OBJS += transaction_commit.o transaction_package_replace.o -OBJS += transaction_dictionary.o transaction_ops.o +OBJS += transaction_dictionary.o transaction_ops.o transaction_store.o OBJS += transaction_revdeps.o pubkey2fp.o OBJS += download.o initend.o pkgdb.o package_conflicts.o OBJS += plist.o plist_find.o plist_match.o archive.o diff --git a/lib/repo_pkgdeps.c b/lib/repo_pkgdeps.c index 434267a4..19320697 100644 --- a/lib/repo_pkgdeps.c +++ b/lib/repo_pkgdeps.c @@ -30,58 +30,6 @@ #include "xbps_api_impl.h" -static int -store_dependency(struct xbps_handle *xhp, - xbps_array_t unsorted, - xbps_dictionary_t repo_pkgd, - pkg_state_t repo_pkg_state) -{ - xbps_array_t replaces; - const char *pkgver; - char *pkgname, *self_replaced; - int rv; - - xbps_dictionary_get_cstring_nocopy(repo_pkgd, "pkgver", &pkgver); - if (xbps_find_pkg_in_array(unsorted, pkgver, NULL)) - return 0; - /* - * Overwrite package state in dictionary with same state than the - * package currently uses, otherwise not-installed. - */ - if ((rv = xbps_set_pkg_state_dictionary(repo_pkgd, repo_pkg_state)) != 0) - return rv; - /* - * Add required objects into package dep's dictionary. - */ - if (!xbps_dictionary_get(repo_pkgd, "automatic-install") && - !xbps_dictionary_set_bool(repo_pkgd, "automatic-install", true)) - return EINVAL; - - /* - * Set a replaces to itself, so that virtual packages are always replaced. - */ - if ((replaces = xbps_dictionary_get(repo_pkgd, "replaces")) == NULL) - replaces = xbps_array_create(); - - pkgname = xbps_pkg_name(pkgver); - assert(pkgname); - self_replaced = xbps_xasprintf("%s>=0", pkgname); - free(pkgname); - xbps_array_add_cstring(replaces, self_replaced); - free(self_replaced); - - if (!xbps_dictionary_set(repo_pkgd, "replaces", replaces)) - return EINVAL; - - /* - * Add the dictionary into the unsorted queue. - */ - xbps_array_add(unsorted, repo_pkgd); - xbps_dbg_printf_append(xhp, " (added %s)\n", pkgver); - - return 0; -} - static int add_missing_reqdep(struct xbps_handle *xhp, const char *reqpkg) { @@ -382,9 +330,9 @@ find_repo_deps(struct xbps_handle *xhp, * Package is on repo, add it into the transaction dictionary. */ xbps_dictionary_set_cstring_nocopy(curpkgd, "transaction", reason); - rv = store_dependency(xhp, unsorted, curpkgd, state); + rv = xbps_transaction_store(xhp, unsorted, curpkgd, state); if (rv != 0) { - xbps_dbg_printf(xhp, "store_dependency failed for `%s': %s\n", reqpkg, strerror(rv)); + xbps_dbg_printf(xhp, "xbps_transaction_store failed for `%s': %s\n", reqpkg, strerror(rv)); break; } continue; @@ -411,9 +359,9 @@ find_repo_deps(struct xbps_handle *xhp, * Package is on repo, add it into the transaction dictionary. */ xbps_dictionary_set_cstring_nocopy(curpkgd, "transaction", reason); - rv = store_dependency(xhp, unsorted, curpkgd, state); + rv = xbps_transaction_store(xhp, unsorted, curpkgd, state); if (rv != 0) { - xbps_dbg_printf(xhp, "store_dependency failed for `%s': %s\n", reqpkg, strerror(rv)); + xbps_dbg_printf(xhp, "xbps_transaction_store failed for `%s': %s\n", reqpkg, strerror(rv)); break; } } diff --git a/lib/transaction_ops.c b/lib/transaction_ops.c index a494a713..f6ca0ac6 100644 --- a/lib/transaction_ops.c +++ b/lib/transaction_ops.c @@ -62,9 +62,9 @@ static int trans_find_pkg(struct xbps_handle *xhp, const char *pkg, bool reinstall) { xbps_dictionary_t pkg_pkgdb = NULL, pkg_repod = NULL; - xbps_array_t pkgs, replaces; + xbps_array_t pkgs; const char *repoloc, *repopkgver, *instpkgver, *reason; - char *self_replaced, *pkgname; + char *pkgname; int action = 0, rv = 0; pkg_state_t state = 0; bool autoinst = false; @@ -193,34 +193,14 @@ trans_find_pkg(struct xbps_handle *xhp, const char *pkg, bool reinstall) * or "update". */ if (!xbps_dictionary_set_cstring_nocopy(pkg_repod, - "transaction", reason)) - return EINVAL; - - /* - * Set a replaces to itself, so that virtual packages are always replaced. - */ - if ((replaces = xbps_dictionary_get(pkg_repod, "replaces")) == NULL) - replaces = xbps_array_create(); - - self_replaced = xbps_xasprintf("%s>=0", pkgname); - xbps_array_add_cstring(replaces, self_replaced); - free(self_replaced); - - if (!xbps_dictionary_set(pkg_repod, "replaces", replaces)) { + "transaction", reason)) { free(pkgname); return EINVAL; } - /* - * Add the pkg dictionary from repository's index dictionary into - * the packages array. - */ - if (!xbps_array_add(pkgs, pkg_repod)) { + if ((rv = xbps_transaction_store(xhp, pkgs, pkg_repod, state)) != 0) { free(pkgname); - return EINVAL; + return rv; } - xbps_dbg_printf(xhp, "%s: added into the transaction (%s).\n", - repopkgver, repoloc); - free(pkgname); return 0; } diff --git a/lib/transaction_store.c b/lib/transaction_store.c new file mode 100644 index 00000000..237523bd --- /dev/null +++ b/lib/transaction_store.c @@ -0,0 +1,83 @@ +/*- + * Copyright (c) 2014 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 "xbps_api_impl.h" + +int HIDDEN +xbps_transaction_store(struct xbps_handle *xhp, xbps_array_t pkgs, + xbps_dictionary_t pkgd, pkg_state_t pstate) +{ + xbps_array_t replaces; + const char *pkgver; + char *pkgname, *self_replaced; + int rv; + + xbps_dictionary_get_cstring_nocopy(pkgd, "pkgver", &pkgver); + if (xbps_find_pkg_in_array(pkgs, pkgver, NULL)) + return 0; + /* + * Overwrite package state in dictionary with same state than the + * package currently uses, otherwise not-installed. + */ + if ((rv = xbps_set_pkg_state_dictionary(pkgd, pstate)) != 0) + return rv; + /* + * Add required objects into package dep's dictionary. + */ + if (!xbps_dictionary_get(pkgd, "automatic-install") && + !xbps_dictionary_set_bool(pkgd, "automatic-install", true)) + return EINVAL; + + /* + * Set a replaces to itself, so that virtual packages are always replaced. + */ + if ((replaces = xbps_dictionary_get(pkgd, "replaces")) == NULL) + replaces = xbps_array_create(); + + pkgname = xbps_pkg_name(pkgver); + assert(pkgname); + self_replaced = xbps_xasprintf("%s>=0", pkgname); + free(pkgname); + xbps_array_add_cstring(replaces, self_replaced); + free(self_replaced); + + if (!xbps_dictionary_set(pkgd, "replaces", replaces)) + return EINVAL; + + /* + * Add the dictionary into the unsorted queue. + */ + if (!xbps_array_add(pkgs, pkgd)) + return EINVAL; + + xbps_dbg_printf_append(xhp, " (added %s)\n", pkgver); + + return 0; +} diff --git a/tests/xbps/libxbps/shell/install_test.sh b/tests/xbps/libxbps/shell/install_test.sh index f76efeaa..72b96708 100644 --- a/tests/xbps/libxbps/shell/install_test.sh +++ b/tests/xbps/libxbps/shell/install_test.sh @@ -183,11 +183,33 @@ install_if_not_installed_on_update_body() { atf_check_equal $pkgver A-1.0_1 } +atf_test_case install_dups + +install_dups_head() { + atf_set "descr" "Tests for pkg installations: install multiple times a pkg" +} + +install_dups_body() { + mkdir some_repo + mkdir -p pkg_A/usr/bin + cd some_repo + xbps-create -A noarch -n A-1.0_1 -s "A pkg" ../pkg_A + atf_check_equal $? 0 + + xbps-rindex -a *.xbps + atf_check_equal $? 0 + cd .. + + out=$(xbps-install -C empty.conf -r root --repository=$PWD/some_repo -ynd A A A A|wc -l) + atf_check_equal $out 1 +} + atf_init_test_cases() { atf_add_test_case install_empty atf_add_test_case install_with_deps atf_add_test_case install_with_vpkg_deps atf_add_test_case install_if_not_installed_on_update + atf_add_test_case install_dups atf_add_test_case update_if_installed atf_add_test_case update_to_empty_pkg }