diff --git a/NEWS b/NEWS index d48b3994..4afd9dfb 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,13 @@ +xbps-0.6.1 (2010-10-23): + + * When replacing a package that is going to be updated in the transaction + do not remove it, just overwrite its files and continue. The updated + package will find that old files didn't match the SHA256 hash and will + skip them. This solves the issue of new package updates requiring new + dependencies with files that were previously stored in the old version. + For example gtk+-2.20 containing gdk-pixbuf, and gtk+-2.22 requiring + gdk-pixbuf externally. + xbps-0.6.0 (2010-06-03): * Synced libfetch code with NetBSD pkgsrc, updated to 2.31. diff --git a/bin/xbps-bin/install.c b/bin/xbps-bin/install.c index 7296e64e..5d4130a2 100644 --- a/bin/xbps-bin/install.c +++ b/bin/xbps-bin/install.c @@ -399,18 +399,21 @@ xbps_update_pkg(const char *pkgname) } static int -replace_packages(prop_object_iterator_t iter, const char *pkgver) +replace_packages(prop_dictionary_t trans_dict, prop_dictionary_t pkgd, + prop_object_iterator_t replaces_iter, const char *pkgver) { - prop_dictionary_t instd; + prop_dictionary_t instd = NULL, transd = NULL; prop_object_t obj; const char *pattern, *reppkgn, *reppkgver, *version; int rv = 0; /* * This package replaces other package(s), so we remove - * them before upgrading or installing new one. + * them before upgrading or installing new one. If the package + * to be replaced is in the transaction and to be updated, + * the new package will overwrite its files. */ - while ((obj = prop_object_iterator_next(iter))) { + while ((obj = prop_object_iterator_next(replaces_iter))) { pattern = prop_string_cstring_nocopy(obj); if (pattern == NULL) return errno; @@ -424,6 +427,25 @@ replace_packages(prop_object_iterator_t iter, const char *pkgver) prop_dictionary_get_cstring_nocopy(instd, "pkgname", &reppkgn); prop_dictionary_get_cstring_nocopy(instd, "pkgver", &reppkgver); + /* + * If the package to be replaced is in the transaction due to + * an update, do not remove it; just overwrite its files. + */ + transd = xbps_find_pkg_in_dict_by_name(trans_dict, + "packages", reppkgn); + if (transd) { + /* + * Set the bool property 'replace-files-in-pkg-update'. + */ + prop_dictionary_set_bool(pkgd, + "replace-files-in-pkg-update", true); + printf("Replacing some files from '%s (will be " + "updated)' with '%s' (matched by '%s')...\n", + reppkgver, pkgver, pattern); + prop_object_release(instd); + continue; + } + printf("Replacing package '%s' with '%s' " "(matched by '%s')...\n", reppkgver, pkgver, pattern); prop_object_release(instd); @@ -436,7 +458,7 @@ replace_packages(prop_object_iterator_t iter, const char *pkgver) return rv; } } - prop_object_iterator_release(iter); + prop_object_iterator_release(replaces_iter); return 0; } @@ -496,14 +518,15 @@ exec_transaction(struct transaction *trans) if (!prop_dictionary_get_cstring_nocopy(obj, "pkgver", &pkgver)) return errno; - prop_dictionary_get_bool(obj, "automatic-install", &autoinst); - prop_dictionary_get_bool(obj, "preserve", &preserve); if (!prop_dictionary_get_cstring_nocopy(obj, "filename", &filename)) return errno; if (!prop_dictionary_get_cstring_nocopy(obj, "trans-action", &tract)) return errno; + + prop_dictionary_get_bool(obj, "automatic-install", &autoinst); + prop_dictionary_get_bool(obj, "preserve", &preserve); replaces_iter = xbps_get_array_iter_from_dict(obj, "replaces"); /* @@ -520,7 +543,7 @@ exec_transaction(struct transaction *trans) * Replace package(s) if necessary. */ if (replaces_iter != NULL) { - rv = replace_packages(replaces_iter, pkgver); + rv = replace_packages(trans->dict, obj, replaces_iter, pkgver); if (rv != 0) { fprintf(stderr, "xbps-bin: couldn't replace some " @@ -635,6 +658,7 @@ xbps_exec_transaction(bool yes) goto out; } + DPRINTF(("Dictionary before transaction happens:\n")); DPRINTF(("%s", prop_dictionary_externalize(trans->dict))); /* @@ -649,6 +673,8 @@ xbps_exec_transaction(bool yes) trans->yes = yes; rv = exec_transaction(trans); + DPRINTF(("Dictionary AFTER transaction happened:\n")); + DPRINTF(("%s", prop_dictionary_externalize(trans->dict))); out: if (trans->iter) diff --git a/lib/unpack.c b/lib/unpack.c index 37b3651c..c4bdd540 100644 --- a/lib/unpack.c +++ b/lib/unpack.c @@ -98,13 +98,13 @@ unpack_archive_fini(struct archive *ar, prop_dictionary_t pkg) const char *pkgname, *version, *rootdir, *entry_str, *transact; char *buf; int rv, flags, lflags; - bool preserve, skip_entry, update; + bool preserve, skip_entry, update, replace_files_in_pkg_update; bool props_plist_found, files_plist_found; assert(ar != NULL); assert(pkg != NULL); - preserve = skip_entry = update = false; + preserve = skip_entry = update = replace_files_in_pkg_update = false; props_plist_found = files_plist_found = false; rootdir = xbps_get_rootdir(); flags = xbps_get_flags(); @@ -281,6 +281,32 @@ unpack_archive_fini(struct archive *ar, prop_dictionary_t pkg) 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, "replace-files-in-pkg-update", + &replace_files_in_pkg_update); + if (replace_files_in_pkg_update) { + lflags &= ~ARCHIVE_EXTRACT_NO_OVERWRITE; + lflags &= ~ARCHIVE_EXTRACT_NO_OVERWRITE_NEWER; + } + /* * Extract entry from archive. */