Skip to content

Commit 86104ff

Browse files
classabbyampDuncaen
authored andcommitted
lib: handle replaces if replaced pkg is installed in the same transaction
replaces isn't honoured if the package to be replaced is currently being installed. This fixes a corner case where a transitional package could be installed along with its replacement, when it should be "ignored" and only the new package installed. This requires transaction commits to not fail if a replaced package isn't installed when it should be "removed". Also, indicate to the user that a package is being replaced, with details about what replaced what shown in verbose output, not just debug output. fixes: #667
1 parent f558e9e commit 86104ff

4 files changed

Lines changed: 50 additions & 3 deletions

File tree

bin/xbps-install/util.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,15 +157,20 @@ print_trans_colmode(struct transaction *trans, unsigned int cols)
157157

158158
while ((obj = xbps_object_iterator_next(trans->iter)) != NULL) {
159159
bool dload = false;
160+
bool replaced = false;
160161

161162
pkgver = pkgname = ipkgver = ver = iver = NULL;
162163
xbps_dictionary_get_cstring_nocopy(obj, "pkgver", &pkgver);
163164
xbps_dictionary_get_cstring_nocopy(obj, "pkgname", &pkgname);
164165
xbps_dictionary_get_uint64(obj, "filename-size", &dlsize);
165166
xbps_dictionary_get_bool(obj, "download", &dload);
167+
xbps_dictionary_get_bool(obj, "replaced", &replaced);
166168

167169
ttype = xbps_transaction_pkg_type(obj);
168170
tract = ttype2str(obj);
171+
if (replaced) {
172+
tract = "replaced";
173+
}
169174
if (trans->xhp->flags & XBPS_FLAG_DOWNLOAD_ONLY) {
170175
tract = "download";
171176
}

lib/transaction_check_replaces.c

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,10 +80,12 @@ xbps_transaction_check_replaces(struct xbps_handle *xhp, xbps_array_t pkgs)
8080

8181
/*
8282
* Find the installed package that matches the pattern
83-
* to be replaced.
83+
* to be replaced. Also check if the package would be
84+
* installed in the transaction.
8485
*/
8586
if (((instd = xbps_pkgdb_get_pkg(xhp, pattern)) == NULL) &&
86-
((instd = xbps_pkgdb_get_virtualpkg(xhp, pattern)) == NULL))
87+
((instd = xbps_pkgdb_get_virtualpkg(xhp, pattern)) == NULL) &&
88+
((instd = xbps_find_pkg_in_array(pkgs, pattern, XBPS_TRANS_INSTALL)) == NULL))
8789
continue;
8890

8991
if (!xbps_dictionary_get_cstring_nocopy(instd, "pkgver", &curpkgver)) {
@@ -142,6 +144,7 @@ xbps_transaction_check_replaces(struct xbps_handle *xhp, xbps_array_t pkgs)
142144
xbps_object_iterator_release(iter);
143145
return false;
144146
}
147+
xbps_verbose_printf("Package `%s' will be replaced by `%s'\n", curpkgver, pkgver);
145148
xbps_dbg_printf(
146149
"Package `%s' in transaction will be "
147150
"replaced by `%s', matched with `%s'\n",
@@ -174,6 +177,7 @@ xbps_transaction_check_replaces(struct xbps_handle *xhp, xbps_array_t pkgs)
174177
xbps_object_iterator_release(iter);
175178
return false;
176179
}
180+
xbps_verbose_printf("Package `%s' will be replaced by `%s'\n", curpkgver, pkgver);
177181
xbps_dbg_printf(
178182
"Package `%s' will be replaced by `%s', "
179183
"matched with `%s'\n", curpkgver, pkgver, pattern);

lib/transaction_commit.c

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ xbps_transaction_commit(struct xbps_handle *xhp)
109109
xbps_trans_type_t ttype;
110110
const char *pkgver = NULL, *pkgname = NULL;
111111
int rv = 0;
112-
bool update;
112+
bool update, replaced;
113113

114114
setlocale(LC_ALL, "");
115115

