diff --git a/NEWS b/NEWS index fe218310..ce01d30a 100644 --- a/NEWS +++ b/NEWS @@ -1,5 +1,20 @@ xbps-0.8.0 (???): + * Fixed finally when a package should replace an installed package, but + at the same time the package to be replaced also needs to be updated + in the transaction. A real example: + + - sg3_utils-1.28 is currently installed. + - Installed package udisks-1.0.2_1 depends on sg3_utils-1.28. + - sg3_utils-1.28 has been splitted into libsgutils for 1.31, + and libsgutils-1.31 has "replaces=sg3_utils<1.31". + - udisks-1.0.2_2 depends on libsgutils-1.31. + + So now the old sg3_utils-1.28 package will be marked in its transaction + object as "remove" and the new sg3_utils-1.31 package as "update". + Therefore both packages (sg3_utils old/new) will be in the transaction + but one will be removed and the other one updated. + * Fixed a bug that made all registered repositories to fail when the first one couldn't be internalized in xbps_repository_pool_init(). diff --git a/bin/xbps-bin/install.c b/bin/xbps-bin/install.c index 8b11abbc..2857d25e 100644 --- a/bin/xbps-bin/install.c +++ b/bin/xbps-bin/install.c @@ -444,16 +444,50 @@ exec_transaction(struct transaction *trans) if ((rv = download_package_list(trans->iter, false)) != 0) return rv; /* - * Iterate over the transaction dictionary. + * Remove packages to be replaced. + */ + if (trans->rm_pkgcnt > 0) { + printf("\n[2/3] Removing packages to be replaced\n"); + while ((obj = prop_object_iterator_next(trans->iter)) != NULL) { + prop_dictionary_get_cstring_nocopy(obj, "pkgname", + &pkgname); + prop_dictionary_get_cstring_nocopy(obj, "version", + &version); + prop_dictionary_get_cstring_nocopy(obj, "pkgver", + &pkgver); + prop_dictionary_get_cstring_nocopy(obj, "transaction", + &tract); + update = false; + prop_dictionary_get_bool(obj, "remove-and-update", + &update); + + if (strcmp(tract, "remove") == 0) { + /* Remove a package */ + printf("Removing `%s' package ...\n", pkgver); + rv = xbps_remove_pkg(pkgname, version, update); + if (rv != 0) { + xbps_error_printf("xbps-bin: failed to " + "remove `%s': %s\n", pkgver, + strerror(rv)); + return rv; + } + } + } + prop_object_iterator_reset(trans->iter); + } + /* + * Install or update packages in transaction. */ printf("\n[2/3] Unpacking\n"); while ((obj = prop_object_iterator_next(trans->iter)) != NULL) { + prop_dictionary_get_cstring_nocopy(obj, "transaction", &tract); + if (strcmp(tract, "remove") == 0) + continue; autoinst = preserve = false; prop_dictionary_get_cstring_nocopy(obj, "pkgname", &pkgname); prop_dictionary_get_cstring_nocopy(obj, "version", &version); prop_dictionary_get_cstring_nocopy(obj, "pkgver", &pkgver); prop_dictionary_get_cstring_nocopy(obj, "filename", &filen); - prop_dictionary_get_cstring_nocopy(obj, "transaction", &tract); prop_dictionary_get_bool(obj, "automatic-install", &autoinst); prop_dictionary_get_bool(obj, "preserve", &preserve); /* @@ -465,18 +499,7 @@ exec_transaction(struct transaction *trans) if (state == XBPS_PKG_STATE_UNPACKED) continue; - if (strcmp(tract, "remove") == 0) { - /* Remove a package */ - printf("Removing `%s' package ...\n", pkgver); - rv = xbps_remove_pkg(pkgname, version, false); - if (rv != 0) { - xbps_error_printf("xbps-bin: failed to remove " - "`%s': %s\n", pkgver, strerror(rv)); - return rv; - } - continue; - - } else if (strcmp(tract, "update") == 0) { + if (strcmp(tract, "update") == 0) { /* Update a package */ instpkgd = xbps_find_pkg_dict_installed(pkgname, false); if (instpkgd == NULL) { diff --git a/include/xbps_api.h b/include/xbps_api.h index 20b9e3cb..8d234550 100644 --- a/include/xbps_api.h +++ b/include/xbps_api.h @@ -53,7 +53,7 @@ * @def XBPS_RELVER * Current library release date. */ -#define XBPS_RELVER "20110205" +#define XBPS_RELVER "20110218" /** * @def XBPS_META_PATH diff --git a/lib/package_replaces.c b/lib/package_replaces.c index 330ddd06..b9859a0f 100644 --- a/lib/package_replaces.c +++ b/lib/package_replaces.c @@ -38,7 +38,7 @@ xbps_repository_pkg_replaces(prop_dictionary_t transd, prop_dictionary_t pkg_repod) { prop_array_t replaces, unsorted; - prop_dictionary_t instd; + prop_dictionary_t instd, reppkgd; prop_object_t obj; prop_object_iterator_t iter; const char *pattern; @@ -51,8 +51,6 @@ xbps_repository_pkg_replaces(prop_dictionary_t transd, if (iter == NULL) return ENOMEM; - unsorted = prop_dictionary_get(transd, "unsorted_deps"); - while ((obj = prop_object_iterator_next(iter)) != NULL) { pattern = prop_string_cstring_nocopy(obj); assert(pattern != NULL); @@ -64,18 +62,15 @@ xbps_repository_pkg_replaces(prop_dictionary_t transd, if (instd == NULL) continue; /* - * If the package to be replaced is in the transaction due to - * an update, do not remove it; just overwrite its files. + * Package contains replaces="pkgpattern", but the + * package that should be replaced is also in the + * transaction and it's going to be updated. */ - transd = xbps_find_pkg_in_dict_by_pattern(transd, - "unsorted_deps", pattern); - if (transd) { - /* - * Set the bool property 'replace-files-in-pkg-update', - * will be used in xbps_unpack_binary_pkg(). - */ - prop_dictionary_set_bool(pkg_repod, - "replace-files-in-pkg-update", true); + 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; } diff --git a/lib/package_unpack.c b/lib/package_unpack.c index 57d35ffc..e90120cf 100644 --- a/lib/package_unpack.c +++ b/lib/package_unpack.c @@ -170,7 +170,7 @@ unpack_archive(prop_dictionary_t pkg_repod, const char *rootdir, *entry_pname, *transact; char *buf; int rv, flags, xflags; - bool preserve, update, replace_files_in_pkg_update; + bool preserve, update; assert(ar != NULL); assert(pkg_repod != NULL); @@ -378,33 +378,6 @@ unpack_archive(prop_dictionary_t pkg_repod, continue; } } - /* - * Account for the following scenario (real example): - * - * - gtk+-2.20 is currently installed. - * - gtk+-2.20 contains libgdk_pixbuf.so. - * - gtk+-2.20 will be updated to 2.22 in the transaction. - * - gtk+-2.22 depends on gdk-pixbuf>=2.22. - * - gdk-pixbuf-2.22 contains libgdk_pixbuf.so. - * - gdk-pixbuf-2.22 will be installed in the transaction. - * - * We do the following to fix this: - * - * - gdk-pixbuf-2.22 installs its files overwritting - * current ones if they exist. - * - gtk+ is updated to 2.22, it checks for obsolete files - * and detects that the files that were owned in 2.20 - * don't match the SHA256 hash and skips them. - */ - replace_files_in_pkg_update = false; - prop_dictionary_get_bool(pkg_repod, - "replace-files-in-pkg-update", - &replace_files_in_pkg_update); - if (replace_files_in_pkg_update) { - flags &= ~ARCHIVE_EXTRACT_NO_OVERWRITE; - flags &= ~ARCHIVE_EXTRACT_NO_OVERWRITE_NEWER; - } - /* * Extract entry from archive. */ diff --git a/lib/transaction_sortdeps.c b/lib/transaction_sortdeps.c index d78597c4..4cad437a 100644 --- a/lib/transaction_sortdeps.c +++ b/lib/transaction_sortdeps.c @@ -53,19 +53,24 @@ struct pkgdep { TAILQ_ENTRY(pkgdep) pkgdep_entries; prop_dictionary_t d; char *name; + const char *trans; }; static TAILQ_HEAD(pkgdep_head, pkgdep) pkgdep_list = TAILQ_HEAD_INITIALIZER(pkgdep_list); static struct pkgdep * -pkgdep_find(const char *name) +pkgdep_find(const char *name, const char *trans) { struct pkgdep *pd = NULL, *pd_new = NULL; TAILQ_FOREACH_SAFE(pd, &pkgdep_list, pkgdep_entries, pd_new) { - if (strcmp(pd->name, name) == 0) - return pd; + if (strcmp(pd->name, name) == 0) { + if (trans == NULL) + return pd; + if (strcmp(pd->trans, trans) == 0) + return pd; + } if (pd->d == NULL) continue; if (xbps_find_virtual_pkg_in_dict(pd->d, name, false)) @@ -77,14 +82,18 @@ pkgdep_find(const char *name) } static ssize_t -pkgdep_find_idx(const char *name) +pkgdep_find_idx(const char *name, const char *trans) { struct pkgdep *pd, *pd_new; ssize_t idx = 0; TAILQ_FOREACH_SAFE(pd, &pkgdep_list, pkgdep_entries, pd_new) { - if (strcmp(pd->name, name) == 0) - return idx; + if (strcmp(pd->name, name) == 0) { + if (trans == NULL) + return idx; + if (strcmp(pd->trans, trans) == 0) + return idx; + } if (pd->d == NULL) continue; if (xbps_find_virtual_pkg_in_dict(pd->d, name, false)) @@ -108,7 +117,7 @@ pkgdep_release(struct pkgdep *pd) } static struct pkgdep * -pkgdep_alloc(prop_dictionary_t d, const char *name) +pkgdep_alloc(prop_dictionary_t d, const char *name, const char *trans) { struct pkgdep *pd; size_t len; @@ -127,6 +136,7 @@ pkgdep_alloc(prop_dictionary_t d, const char *name) pd->d = NULL; (void)strlcpy(pd->name, name, len); + pd->trans = trans; return pd; } @@ -152,13 +162,14 @@ sort_pkg_rundeps(prop_dictionary_t transd, prop_dictionary_t curpkgd; prop_object_t obj; struct pkgdep *lpd, *pdn; - const char *str; + const char *str, *tract; char *pkgnamedep; - ssize_t pkgdepidx, curpkgidx = pkgdep_find_idx(pd->name); + ssize_t pkgdepidx, curpkgidx; size_t i, idx = 0; int rv = 0; xbps_dbg_printf_append("\n"); + curpkgidx = pkgdep_find_idx(pd->name, pd->trans); again: for (i = idx; i < prop_array_count(pkg_rundeps); i++) { @@ -174,7 +185,7 @@ again: break; } xbps_dbg_printf(" Required dependency '%s': ", str); - pdn = pkgdep_find(pkgnamedep); + pdn = pkgdep_find(pkgnamedep, NULL); if ((pdn == NULL) && xbps_check_is_installed_pkg_by_name(pkgnamedep)) { /* @@ -184,7 +195,7 @@ again: * which is expensive. */ xbps_dbg_printf_append("installed.\n"); - lpd = pkgdep_alloc(NULL, pkgnamedep); + lpd = pkgdep_alloc(NULL, pkgnamedep, "installed"); if (lpd == NULL) { rv = ENOMEM; break; @@ -208,7 +219,9 @@ again: rv = EINVAL; break; } - lpd = pkgdep_alloc(curpkgd, pkgnamedep); + prop_dictionary_get_cstring_nocopy(curpkgd, + "transaction", &tract); + lpd = pkgdep_alloc(curpkgd, pkgnamedep, tract); if (lpd == NULL) { free(pkgnamedep); rv = ENOMEM; @@ -229,7 +242,7 @@ again: /* * Find package dependency index. */ - pkgdepidx = pkgdep_find_idx(pkgnamedep); + pkgdepidx = pkgdep_find_idx(pkgnamedep, tract); /* * If package dependency index is less than current * package index, it's already sorted. @@ -262,7 +275,7 @@ xbps_sort_pkg_deps(void) prop_object_iterator_t iter; struct pkgdep *pd; size_t ndeps = 0, cnt = 0; - const char *pkgname, *pkgver; + const char *pkgname, *pkgver, *tract; int rv = 0; if ((transd = xbps_transaction_dictionary_get()) == NULL) @@ -308,14 +321,15 @@ xbps_sort_pkg_deps(void) while ((obj = prop_object_iterator_next(iter)) != NULL) { prop_dictionary_get_cstring_nocopy(obj, "pkgname", &pkgname); prop_dictionary_get_cstring_nocopy(obj, "pkgver", &pkgver); + prop_dictionary_get_cstring_nocopy(obj, "transaction", &tract); xbps_dbg_printf("Sorting package '%s': ", pkgver); - pd = pkgdep_find(pkgname); + pd = pkgdep_find(pkgname, tract); if (pd == NULL) { /* * If package not in list, just add to the tail. */ - pd = pkgdep_alloc(obj, pkgname); + pd = pkgdep_alloc(obj, pkgname, tract); if (pd == NULL) { pkgdep_end(NULL); prop_object_iterator_release(iter);