diff --git a/NEWS b/NEWS index 7991c498..885de91c 100644 --- a/NEWS +++ b/NEWS @@ -1,5 +1,8 @@ xbps-0.48 (???): + * libxbps: implemented reverse conflicts. That means that just a single pkg + needs to set conflicts to be effective, rather than all involved pkgs. + * libxbps: with -M (--memory-sync opt of xbps-{install,query}) only process remote repositories, not local ones. diff --git a/include/xbps_api_impl.h b/include/xbps_api_impl.h index 077abeff..f7146f23 100644 --- a/include/xbps_api_impl.h +++ b/include/xbps_api_impl.h @@ -143,8 +143,7 @@ int HIDDEN xbps_unpack_binary_pkg(struct xbps_handle *, xbps_dictionary_t); int HIDDEN xbps_transaction_package_replace(struct xbps_handle *, xbps_array_t); int HIDDEN xbps_remove_pkg(struct xbps_handle *, const char *, bool); int HIDDEN xbps_register_pkg(struct xbps_handle *, xbps_dictionary_t); -void HIDDEN xbps_pkg_find_conflicts(struct xbps_handle *, xbps_array_t, - xbps_dictionary_t); +void HIDDEN xbps_transaction_conflicts(struct xbps_handle *, xbps_array_t); char HIDDEN *xbps_archive_get_file(struct archive *, struct archive_entry *); xbps_dictionary_t HIDDEN xbps_archive_get_dictionary(struct archive *, struct archive_entry *); diff --git a/lib/Makefile b/lib/Makefile index 571e621b..bc97817d 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -36,8 +36,9 @@ 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 transaction_store.o -OBJS += transaction_revdeps.o pubkey2fp.o package_fulldeptree.o -OBJS += download.o initend.o pkgdb.o package_conflicts.o +OBJS += transaction_revdeps.o transaction_conflicts.o +OBJS += pubkey2fp.o package_fulldeptree.o +OBJS += download.o initend.o pkgdb.o OBJS += plist.o plist_find.o plist_match.o archive.o OBJS += plist_remove.o plist_fetch.o util.o util_hash.o OBJS += repo.o repo_pkgdeps.o repo_sync.o diff --git a/lib/package_conflicts.c b/lib/transaction_conflicts.c similarity index 63% rename from lib/package_conflicts.c rename to lib/transaction_conflicts.c index c09a6666..192dbb07 100644 --- a/lib/package_conflicts.c +++ b/lib/transaction_conflicts.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2012-2014 Juan Romero Pardines. + * Copyright (c) 2012-2015 Juan Romero Pardines. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -31,10 +31,9 @@ #include "xbps_api_impl.h" -void HIDDEN -xbps_pkg_find_conflicts(struct xbps_handle *xhp, - xbps_array_t unsorted, - xbps_dictionary_t pkg_repod) +static void +pkg_conflicts_trans(struct xbps_handle *xhp, xbps_array_t array, + xbps_dictionary_t pkg_repod) { xbps_array_t pkg_cflicts, trans_cflicts; xbps_dictionary_t pkgd, tpkgd; @@ -76,7 +75,7 @@ xbps_pkg_find_conflicts(struct xbps_handle *xhp, * the transaction and does not match the pattern, * ignore it. */ - if ((tpkgd = xbps_find_pkg_in_array(unsorted, pkgname, NULL))) { + if ((tpkgd = xbps_find_pkg_in_array(array, pkgname, NULL))) { const char *tract, *p; xbps_dictionary_get_cstring_nocopy(tpkgd, @@ -104,8 +103,8 @@ xbps_pkg_find_conflicts(struct xbps_handle *xhp, /* * Check if current pkg conflicts with any pkg in transaction. */ - if ((pkgd = xbps_find_pkg_in_array(unsorted, cfpkg, NULL)) || - (pkgd = xbps_find_virtualpkg_in_array(xhp, unsorted, cfpkg, NULL))) { + if ((pkgd = xbps_find_pkg_in_array(array, cfpkg, NULL)) || + (pkgd = xbps_find_virtualpkg_in_array(xhp, array, cfpkg, NULL))) { xbps_dictionary_get_cstring_nocopy(pkgd, "pkgver", &pkgver); pkgname = xbps_pkg_name(pkgver); @@ -129,3 +128,70 @@ xbps_pkg_find_conflicts(struct xbps_handle *xhp, xbps_object_iterator_release(iter); free(repopkgname); } + +static int +pkgdb_conflicts_cb(struct xbps_handle *xhp, xbps_object_t obj, + const char *key _unused, void *arg, bool *done _unused) +{ + xbps_array_t pkg_cflicts, trans_cflicts, pkgs = arg; + xbps_dictionary_t pkgd; + xbps_object_t obj2; + xbps_object_iterator_t iter; + const char *cfpkg, *repopkgver, *pkgver; + char *pkgname, *repopkgname, *buf; + + pkg_cflicts = xbps_dictionary_get(obj, "conflicts"); + if (xbps_array_count(pkg_cflicts) == 0) + return 0; + + trans_cflicts = xbps_dictionary_get(xhp->transd, "conflicts"); + xbps_dictionary_get_cstring_nocopy(obj, "pkgver", &repopkgver); + repopkgname = xbps_pkg_name(repopkgver); + assert(repopkgname); + + iter = xbps_array_iterator(pkg_cflicts); + assert(iter); + + while ((obj2 = xbps_object_iterator_next(iter))) { + cfpkg = xbps_string_cstring_nocopy(obj2); + if ((pkgd = xbps_find_pkg_in_array(pkgs, cfpkg, NULL)) || + (pkgd = xbps_find_virtualpkg_in_array(xhp, pkgs, cfpkg, NULL))) { + xbps_dictionary_get_cstring_nocopy(pkgd, + "pkgver", &pkgver); + pkgname = xbps_pkg_name(pkgver); + assert(pkgname); + if (strcmp(pkgname, repopkgname) == 0) { + free(pkgname); + continue; + } + free(pkgname); + xbps_dbg_printf(xhp, "found conflicting pkgs in " + "transaction %s <-> %s\n", pkgver, repopkgver); + buf = xbps_xasprintf("CONFLICT: %s with " + "%s in transaction", repopkgver, pkgver); + if (!xbps_match_string_in_array(trans_cflicts, buf)) + xbps_array_add_cstring(trans_cflicts, buf); + + free(buf); + continue; + } + } + xbps_object_iterator_release(iter); + free(repopkgname); + return 0; +} + +void HIDDEN +xbps_transaction_conflicts(struct xbps_handle *xhp, xbps_array_t pkgs) +{ + xbps_dictionary_t pkgd; + unsigned int i; + + /* find conflicts in transaction */ + for (i = 0; i < xbps_array_count(pkgs); i++) { + pkgd = xbps_array_get(pkgs, i); + pkg_conflicts_trans(xhp, pkgs, pkgd); + } + /* find conflicts in pkgdb */ + (void)xbps_pkgdb_foreach_cb_multi(xhp, pkgdb_conflicts_cb, pkgs); +} diff --git a/lib/transaction_dictionary.c b/lib/transaction_dictionary.c index 222d49eb..d92e935d 100644 --- a/lib/transaction_dictionary.c +++ b/lib/transaction_dictionary.c @@ -319,11 +319,10 @@ xbps_transaction_prepare(struct xbps_handle *xhp) return ENODEV; } } - for (i = 0; i < xbps_array_count(pkgs); i++) - xbps_pkg_find_conflicts(xhp, pkgs, xbps_array_get(pkgs, i)); /* * If there are package conflicts bail out. */ + xbps_transaction_conflicts(xhp, pkgs); array = xbps_dictionary_get(xhp->transd, "conflicts"); if (xbps_array_count(array)) return EAGAIN; diff --git a/tests/xbps/libxbps/shell/Kyuafile b/tests/xbps/libxbps/shell/Kyuafile index d9ea33c0..53a4bf14 100644 --- a/tests/xbps/libxbps/shell/Kyuafile +++ b/tests/xbps/libxbps/shell/Kyuafile @@ -21,3 +21,4 @@ atf_test_program{name="update_shlibs"} atf_test_program{name="update_hold"} atf_test_program{name="update_repolock"} atf_test_program{name="cyclic_deps"} +atf_test_program{name="conflicts"} diff --git a/tests/xbps/libxbps/shell/Makefile b/tests/xbps/libxbps/shell/Makefile index d88daf52..4e14e2b5 100644 --- a/tests/xbps/libxbps/shell/Makefile +++ b/tests/xbps/libxbps/shell/Makefile @@ -6,7 +6,7 @@ TESTSHELL = conf_files_test issue6_test issue18_test issue20_test remove_test TESTSHELL+= replace_test installmode_test obsoletefiles_test TESTSHELL+= issue31_test scripts_test incorrect_deps_test TESTSHELL+= vpkg_test install_test preserve_files_test configure_test -TESTSHELL+= update_shlibs update_hold update_repolock cyclic_deps +TESTSHELL+= update_shlibs update_hold update_repolock cyclic_deps conflicts EXTRA_FILES = Kyuafile include $(TOPDIR)/mk/test.mk diff --git a/tests/xbps/libxbps/shell/conflicts.sh b/tests/xbps/libxbps/shell/conflicts.sh new file mode 100644 index 00000000..cf62f828 --- /dev/null +++ b/tests/xbps/libxbps/shell/conflicts.sh @@ -0,0 +1,88 @@ +#!/usr/bin/env atf-sh + +atf_test_case conflicts_trans + +conflicts_trans_head() { + atf_set "descr" "Tests for pkg conflicts: conflicting pkgs in transaction" +} + +conflicts_trans_body() { + mkdir some_repo + mkdir -p pkg_{A,B}/usr/bin + cd some_repo + xbps-create -A noarch -n A-1.0_1 -s "A pkg" --conflicts "B>=0" ../pkg_A + atf_check_equal $? 0 + xbps-create -A noarch -n B-1.0_1 -s "B pkg" ../pkg_B + atf_check_equal $? 0 + + xbps-rindex -d -a $PWD/*.xbps + atf_check_equal $? 0 + cd .. + + xbps-install -r root --repository=$PWD/some_repo -dy A B + # EAGAIN, conflicts. + atf_check_equal $? 11 + # 0 pkgs installed. + xbps-query -r root -l|wc -l + atf_check_equal $(xbps-query -r root -l|wc -l) 0 +} + +atf_test_case conflicts_installed + +conflicts_installed_head() { + atf_set "descr" "Tests for pkg conflicts: installed pkg conflicts with pkg in transaction" +} + +conflicts_installed_body() { + mkdir some_repo + mkdir -p pkg_{A,B}/usr/bin + cd some_repo + xbps-create -A noarch -n A-1.0_1 -s "A pkg" --conflicts "B>=0" ../pkg_A + atf_check_equal $? 0 + xbps-create -A noarch -n B-1.0_1 -s "B pkg" ../pkg_B + atf_check_equal $? 0 + + xbps-rindex -d -a $PWD/*.xbps + atf_check_equal $? 0 + cd .. + + xbps-install -r root --repository=$PWD/some_repo -dy A + atf_check_equal $? 0 + xbps-install -r root --repository=$PWD/some_repo -dy B + atf_check_equal $? 11 + xbps-query -r root -l|wc -l + atf_check_equal $(xbps-query -r root -l|wc -l) 1 +} + +atf_test_case conflicts_trans_installed + +conflicts_trans_installed_head() { + atf_set "descr" "Tests for pkg conflicts: pkg in transaction conflicts with installed pkg" +} + +conflicts_trans_installed_body() { + mkdir some_repo + mkdir -p pkg_{A,B}/usr/bin + cd some_repo + xbps-create -A noarch -n A-1.0_1 -s "A pkg" --conflicts "B>=0" ../pkg_A + atf_check_equal $? 0 + xbps-create -A noarch -n B-1.0_1 -s "B pkg" ../pkg_B + atf_check_equal $? 0 + + xbps-rindex -d -a $PWD/*.xbps + atf_check_equal $? 0 + cd .. + + xbps-install -r root --repository=$PWD/some_repo -dy B + atf_check_equal $? 0 + xbps-install -r root --repository=$PWD/some_repo -dy A + atf_check_equal $? 11 + xbps-query -r root -l|wc -l + atf_check_equal $(xbps-query -r root -l|wc -l) 1 +} + +atf_init_test_cases() { + atf_add_test_case conflicts_trans + atf_add_test_case conflicts_trans_installed + atf_add_test_case conflicts_installed +}