diff --git a/NEWS b/NEWS index 1b254eb2..94ac35fc 100644 --- a/NEWS +++ b/NEWS @@ -1,5 +1,11 @@ xbps-0.38 (???): + * Added support to replace virtual packages when the package to be installed + matches a virtual pkgname, for example: + + - nvidia is installed and provides the `libGL` virtual pkgname. + - libGL matches the virtual pkgname and therefore replaces the `nvidia` pkg. + * xbps-query(8): added --fulldeptree long option to print a full dependency tree for a package; this supersedes -xx which was broken since 0.37. diff --git a/lib/repo_pkgdeps.c b/lib/repo_pkgdeps.c index 8a169772..15fe2007 100644 --- a/lib/repo_pkgdeps.c +++ b/lib/repo_pkgdeps.c @@ -36,7 +36,9 @@ store_dependency(struct xbps_handle *xhp, xbps_dictionary_t repo_pkgd, pkg_state_t repo_pkg_state) { + xbps_array_t replaces; const char *pkgver; + char *pkgname, *self_replaced; int rv; /* * Overwrite package state in dictionary with same state than the @@ -49,11 +51,29 @@ store_dependency(struct xbps_handle *xhp, */ if (!xbps_dictionary_set_bool(repo_pkgd, "automatic-install", true)) return EINVAL; + + xbps_dictionary_get_cstring_nocopy(repo_pkgd, "pkgver", &pkgver); + /* + * 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)) { + free(pkgname); + return EINVAL; + } /* * Add the dictionary into the unsorted queue. */ xbps_array_add(unsorted, repo_pkgd); - xbps_dictionary_get_cstring_nocopy(repo_pkgd, "pkgver", &pkgver); xbps_dbg_printf_append(xhp, " (added %s)\n", pkgver); return 0; diff --git a/lib/transaction_ops.c b/lib/transaction_ops.c index 3090f5bd..5e3baf4c 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 unsorted; + xbps_array_t unsorted, replaces; const char *repoloc, *repopkgver, *instpkgver, *reason; - char *pkgname; + char *self_replaced, *pkgname; int action = 0, rv = 0; pkg_state_t state = 0; bool autoinst = false; @@ -175,10 +175,10 @@ trans_find_pkg(struct xbps_handle *xhp, const char *pkg, bool reinstall) /* Package not installed, don't error out */ state = XBPS_PKG_STATE_NOT_INSTALLED; } - free(pkgname); - - if ((rv = xbps_set_pkg_state_dictionary(pkg_repod, state)) != 0) + if ((rv = xbps_set_pkg_state_dictionary(pkg_repod, state)) != 0) { + free(pkgname); return rv; + } if ((action == TRANS_INSTALL) && (state == XBPS_PKG_STATE_UNPACKED)) reason = "configure"; @@ -193,16 +193,32 @@ trans_find_pkg(struct xbps_handle *xhp, const char *pkg, bool reinstall) "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)) { + free(pkgname); + return EINVAL; + } /* * Add the pkg dictionary from repository's index dictionary into * the "unsorted" queue. */ - if (!xbps_array_add(unsorted, pkg_repod)) + if (!xbps_array_add(unsorted, pkg_repod)) { + free(pkgname); return EINVAL; - + } xbps_dbg_printf(xhp, "%s: added into the transaction (%s).\n", repopkgver, repoloc); + free(pkgname); return 0; } diff --git a/tests/xbps/libxbps/shell/replace_test.sh b/tests/xbps/libxbps/shell/replace_test.sh index 11903e45..6e36897f 100644 --- a/tests/xbps/libxbps/shell/replace_test.sh +++ b/tests/xbps/libxbps/shell/replace_test.sh @@ -36,6 +36,37 @@ replace_dups_body() { atf_check_equal $result 1 } +atf_test_case self_replace + +self_replace_head() { + atf_set "descr" "Tests for package replace: self replacing virtual packages" +} + +self_replace_body() { + mkdir some_repo root + mkdir -p pkg_A/usr/bin pkg_B/usr/bin + echo "A-1.0_1" > pkg_A/usr/bin/foo + echo "B-1.0_1" > pkg_B/usr/bin/foo + cd some_repo + xbps-create -A noarch -n A-1.0_1 -s "A pkg" ../pkg_A + atf_check_equal $? 0 + xbps-create -A noarch -n B-1.0_1 -s "B pkg" --replaces "A>=0" --provides="A-1.0_1" ../pkg_B + atf_check_equal $? 0 + xbps-rindex -a *.xbps + atf_check_equal $? 0 + cd .. + xbps-install -C empty.conf -r root --repository=$PWD/some_repo -y A + atf_check_equal $? 0 + xbps-install -C empty.conf -r root --repository=$PWD/some_repo -y B + atf_check_equal $? 0 + xbps-install -C empty.conf -r root --repository=$PWD/some_repo -y A + atf_check_equal $? 0 + out=$(xbps-query -C empty.conf -r root -l|awk '{print $2}') + exp="A-1.0_1" + atf_check_equal $out $exp +} + atf_init_test_cases() { atf_add_test_case replace_dups + atf_add_test_case self_replace }