@@ -232,6 +232,11 @@ xbps_transaction_commit(struct xbps_handle *xhp)
232232
}
233233

234234
if ((pkgdb_pkgd = xbps_pkgdb_get_pkg(xhp, pkgname)) == NULL) {
235+
replaced = false;
236+
xbps_dictionary_get_bool(obj, "replaced", &replaced);
237+
if (replaced) {
238+
continue;
239+
}
235240
rv = ENOENT;
236241
xbps_dbg_printf("[trans] cannot find %s in pkgdb: %s\n",
237242
pkgname, strerror(rv));
@@ -302,6 +307,7 @@ xbps_transaction_commit(struct xbps_handle *xhp)
302307

303308
while ((obj = xbps_object_iterator_next(iter)) != NULL) {
304309
xbps_dictionary_get_cstring_nocopy(obj, "pkgver", &pkgver);
310+
xbps_dictionary_get_cstring_nocopy(obj, "pkgname", &pkgname);
305311

306312
ttype = xbps_transaction_pkg_type(obj);
307313
if (ttype == XBPS_TRANS_REMOVE) {
@@ -310,6 +316,11 @@ xbps_transaction_commit(struct xbps_handle *xhp)
310316
*/
311317
update = false;
312318
xbps_dictionary_get_bool(obj, "remove-and-update", &update);
319+
replaced = false;
320+
xbps_dictionary_get_bool(obj, "replaced", &replaced);
321+
if (((pkgdb_pkgd = xbps_pkgdb_get_pkg(xhp, pkgname)) == NULL) && replaced) {
322+
continue;
323+
}
313324
rv = xbps_remove_pkg(xhp, pkgver, update);
314325
if (rv != 0) {
315326
xbps_dbg_printf("[trans] failed to "

tests/xbps/libxbps/shell/replace_test.sh

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -419,6 +419,32 @@ replace_transitional_pkg_automatically_installed3_body() {
419419
atf_check_equal $(xbps-query -C xbps.d -r root -p automatic-install A) ""
420420
}
421421

422+
atf_test_case replace_transitional_pkg_during_install
423+
424+
replace_transitional_pkg_during_install_head() {
425+
atf_set "descr" "Tests for package replace: install a transitional package and replace it during the transaction"
426+
}
427+
428+
replace_transitional_pkg_during_install_body() {
429+
mkdir some_repo root
430+
mkdir -p pkg_A/usr/bin empty
431+
echo "A-1.0_1" > pkg_A/usr/bin/foo
432+
cd some_repo
433+
xbps-create -A noarch -n A-1.0_1 -s "A pkg" --replaces "B>=0" ../pkg_A
434+
atf_check_equal $? 0
435+
xbps-create -A noarch -n B-1.0_1 -s "A pkg - transitional dummy package" --dependencies="A>=0" ../empty
436+
atf_check_equal $? 0
437+
xbps-rindex -d -a $PWD/*.xbps
438+
atf_check_equal $? 0
439+
cd ..
440+
xbps-install -C xbps.d -r root --repository=$PWD/some_repo -yd B
441+
atf_check_equal $? 0
442+
result=$(xbps-query -r root -l | wc -l)
443+
atf_check_equal $result 1
444+
atf_check_equal $(xbps-query -C xbps.d -r root -p state A) installed
445+
atf_check_equal $(xbps-query -C xbps.d -r root -p state B) ""
446+
}
447+
422448
atf_test_case replace_automatically_installed_dep
423449

424450
replace_automatically_installed_dep_head() {
@@ -600,6 +626,7 @@ atf_init_test_cases() {
600626
atf_add_test_case replace_transitional_pkg_automatically_installed
601627
atf_add_test_case replace_transitional_pkg_automatically_installed2
602628
atf_add_test_case replace_transitional_pkg_automatically_installed3
629+
atf_add_test_case replace_transitional_pkg_during_install
603630
atf_add_test_case replace_automatically_installed_dep
604631
atf_add_test_case replace_automatically_installed_dep2
605632
atf_add_test_case replace_automatically_installed_dep3

0 commit comments

Comments
 (0)