diff --git a/NEWS b/NEWS index af7e3a7b..961a4fa6 100644 --- a/NEWS +++ b/NEWS @@ -1,5 +1,12 @@ xbps-0.42 (???): + * libxbps: replaces the internal redundant dependency sorting step + that was made in xbps_transaction_prepare() with a simple implementation + that fixes 2 bugs and makes xbps 2x faster to resolve dependencies. + + Packages that don't have "provides" obj but were declared as virtual packages, + were not detected correctly and lead me to rewrite this code. + * pkgdb: switch to zplists by default. * Fixed issue #62 (Dup replaced pkgs in transaction); see diff --git a/include/xbps_api_impl.h b/include/xbps_api_impl.h index ca5b2dae..46349e8e 100644 --- a/include/xbps_api_impl.h +++ b/include/xbps_api_impl.h @@ -184,19 +184,13 @@ xbps_dictionary_t HIDDEN xbps_find_virtualpkg_in_array(struct xbps_handle *, xbp * @private * From lib/transaction_revdeps.c */ -void HIDDEN xbps_transaction_revdeps(struct xbps_handle *); +void HIDDEN xbps_transaction_revdeps(struct xbps_handle *, xbps_array_t); /** * @privuate * From lib/transaction_shlibs.c */ -bool HIDDEN xbps_transaction_shlibs(struct xbps_handle *); - -/** - * @private - * From lib/transaction_sortdeps.c - */ -int HIDDEN xbps_transaction_sort(struct xbps_handle *); +bool HIDDEN xbps_transaction_shlibs(struct xbps_handle *, xbps_array_t, xbps_array_t); /** * @private @@ -241,7 +235,7 @@ int HIDDEN xbps_set_cb_state(struct xbps_handle *, xbps_state_t, int, */ int HIDDEN xbps_unpack_binary_pkg(struct xbps_handle *, xbps_dictionary_t); -int HIDDEN xbps_transaction_package_replace(struct xbps_handle *); +int HIDDEN xbps_transaction_package_replace(struct xbps_handle *, xbps_array_t); /** * @private diff --git a/lib/Makefile b/lib/Makefile index bb22f36b..b2f2fb63 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -38,7 +38,7 @@ OBJS += package_remove.o package_find_obsoletes.o package_state.o 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_sortdeps.o transaction_ops.o +OBJS += transaction_dictionary.o transaction_ops.o OBJS += transaction_revdeps.o pubkey2fp.o OBJS += download.o initend.o pkgdb.o package_conflicts.o OBJS += plist.o plist_find.o plist_match.o archive.o diff --git a/lib/repo_pkgdeps.c b/lib/repo_pkgdeps.c index c2dccfcd..434267a4 100644 --- a/lib/repo_pkgdeps.c +++ b/lib/repo_pkgdeps.c @@ -40,6 +40,10 @@ store_dependency(struct xbps_handle *xhp, const char *pkgver; char *pkgname, *self_replaced; int rv; + + xbps_dictionary_get_cstring_nocopy(repo_pkgd, "pkgver", &pkgver); + if (xbps_find_pkg_in_array(unsorted, pkgver, NULL)) + return 0; /* * Overwrite package state in dictionary with same state than the * package currently uses, otherwise not-installed. @@ -53,7 +57,6 @@ store_dependency(struct xbps_handle *xhp, !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. */ @@ -370,23 +373,22 @@ find_repo_deps(struct xbps_handle *xhp, } free(pkgname); free(reqpkgname); - /* - * Package is on repo, add it into the transaction dictionary. - */ - xbps_dictionary_set_cstring_nocopy(curpkgd, "transaction", reason); - rv = store_dependency(xhp, unsorted, curpkgd, state); - if (rv != 0) { - xbps_dbg_printf(xhp, "store_dependency failed for `%s': %s\n", reqpkg, strerror(rv)); - break; - } /* * If package doesn't have rundeps, pass to the next one. */ curpkgrdeps = xbps_dictionary_get(curpkgd, "run_depends"); - if (curpkgrdeps == NULL) + if (curpkgrdeps == NULL) { + /* + * Package is on repo, add it into the transaction dictionary. + */ + xbps_dictionary_set_cstring_nocopy(curpkgd, "transaction", reason); + rv = store_dependency(xhp, unsorted, curpkgd, state); + if (rv != 0) { + xbps_dbg_printf(xhp, "store_dependency failed for `%s': %s\n", reqpkg, strerror(rv)); + break; + } continue; - - curpkgprovides = xbps_dictionary_get(curpkgd, "provides"); + } if (xhp->flags & XBPS_FLAG_DEBUG) { xbps_dbg_printf(xhp, ""); @@ -399,11 +401,21 @@ find_repo_deps(struct xbps_handle *xhp, * Recursively find rundeps for current pkg dictionary. */ (*depth)++; + curpkgprovides = xbps_dictionary_get(curpkgd, "provides"); rv = find_repo_deps(xhp, unsorted, curpkgrdeps, curpkgprovides, pkgver_q, depth); if (rv != 0) { xbps_dbg_printf(xhp, "Error checking %s for rundeps: %s\n", reqpkg, strerror(rv)); break; } + /* + * Package is on repo, add it into the transaction dictionary. + */ + xbps_dictionary_set_cstring_nocopy(curpkgd, "transaction", reason); + rv = store_dependency(xhp, unsorted, curpkgd, state); + if (rv != 0) { + xbps_dbg_printf(xhp, "store_dependency failed for `%s': %s\n", reqpkg, strerror(rv)); + break; + } } xbps_object_iterator_release(iter); (*depth)--; diff --git a/lib/transaction_dictionary.c b/lib/transaction_dictionary.c index 9abcc81a..4ccdec95 100644 --- a/lib/transaction_dictionary.c +++ b/lib/transaction_dictionary.c @@ -201,7 +201,7 @@ xbps_transaction_init(struct xbps_handle *xhp) xhp->transd = NULL; return ENOMEM; } - if (!xbps_dictionary_set(xhp->transd, "unsorted_deps", array)) { + if (!xbps_dictionary_set(xhp->transd, "packages", array)) { xbps_object_release(xhp->transd); xhp->transd = NULL; return EINVAL; @@ -250,8 +250,8 @@ xbps_transaction_init(struct xbps_handle *xhp) int xbps_transaction_prepare(struct xbps_handle *xhp) { - xbps_array_t array; - unsigned int i; + xbps_array_t array, pkgs, edges; + unsigned int i, cnt; int rv = 0; if (xhp->transd == NULL) @@ -260,22 +260,50 @@ xbps_transaction_prepare(struct xbps_handle *xhp) /* * Collect dependencies for pkgs in transaction. */ - array = xbps_dictionary_get(xhp->transd, "unsorted_deps"); - for (i = 0; i < xbps_array_count(array); i++) { - if ((rv = xbps_repository_find_deps(xhp, array, xbps_array_get(array, i))) != 0) + if ((edges = xbps_array_create()) == NULL) + return ENOMEM; + /* + * The edges are also appended after its dependencies have been + * collected; the edges at the original array are removed later. + */ + pkgs = xbps_dictionary_get(xhp->transd, "packages"); + assert(xbps_object_type(pkgs) == XBPS_TYPE_ARRAY); + cnt = xbps_array_count(pkgs); + for (i = 0; i < cnt; i++) { + xbps_dictionary_t pkgd; + xbps_string_t str; + + pkgd = xbps_array_get(pkgs, i); + str = xbps_dictionary_get(pkgd, "pkgver"); + assert(xbps_object_type(str) == XBPS_TYPE_STRING); + + if (!xbps_array_add(edges, str)) + return ENOMEM; + + if ((rv = xbps_repository_find_deps(xhp, pkgs, pkgd)) != 0) return rv; + + if (!xbps_array_add(pkgs, pkgd)) + return ENOMEM; } + /* ... remove dup edges at head */ + for (i = 0; i < xbps_array_count(edges); i++) { + const char *pkgver; + xbps_array_get_cstring_nocopy(edges, i, &pkgver); + xbps_remove_pkg_from_array_by_pkgver(pkgs, pkgver); + } + xbps_object_release(edges); + /* * If there are missing deps or revdeps bail out. */ - xbps_transaction_revdeps(xhp); + xbps_transaction_revdeps(xhp, pkgs); array = xbps_dictionary_get(xhp->transd, "missing_deps"); if (xbps_array_count(array)) return ENODEV; - array = xbps_dictionary_get(xhp->transd, "unsorted_deps"); - for (i = 0; i < xbps_array_count(array); i++) - xbps_pkg_find_conflicts(xhp, array, xbps_array_get(array, i)); + 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. */ @@ -285,7 +313,7 @@ xbps_transaction_prepare(struct xbps_handle *xhp) /* * Check for packages to be replaced. */ - if ((rv = xbps_transaction_package_replace(xhp)) != 0) { + if ((rv = xbps_transaction_package_replace(xhp, pkgs)) != 0) { xbps_object_release(xhp->transd); xhp->transd = NULL; return rv; @@ -293,17 +321,9 @@ xbps_transaction_prepare(struct xbps_handle *xhp) /* * Check for unresolved shared libraries. */ - if (xbps_transaction_shlibs(xhp)) + if (xbps_transaction_shlibs(xhp, pkgs, xbps_dictionary_get(xhp->transd, "missing_shlibs"))) return ENOEXEC; - /* - * Sort package dependencies if necessary. - */ - if ((rv = xbps_transaction_sort(xhp)) != 0) { - xbps_object_release(xhp->transd); - xhp->transd = NULL; - return rv; - } /* * Add transaction stats for total download/installed size, * number of packages to be installed, updated, configured @@ -317,7 +337,6 @@ xbps_transaction_prepare(struct xbps_handle *xhp) /* * Remove now unneeded objects. */ - xbps_dictionary_remove(xhp->transd, "unsorted"); xbps_dictionary_remove(xhp->transd, "missing_shlibs"); xbps_dictionary_remove(xhp->transd, "missing_deps"); xbps_dictionary_remove(xhp->transd, "conflicts"); diff --git a/lib/transaction_ops.c b/lib/transaction_ops.c index d3d30ccb..a494a713 100644 --- a/lib/transaction_ops.c +++ b/lib/transaction_ops.c @@ -62,7 +62,7 @@ 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, replaces; + xbps_array_t pkgs, replaces; const char *repoloc, *repopkgver, *instpkgver, *reason; char *self_replaced, *pkgname; int action = 0, rv = 0; @@ -151,13 +151,13 @@ trans_find_pkg(struct xbps_handle *xhp, const char *pkg, bool reinstall) if ((rv = xbps_transaction_init(xhp)) != 0) return rv; - unsorted = xbps_dictionary_get(xhp->transd, "unsorted_deps"); + pkgs = xbps_dictionary_get(xhp->transd, "packages"); /* * Find out if package being updated matches the one already * in transaction, in that case ignore it. */ if (action == TRANS_UPDATE) { - if (xbps_find_pkg_in_array(unsorted, repopkgver, NULL)) { + if (xbps_find_pkg_in_array(pkgs, repopkgver, NULL)) { xbps_dbg_printf(xhp, "[update] `%s' already queued in " "transaction.\n", repopkgver); return EEXIST; @@ -212,9 +212,9 @@ trans_find_pkg(struct xbps_handle *xhp, const char *pkg, bool reinstall) } /* * Add the pkg dictionary from repository's index dictionary into - * the "unsorted" queue. + * the packages array. */ - if (!xbps_array_add(unsorted, pkg_repod)) { + if (!xbps_array_add(pkgs, pkg_repod)) { free(pkgname); return EINVAL; } @@ -290,7 +290,7 @@ xbps_transaction_remove_pkg(struct xbps_handle *xhp, bool recursive) { xbps_dictionary_t pkgd; - xbps_array_t unsorted, orphans, orphans_pkg, reqby; + xbps_array_t pkgs, orphans, orphans_pkg, reqby; xbps_object_t obj; const char *pkgver; unsigned int count; @@ -308,7 +308,7 @@ xbps_transaction_remove_pkg(struct xbps_handle *xhp, if ((rv = xbps_transaction_init(xhp)) != 0) return rv; - unsorted = xbps_dictionary_get(xhp->transd, "unsorted_deps"); + pkgs = xbps_dictionary_get(xhp->transd, "packages"); if (!recursive) goto rmpkg; @@ -330,7 +330,7 @@ xbps_transaction_remove_pkg(struct xbps_handle *xhp, obj = xbps_array_get(orphans, count); xbps_dictionary_get_cstring_nocopy(obj, "pkgver", &pkgver); xbps_dictionary_set_cstring_nocopy(obj, "transaction", "remove"); - xbps_array_add(unsorted, obj); + xbps_array_add(pkgs, obj); xbps_dbg_printf(xhp, "%s: added into transaction (remove).\n", pkgver); } reqby = xbps_pkgdb_get_pkg_revdeps(xhp, pkgname); @@ -347,11 +347,11 @@ xbps_transaction_remove_pkg(struct xbps_handle *xhp, rmpkg: /* - * Add pkg dictionary into the transaction unsorted queue. + * Add pkg dictionary into the transaction pkgs queue. */ xbps_dictionary_get_cstring_nocopy(pkgd, "pkgver", &pkgver); xbps_dictionary_set_cstring_nocopy(pkgd, "transaction", "remove"); - xbps_array_add(unsorted, pkgd); + xbps_array_add(pkgs, pkgd); xbps_dbg_printf(xhp, "%s: added into transaction (remove).\n", pkgver); reqby = xbps_pkgdb_get_pkg_revdeps(xhp, pkgver); /* @@ -368,7 +368,7 @@ rmpkg: int xbps_transaction_autoremove_pkgs(struct xbps_handle *xhp) { - xbps_array_t orphans, unsorted; + xbps_array_t orphans, pkgs; xbps_object_t obj; const char *pkgver; unsigned int count; @@ -386,16 +386,16 @@ xbps_transaction_autoremove_pkgs(struct xbps_handle *xhp) if ((rv = xbps_transaction_init(xhp)) != 0) goto out; - unsorted = xbps_dictionary_get(xhp->transd, "unsorted_deps"); + pkgs = xbps_dictionary_get(xhp->transd, "packages"); /* - * Add pkg orphan dictionary into the transaction unsorted queue. + * Add pkg orphan dictionary into the transaction pkgs queue. */ while (count--) { obj = xbps_array_get(orphans, count); xbps_dictionary_get_cstring_nocopy(obj, "pkgver", &pkgver); xbps_dictionary_set_cstring_nocopy(obj, "transaction", "remove"); - xbps_array_add(unsorted, obj); + xbps_array_add(pkgs, obj); xbps_dbg_printf(xhp, "%s: added (remove).\n", pkgver); } out: diff --git a/lib/transaction_package_replace.c b/lib/transaction_package_replace.c index 2eebd51d..3c0603be 100644 --- a/lib/transaction_package_replace.c +++ b/lib/transaction_package_replace.c @@ -34,20 +34,16 @@ #include "xbps_api_impl.h" int HIDDEN -xbps_transaction_package_replace(struct xbps_handle *xhp) +xbps_transaction_package_replace(struct xbps_handle *xhp, xbps_array_t pkgs) { - xbps_array_t unsorted; - - unsorted = xbps_dictionary_get(xhp->transd, "unsorted_deps"); - - for (unsigned int i = 0; i < xbps_array_count(unsorted); i++) { + for (unsigned int i = 0; i < xbps_array_count(pkgs); i++) { xbps_array_t replaces; xbps_object_t obj, obj2; xbps_object_iterator_t iter; const char *pkgver; char *pkgname; - obj = xbps_array_get(unsorted, i); + obj = xbps_array_get(pkgs, i); replaces = xbps_dictionary_get(obj, "replaces"); if (replaces == NULL || xbps_array_count(replaces) == 0) continue; @@ -89,7 +85,7 @@ xbps_transaction_package_replace(struct xbps_handle *xhp) /* * Make sure to not add duplicates. */ - reppkgd = xbps_find_pkg_in_array(unsorted, curpkgname, NULL); + reppkgd = xbps_find_pkg_in_array(pkgs, curpkgname, NULL); if (reppkgd) { xbps_dictionary_get_cstring_nocopy(reppkgd, "transaction", &tract); @@ -102,12 +98,12 @@ xbps_transaction_package_replace(struct xbps_handle *xhp) * transaction and it's going to be updated. */ xbps_dictionary_get_bool(instd, "automatic-install", &instd_auto); - if ((reppkgd = xbps_find_pkg_in_array(unsorted, curpkgname, NULL))) { + if ((reppkgd = xbps_find_pkg_in_array(pkgs, curpkgname, NULL))) { xbps_dictionary_set_bool(reppkgd, "automatic-install", instd_auto); xbps_dictionary_set_bool(reppkgd, "skip-obsoletes", true); - xbps_array_replace_dict_by_name(unsorted, + xbps_array_replace_dict_by_name(pkgs, reppkgd, curpkgname); continue; } @@ -129,7 +125,7 @@ xbps_transaction_package_replace(struct xbps_handle *xhp) */ xbps_dictionary_set_cstring_nocopy(instd, "transaction", "remove"); - xbps_array_add(unsorted, instd); + xbps_array_add(pkgs, instd); free(curpkgname); } xbps_object_iterator_release(iter); diff --git a/lib/transaction_revdeps.c b/lib/transaction_revdeps.c index f02a11c5..14a5df5c 100644 --- a/lib/transaction_revdeps.c +++ b/lib/transaction_revdeps.c @@ -42,13 +42,13 @@ */ static bool check_virtual_pkgs(struct xbps_handle *xhp, + xbps_array_t pkgs, xbps_dictionary_t trans_pkgd, xbps_dictionary_t rev_pkgd) { - xbps_array_t unsorted, provides; + xbps_array_t provides; bool matched = false; - unsorted = xbps_dictionary_get(xhp->transd, "unsorted_deps"); provides = xbps_dictionary_get(trans_pkgd, "provides"); for (unsigned int i = 0; i < xbps_array_count(provides); i++) { xbps_array_t rundeps, mdeps; @@ -90,7 +90,7 @@ check_virtual_pkgs(struct xbps_handle *xhp, xbps_dictionary_get_cstring_nocopy(trans_pkgd, "pkgver", &pkgver); pkgdepname = xbps_pkg_name(pkgver); assert(pkgdepname); - if (xbps_find_pkg_in_array(unsorted, pkgdepname, NULL)) { + if (xbps_find_pkg_in_array(pkgs, pkgdepname, NULL)) { free(pkgdepname); continue; } @@ -113,18 +113,16 @@ check_virtual_pkgs(struct xbps_handle *xhp, } void HIDDEN -xbps_transaction_revdeps(struct xbps_handle *xhp) +xbps_transaction_revdeps(struct xbps_handle *xhp, xbps_array_t pkgs) { - xbps_array_t mdeps, unsorted, pkgrdeps, rundeps; + xbps_array_t mdeps, pkgrdeps, rundeps; xbps_dictionary_t revpkgd; xbps_object_t obj; const char *pkgver, *curdep, *revpkgver, *curpkgver, *tract; char *pkgname, *curdepname, *curpkgname, *str; - unsorted = xbps_dictionary_get(xhp->transd, "unsorted_deps"); - - for (unsigned int i = 0; i < xbps_array_count(unsorted); i++) { - obj = xbps_array_get(unsorted, i); + for (unsigned int i = 0; i < xbps_array_count(pkgs); i++) { + obj = xbps_array_get(pkgs, i); /* * Only check packages in transaction being updated. */ @@ -163,7 +161,7 @@ xbps_transaction_revdeps(struct xbps_handle *xhp) /* * First try to match any supported virtual package. */ - if (check_virtual_pkgs(xhp, obj, revpkgd)) + if (check_virtual_pkgs(xhp, pkgs, obj, revpkgd)) continue; /* * Try to match real dependencies. @@ -200,7 +198,7 @@ xbps_transaction_revdeps(struct xbps_handle *xhp) * is in the transaction. */ pkgname = xbps_pkg_name(curpkgver); - if (xbps_find_pkg_in_array(unsorted, pkgname, NULL)) { + if (xbps_find_pkg_in_array(pkgs, pkgname, NULL)) { free(pkgname); continue; } diff --git a/lib/transaction_shlibs.c b/lib/transaction_shlibs.c index 913dd9f6..5f7d4221 100644 --- a/lib/transaction_shlibs.c +++ b/lib/transaction_shlibs.c @@ -43,9 +43,9 @@ * Abort transaction if such case is found. */ static bool -shlib_trans_matched(struct xbps_handle *xhp, const char *pkgver, const char *shlib) +shlib_trans_matched(xbps_array_t pkgs, const char *pkgver, const char *shlib) { - xbps_array_t unsorted, shrequires; + xbps_array_t shrequires; xbps_dictionary_t pkgd; const char *tract; char *pkgname; @@ -53,8 +53,7 @@ shlib_trans_matched(struct xbps_handle *xhp, const char *pkgver, const char *shl pkgname = xbps_pkg_name(pkgver); assert(pkgname); - unsorted = xbps_dictionary_get(xhp->transd, "unsorted_deps"); - if ((pkgd = xbps_find_pkg_in_array(unsorted, pkgname, NULL)) == NULL) { + if ((pkgd = xbps_find_pkg_in_array(pkgs, pkgname, NULL)) == NULL) { free(pkgname); return false; } @@ -72,7 +71,7 @@ shlib_trans_matched(struct xbps_handle *xhp, const char *pkgver, const char *shl } static bool -shlib_matched(struct xbps_handle *xhp, xbps_array_t unsorted, xbps_array_t mshlibs, +shlib_matched(struct xbps_handle *xhp, xbps_array_t pkgs, xbps_array_t mshlibs, const char *pkgver, const char *shlib) { xbps_array_t revdeps; @@ -106,7 +105,7 @@ shlib_matched(struct xbps_handle *xhp, xbps_array_t unsorted, xbps_array_t mshli * First check if this revdep has been queued in transaction; * otherwise process the current installed pkg. */ - pkgd = xbps_find_pkg_in_array(unsorted, rpkgname, NULL); + pkgd = xbps_find_pkg_in_array(pkgs, rpkgname, NULL); free(rpkgname); if (pkgd) { /* @@ -137,7 +136,7 @@ shlib_matched(struct xbps_handle *xhp, xbps_array_t unsorted, xbps_array_t mshli * installed pkg; find out if there's an update * in the transaction with the matching version. */ - if (!shlib_trans_matched(xhp, rpkgver, shlib)) { + if (!shlib_trans_matched(pkgs, rpkgver, shlib)) { char *buf; /* shlib not matched */ buf = xbps_xasprintf("%s breaks `%s' " @@ -159,21 +158,17 @@ shlib_matched(struct xbps_handle *xhp, xbps_array_t unsorted, xbps_array_t mshli bool HIDDEN -xbps_transaction_shlibs(struct xbps_handle *xhp) +xbps_transaction_shlibs(struct xbps_handle *xhp, xbps_array_t pkgs, xbps_array_t mshlibs) { - xbps_array_t unsorted, mshlibs; bool unmatched = false; - mshlibs = xbps_dictionary_get(xhp->transd, "missing_shlibs"); - unsorted = xbps_dictionary_get(xhp->transd, "unsorted_deps"); - - for (unsigned int i = 0; i < xbps_array_count(unsorted); i++) { + for (unsigned int i = 0; i < xbps_array_count(pkgs); i++) { xbps_array_t shprovides; xbps_object_t obj, pkgd; const char *pkgver, *tract; char *pkgname; - obj = xbps_array_get(unsorted, i); + obj = xbps_array_get(pkgs, i); /* * If pkg does not have 'shlib-provides' obj, pass to next one. */ @@ -206,7 +201,7 @@ xbps_transaction_shlibs(struct xbps_handle *xhp) * Check that all shlibs provided by this pkg are used by * its revdeps. */ - if (!shlib_matched(xhp, unsorted, mshlibs, pkgver, shlib)) + if (!shlib_matched(xhp, pkgs, mshlibs, pkgver, shlib)) unmatched = true; } } diff --git a/lib/transaction_sortdeps.c b/lib/transaction_sortdeps.c deleted file mode 100644 index cb394645..00000000 --- a/lib/transaction_sortdeps.c +++ /dev/null @@ -1,392 +0,0 @@ -/*- - * Copyright (c) 2009-2014 Juan Romero Pardines. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include -#include -#include -#include - -#include "xbps_api_impl.h" - -/* - * Sorting algorithm for packages in the transaction dictionary. - * The transaction dictionary contains all package dictionaries found from - * the repository plist index file in the "unsorted_deps" array. - * - * Any package in the unsorted_deps array is added into the tail and - * later if a package dependency has an index greater than current - * package, the package dependency is moved just before it. - * - * Once that all package dependencies for a package are in the correct - * index, the counter is increased. When all packages in the "unsorted_deps" - * array are processed the loop is stopped and the counter should have - * the same number than the "unsorted_deps" array... otherwise something - * went wrong. - */ - -struct pkgdep { - TAILQ_ENTRY(pkgdep) pkgdep_entries; - xbps_dictionary_t d; - char *name; -}; - -static TAILQ_HEAD(pkgdep_head, pkgdep) pkgdep_list = - TAILQ_HEAD_INITIALIZER(pkgdep_list); - -static struct pkgdep * -pkgdep_find(const char *pkg) -{ - struct pkgdep *pd = NULL; - const char *pkgver, *tract; - - TAILQ_FOREACH(pd, &pkgdep_list, pkgdep_entries) { - if (pd->d == NULL) { - /* ignore entries without dictionary */ - continue; - } - xbps_dictionary_get_cstring_nocopy(pd->d, - "transaction", &tract); - /* ignore pkgs to be removed */ - if (strcmp(tract, "remove") == 0) - continue; - /* simple match */ - xbps_dictionary_get_cstring_nocopy(pd->d, "pkgver", &pkgver); - if (strcmp(pkgver, pkg) == 0) - return pd; - /* pkg expression match */ - if (xbps_pkgpattern_match(pkgver, pkg)) - return pd; - /* virtualpkg expression match */ - if (xbps_match_virtual_pkg_in_dict(pd->d, pkg)) - return pd; - } - - /* not found */ - return NULL; -} - -static int32_t -pkgdep_find_idx(const char *pkg) -{ - struct pkgdep *pd; - int32_t idx = 0; - const char *pkgver, *tract; - - TAILQ_FOREACH(pd, &pkgdep_list, pkgdep_entries) { - if (pd->d == NULL) { - /* ignore entries without dictionary */ - idx++; - continue; - } - xbps_dictionary_get_cstring_nocopy(pd->d, - "transaction", &tract); - /* ignore pkgs to be removed */ - if (strcmp(tract, "remove") == 0) { - idx++; - continue; - } - /* simple match */ - xbps_dictionary_get_cstring_nocopy(pd->d, "pkgver", &pkgver); - if (strcmp(pkgver, pkg) == 0) - return idx; - /* pkg expression match */ - if (xbps_pkgpattern_match(pkgver, pkg)) - return idx; - /* virtualpkg expression match */ - if (xbps_match_virtual_pkg_in_dict(pd->d, pkg)) - return idx; - - idx++; - } - /* not found */ - return -1; -} - -static void -pkgdep_release(struct pkgdep *pd) -{ - free(pd->name); - free(pd); -} - -static struct pkgdep * -pkgdep_alloc(xbps_dictionary_t d, const char *pkg) -{ - struct pkgdep *pd; - - pd = malloc(sizeof(*pd)); - assert(pd); - pd->d = d; - pd->name = strdup(pkg); - - return pd; -} - -static void -pkgdep_end(xbps_array_t sorted) -{ - struct pkgdep *pd; - - while ((pd = TAILQ_FIRST(&pkgdep_list)) != NULL) { - TAILQ_REMOVE(&pkgdep_list, pd, pkgdep_entries); - if (sorted != NULL && pd->d != NULL) - xbps_array_add(sorted, pd->d); - - pkgdep_release(pd); - } -} - -static int -sort_pkg_rundeps(struct xbps_handle *xhp, - struct pkgdep *pd, - xbps_array_t pkg_rundeps, - xbps_array_t unsorted) -{ - xbps_array_t provides; - xbps_dictionary_t curpkgd; - struct pkgdep *lpd, *pdn; - const char *str; - int32_t pkgdepidx, curpkgidx; - uint32_t i, idx = 0; - int rv = 0; - - xbps_dbg_printf_append(xhp, "\n"); - curpkgidx = pkgdep_find_idx(pd->name); - -again: - for (i = idx; i < xbps_array_count(pkg_rundeps); i++) { - xbps_array_get_cstring_nocopy(pkg_rundeps, i, &str); - xbps_dbg_printf(xhp, " Required dependency '%s': ", str); - - pdn = pkgdep_find(str); - if ((pdn == NULL) && xbps_pkg_is_installed(xhp, str)) { - /* - * Package dependency is installed, just add to - * the list but just mark it as "installed", to avoid - * calling xbps_pkg_is_installed(), - * which is expensive. - */ - xbps_dbg_printf_append(xhp, "installed.\n"); - lpd = pkgdep_alloc(NULL, str); - TAILQ_INSERT_TAIL(&pkgdep_list, lpd, pkgdep_entries); - continue; - } else if (pdn != NULL && pdn->d == NULL) { - /* - * Package was added previously into the list - * and is installed, skip. - */ - xbps_dbg_printf_append(xhp, "installed.\n"); - continue; - } - if (((curpkgd = xbps_find_pkg_in_array(unsorted, str, "remove")) == NULL) && - ((curpkgd = xbps_find_virtualpkg_in_array(xhp, unsorted, str, "remove")) == NULL)) { - xbps_dbg_printf_append(xhp, "cannot find %s in unsorted array\n", str); - rv = EINVAL; - break; - } - if (pd->d) { - provides = xbps_dictionary_get(pd->d, "provides"); - if (provides && xbps_match_virtual_pkg_in_array(provides, str)) { - xbps_dbg_printf_append(xhp, "%s is a vpkg provided by %s, ignored.\n", str, pd->name); - continue; - } - } - lpd = pkgdep_alloc(curpkgd, str); - if (pdn == NULL) { - /* - * If package is not in the list, add to the tail - * and iterate at the same position. - */ - TAILQ_INSERT_TAIL(&pkgdep_list, lpd, pkgdep_entries); - idx = i; - xbps_dbg_printf_append(xhp, "added into the tail, " - "checking again...\n"); - goto again; - } - /* - * Find package dependency index. - */ - pkgdepidx = pkgdep_find_idx(str); - /* - * If package dependency index is less than current - * package index, it's already sorted. - */ - if (pkgdepidx < curpkgidx) { - xbps_dbg_printf_append(xhp, "already sorted.\n"); - pkgdep_release(lpd); - } else if (pd == pdn) { - /* - * Processing same pkg, just continue. - */ - xbps_dbg_printf_append(xhp, "already sorted.\n"); - pkgdep_release(lpd); - } else { - /* - * Remove package dependency from list and move - * it before current package. - */ - TAILQ_REMOVE(&pkgdep_list, pdn, pkgdep_entries); - pkgdep_release(pdn); - TAILQ_INSERT_BEFORE(pd, lpd, pkgdep_entries); - xbps_dbg_printf_append(xhp, - "added before `%s'.\n", pd->name); - } - } - - return rv; -} - -int HIDDEN -xbps_transaction_sort(struct xbps_handle *xhp) -{ - xbps_array_t provides, sorted, unsorted, rundeps; - xbps_object_t obj; - struct pkgdep *pd; - unsigned int ndeps = 0, cnt = 0; - const char *pkgver, *tract, *vpkgdep; - int rv = 0; - bool vpkg_found; - - if ((sorted = xbps_array_create()) == NULL) - return ENOMEM; - /* - * Add sorted packages array into transaction dictionary (empty). - */ - if (!xbps_dictionary_set(xhp->transd, "packages", sorted)) { - rv = EINVAL; - goto out; - } - /* - * All required deps are satisfied (already installed). - */ - unsorted = xbps_dictionary_get(xhp->transd, "unsorted_deps"); - if (xbps_array_count(unsorted) == 0) { - xbps_dictionary_set(xhp->transd, "packages", sorted); - xbps_object_release(sorted); - return 0; - } - /* - * The sorted array should have the same capacity than - * all objects in the unsorted array. - */ - ndeps = xbps_array_count(unsorted); - /* - * Iterate over the unsorted package dictionaries and sort all - * its package dependencies. - */ - for (unsigned int i = 0; i < ndeps; i++) { - vpkg_found = false; - obj = xbps_array_get(unsorted, i); - xbps_dictionary_get_cstring_nocopy(obj, "pkgver", &pkgver); - xbps_dictionary_get_cstring_nocopy(obj, "transaction", &tract); - provides = xbps_dictionary_get(obj, "provides"); - xbps_dbg_printf(xhp, "Sorting package '%s' (%s): ", pkgver, tract); - - if (provides) { - /* - * If current pkgdep provides any virtual pkg check - * if any of them was previously added. If true, don't - * add it into the list again, just order its deps. - */ - for (unsigned int j = 0; j < xbps_array_count(provides); j++) { - xbps_array_get_cstring_nocopy(provides, - j, &vpkgdep); - pd = pkgdep_find(vpkgdep); - if (pd != NULL) { - xbps_dbg_printf_append(xhp, "already " - "sorted via `%s' vpkg.", vpkgdep); - vpkg_found = true; - break; - } - } - } - pd = pkgdep_find(pkgver); - if ((!strcmp(tract, "remove") || (!pd && !vpkg_found))) { - /* - * If package not in list, just add to the tail. - */ - pd = pkgdep_alloc(obj, pkgver); - if (pd == NULL) { - pkgdep_end(NULL); - rv = ENOMEM; - goto out; - } - if (strcmp(tract, "remove") == 0) { - xbps_dbg_printf_append(xhp, "added into head.\n"); - TAILQ_INSERT_HEAD(&pkgdep_list, pd, - pkgdep_entries); - cnt++; - continue; - } else { - xbps_dbg_printf_append(xhp, "added into tail."); - TAILQ_INSERT_TAIL(&pkgdep_list, pd, - pkgdep_entries); - } - } - if (pd == NULL) - continue; - /* - * Packages that don't have deps go at head, because - * it doesn't matter. - */ - rundeps = xbps_dictionary_get(obj, "run_depends"); - if (xbps_array_count(rundeps) == 0) { - xbps_dbg_printf_append(xhp, "\n"); - cnt++; - continue; - } - /* - * Sort package run-time dependencies for this package. - */ - if ((rv = sort_pkg_rundeps(xhp, pd, rundeps, unsorted)) != 0) { - pkgdep_end(NULL); - goto out; - } - cnt++; - } - /* - * We are done, now we have to copy all pkg dictionaries - * from the sorted list into the "packages" array, and at - * the same time freeing memory used for temporary sorting. - */ - pkgdep_end(sorted); - /* - * Sanity check that the array contains the same number of - * objects than the total number of required dependencies. - */ - assert(cnt == xbps_array_count(unsorted)); - /* - * We are done, all packages were sorted... remove the - * temporary array with unsorted packages. - */ - xbps_dictionary_remove(xhp->transd, "unsorted_deps"); -out: - if (rv != 0) - xbps_dictionary_remove(xhp->transd, "packages"); - - xbps_object_release(sorted); - - return rv; -} diff --git a/tests/xbps/libxbps/shell/install_test.sh b/tests/xbps/libxbps/shell/install_test.sh index eabc7f8e..f76efeaa 100644 --- a/tests/xbps/libxbps/shell/install_test.sh +++ b/tests/xbps/libxbps/shell/install_test.sh @@ -80,7 +80,7 @@ install_with_vpkg_deps_body() { atf_check_equal $? 0 cd .. - echo -e "C-1.0_1\nA-1.0_1\nB-1.0_1\nD-1.0_1\n" > exp + echo -e "A-1.0_1\nB-1.0_1\nD-1.0_1\nC-1.0_1\n" > exp xbps-install -C empty.conf -r root --repository=$PWD/some_repo -yn E|awk '{print $1}' > out echo >> out echo "exp: '$(cat exp)'" >&2