diff --git a/bin/xbps-bin/install.c b/bin/xbps-bin/install.c index 8018ef4c..908a5ea5 100644 --- a/bin/xbps-bin/install.c +++ b/bin/xbps-bin/install.c @@ -639,21 +639,18 @@ xbps_exec_transaction(bool yes) if (trans == NULL) return rv; - trans->dict = xbps_repository_get_transaction_dict(); + trans->dict = xbps_transaction_prepare(); if (trans->dict == NULL) { + if (errno == ENODEV) { + /* missing packages */ + array = xbps_transaction_missingdeps_get(); + show_missing_deps(trans->dict); + goto out; + } xbps_dbg_printf("Empty transaction dictionary: %s\n", strerror(errno)); goto out; } - /* - * Bail out if there are unresolved deps. - */ - array = prop_dictionary_get(trans->dict, "missing_deps"); - if (array && prop_array_count(array) > 0) { - show_missing_deps(trans->dict); - goto out; - } - xbps_dbg_printf("Dictionary before transaction happens:\n"); xbps_dbg_printf_append("%s", prop_dictionary_externalize(trans->dict)); @@ -676,5 +673,6 @@ out: prop_object_release(trans->dict); if (trans) free(trans); + return rv; } diff --git a/include/xbps_api.h b/include/xbps_api.h index 7348b9ed..cf970d00 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 "20110119" +#define XBPS_RELVER "20110124" /** * @def XBPS_META_PATH @@ -687,22 +687,36 @@ int xbps_repository_update_pkg(const char *pkgname); */ int xbps_repository_update_allpkgs(void); +/*@}*/ + +/** @addtogroup transdict */ +/*@{*/ + /** - * Returns the transaction proplib dictionary, as shown above in the image. + * Returns the transaction dictionary, as shown above in the image. + * Before returning the package list is sorted in the correct order + * and total installed/download size for the transaction is computed. + * + * @return The proplib transaction dictionary on success, otherwise NULL + * and errno is set appropiately. ENXIO if the transaction + * dictionary and the missing deps array were not created. ENODEV if + * there are missing dependencies or any other if there was an error + * while sorting packages or computing the transaction size. * * @note - * - If the array \a missing_deps object in the returned transaction - * dictionary is not empty, that means that some required package - * dependencies could not be found; in that case the caller should stop - * immediately the transaction. - * - This function won't return anything useful in the proplib - * dictionary, if either of xbps_repository_install_pkg() or - * xbps_repository_update_pkg() functions are not called previously. - * - * @return The transaction dictionary to install/update/replace - * a package list. NULL on failure and errno is set appropiately. + * - This function will set errno to ENXIO if xbps_repository_install_pkg() + * xbps_repository_update_pkg() functions were not called previously. */ -prop_dictionary_t xbps_repository_get_transaction_dict(void); +prop_dictionary_t xbps_transaction_prepare(void); + +/** + * Returns the missing deps array if xbps_repository_install_pkg() + * or xbps_repository_update_pkg() failed to find required packages + * in registered repositories. + * + * @return The proplib array, NULL if it couldn't created. + */ +prop_array_t xbps_transaction_missingdeps_get(void); /*@}*/ diff --git a/include/xbps_api_impl.h b/include/xbps_api_impl.h index e18bb55f..4f290f52 100644 --- a/include/xbps_api_impl.h +++ b/include/xbps_api_impl.h @@ -128,6 +128,7 @@ int HIDDEN xbps_remove_obsoletes(prop_dictionary_t, prop_dictionary_t); * From lib/repository_finddeps.c */ int HIDDEN xbps_repository_find_pkg_deps(prop_dictionary_t, + prop_array_t, prop_dictionary_t); /** @@ -139,9 +140,15 @@ int HIDDEN xbps_requiredby_pkg_remove(const char *); /** * @private - * From lib/sortdeps.c + * From lib/transaction_sortdeps.c */ -int HIDDEN xbps_sort_pkg_deps(prop_dictionary_t); +int HIDDEN xbps_sort_pkg_deps(void); + +/** + * @private + * From lib/transaction_dictionary.c + */ +prop_dictionary_t HIDDEN xbps_transaction_dictionary_get(void); /** * @private diff --git a/lib/Makefile b/lib/Makefile index 3210b63c..40f0db42 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -39,9 +39,10 @@ endif OBJS = package_configure.o package_config_files.o package_orphans.o OBJS += package_remove.o package_remove_obsoletes.o package_state.o OBJS += package_unpack.o package_requiredby.o package_register.o -OBJS += package_purge.o initend.o +OBJS += package_purge.o initend.o transaction_dictionary.o +OBJS += transaction_sortdeps.o OBJS += cmpver.o download.o fexec.o humanize_number.o plist.o -OBJS += sortdeps.o util.o pkgmatch.o mkpath.o +OBJS += util.o pkgmatch.o mkpath.o OBJS += regpkgdb_dictionary.o repository.o repository_finddeps.o OBJS += repository_findpkg.o repository_plist.o OBJS += repository_pool.o repository_sync_index.o diff --git a/lib/repository_finddeps.c b/lib/repository_finddeps.c index bbb4d5da..54bfe71a 100644 --- a/lib/repository_finddeps.c +++ b/lib/repository_finddeps.c @@ -451,13 +451,15 @@ find_repo_deps(prop_dictionary_t trans_dict, /* transaction dictionary */ int HIDDEN xbps_repository_find_pkg_deps(prop_dictionary_t trans_dict, + prop_array_t mdeps, prop_dictionary_t repo_pkgd) { - prop_array_t pkg_rdeps, missing_rdeps; + prop_array_t pkg_rdeps; const char *pkgname, *pkgver; int rv = 0; assert(trans_dict != NULL); + assert(mdeps != NULL); assert(repo_pkgd != NULL); pkg_rdeps = prop_dictionary_get(repo_pkgd, "run_depends"); @@ -471,9 +473,7 @@ xbps_repository_find_pkg_deps(prop_dictionary_t trans_dict, * This will find direct and indirect deps, if any of them is not * there it will be added into the missing_deps array. */ - missing_rdeps = prop_dictionary_get(trans_dict, "missing_deps"); - rv = find_repo_deps(trans_dict, missing_rdeps, pkgname, pkg_rdeps); - if (rv != 0) { + if ((rv = find_repo_deps(trans_dict, mdeps, pkgname, pkg_rdeps)) != 0) { xbps_dbg_printf("Error '%s' while checking rundeps!\n", strerror(rv)); } diff --git a/lib/repository_findpkg.c b/lib/repository_findpkg.c index 4bec6fe0..0534ffc0 100644 --- a/lib/repository_findpkg.c +++ b/lib/repository_findpkg.c @@ -34,11 +34,11 @@ /** * @file lib/repository_findpkg.c - * @brief Repository transaction handling routines - * @defgroup repo_pkgs Repository transaction handling functions + * @brief Repository package handling routines + * @defgroup repo_pkgs Repository package handling functions * * The following image shows off the full transaction dictionary returned - * by xbps_repository_get_transaction_dict(). + * by xbps_transaction_prepare(). * * @image html images/xbps_transaction_dictionary.png * @@ -53,120 +53,6 @@ * data type is specified on its edge, i.e string, array, integer, dictionary. */ -static prop_dictionary_t trans_dict; -static bool trans_dict_initialized; - -/* - * This creates the transaction dictionary with two arrays, one for - * dependencies not yet sorted and another one for missing dependencies. - * - * Before returning the dictionary to the caller, package dependencies in - * the "unsorted_deps" array will be sorted and moved to another - * array called "packages". If there are no missing dependencies, the - * "missing_deps" array will be removed. - * - */ -static int -create_transaction_dictionary(void) -{ - prop_array_t unsorted, missing; - int rv = 0; - - if (trans_dict_initialized) - return 0; - - trans_dict = prop_dictionary_create(); - if (trans_dict == NULL) - return ENOMEM; - - missing = prop_array_create(); - if (missing == NULL) { - rv = ENOMEM; - goto fail; - } - - unsorted = prop_array_create(); - if (unsorted == NULL) { - rv = ENOMEM; - goto fail2; - } - - if (!xbps_add_obj_to_dict(trans_dict, missing, "missing_deps")) { - rv = EINVAL; - goto fail3; - } - if (!xbps_add_obj_to_dict(trans_dict, unsorted, "unsorted_deps")) { - rv = EINVAL; - goto fail3; - } - - trans_dict_initialized = true; - - return rv; - -fail3: - prop_object_release(unsorted); -fail2: - prop_object_release(missing); -fail: - prop_object_release(trans_dict); - - return rv; -} - -static int -compute_transaction_sizes(void) -{ - prop_object_iterator_t iter; - prop_object_t obj; - uint64_t tsize = 0, dlsize = 0, instsize = 0; - int rv = 0; - const char *tract; - - iter = xbps_get_array_iter_from_dict(trans_dict, "packages"); - if (iter == NULL) - return EINVAL; - - while ((obj = prop_object_iterator_next(iter)) != NULL) { - prop_dictionary_get_cstring_nocopy(obj, "trans-action", &tract); - /* - * Skip pkgs that need to be configured. - */ - if (strcmp(tract, "configure") == 0) - continue; - - prop_dictionary_get_uint64(obj, "filename-size", &tsize); - dlsize += tsize; - tsize = 0; - prop_dictionary_get_uint64(obj, "installed_size", &tsize); - instsize += tsize; - tsize = 0; - } - - /* - * Add object in transaction dictionary with total installed - * size that it will take. - */ - if (!prop_dictionary_set_uint64(trans_dict, - "total-installed-size", instsize)) { - rv = EINVAL; - goto out; - } - /* - * Add object in transaction dictionary with total download - * size that needs to be sucked in. - */ - if (!prop_dictionary_set_uint64(trans_dict, - "total-download-size", dlsize)) { - rv = EINVAL; - goto out; - } -out: - prop_object_iterator_release(iter); - - return rv; -} - static int set_pkg_state(prop_dictionary_t pkgd, const char *pkgname) { @@ -193,46 +79,6 @@ set_pkg_state(prop_dictionary_t pkgd, const char *pkgname) return rv; } -prop_dictionary_t -xbps_repository_get_transaction_dict(void) -{ - int rv = 0; - - if (trans_dict_initialized == false) { - errno = ENXIO; - return NULL; - } - - /* - * Sort package dependencies if necessary. - */ - if ((rv = xbps_sort_pkg_deps(trans_dict)) != 0) { - errno = rv; - /* - * If there are missing deps (ENOENT) - * return the dictionary, the client should always - * check if that's the case. - */ - return trans_dict; - } - - /* - * Add total transaction installed/download sizes - * to the transaction dictionary. - */ - if ((rv = compute_transaction_sizes()) != 0) { - errno = rv; - return NULL; - } - - /* - * Remove the "missing_deps" array now that it's not needed. - */ - prop_dictionary_remove(trans_dict, "missing_deps"); - - return trans_dict; -} - int xbps_repository_update_allpkgs(void) { @@ -288,8 +134,8 @@ out: int xbps_repository_update_pkg(const char *pkgname) { - prop_array_t unsorted; - prop_dictionary_t pkg_repod; + prop_array_t unsorted, mdeps; + prop_dictionary_t transd, pkg_repod; int rv = 0; assert(pkgname != NULL); @@ -314,16 +160,18 @@ xbps_repository_update_pkg(const char *pkgname) errno = 0; goto out; } - /* - * Create the transaction dictionary. - */ - if ((rv = create_transaction_dictionary()) != 0) + if ((transd = xbps_transaction_dictionary_get()) == NULL) { + rv = EINVAL; goto out; - + } + if ((mdeps = xbps_transaction_missingdeps_get()) == NULL) { + rv = EINVAL; + goto out; + } /* * Construct the dependency chain for this package. */ - rv = xbps_repository_find_pkg_deps(trans_dict, pkg_repod); + rv = xbps_repository_find_pkg_deps(transd, mdeps, pkg_repod); if (rv != 0) goto out; @@ -331,7 +179,7 @@ xbps_repository_update_pkg(const char *pkgname) * Add required package dictionary into the packages * dictionary. */ - unsorted = prop_dictionary_get(trans_dict, "unsorted_deps"); + unsorted = prop_dictionary_get(transd, "unsorted_deps"); if (unsorted == NULL) { rv = errno; goto out; @@ -373,7 +221,8 @@ int xbps_repository_install_pkg(const char *pkg) { prop_dictionary_t pkg_repod = NULL, origin_pkgrd = NULL; - prop_array_t unsorted; + prop_dictionary_t transd; + prop_array_t mdeps, unsorted; const char *pkgname; int rv = 0; @@ -392,10 +241,16 @@ xbps_repository_install_pkg(const char *pkg) goto out; } /* - * Create the transaction dictionary. + * Prepare transaction dictionary and missing deps array. */ - if ((rv = create_transaction_dictionary()) != 0) + if ((transd = xbps_transaction_dictionary_get()) == NULL) { + rv = EINVAL; goto out; + } + if ((mdeps = xbps_transaction_missingdeps_get()) == NULL) { + rv = EINVAL; + goto out; + } origin_pkgrd = prop_dictionary_copy(pkg_repod); prop_dictionary_get_cstring_nocopy(pkg_repod, "pkgname", &pkgname); @@ -403,8 +258,7 @@ xbps_repository_install_pkg(const char *pkg) * Check that this pkg hasn't been added previously into * the transaction. */ - if (xbps_find_pkg_in_dict_by_pattern(trans_dict, - "unsorted_deps", pkg)) { + if (xbps_find_pkg_in_dict_by_pattern(transd, "unsorted_pkgs", pkg)) { xbps_dbg_printf("package '%s' already queued in transaction\n", pkg); goto out; @@ -413,8 +267,8 @@ xbps_repository_install_pkg(const char *pkg) * Prepare required package dependencies and add them into the * "unsorted" array in transaction dictionary. */ - rv = xbps_repository_find_pkg_deps(trans_dict, origin_pkgrd); - if (rv != 0) + if ((rv = xbps_repository_find_pkg_deps(transd, mdeps, + origin_pkgrd)) != 0) goto out; if ((rv = set_pkg_state(origin_pkgrd, pkgname)) != 0) @@ -433,7 +287,7 @@ xbps_repository_install_pkg(const char *pkg) * Add required package dictionary into the unsorted array and * set package state as not yet installed. */ - unsorted = prop_dictionary_get(trans_dict, "unsorted_deps"); + unsorted = prop_dictionary_get(transd, "unsorted_deps"); if (unsorted == NULL) { rv = EINVAL; goto out; diff --git a/lib/transaction_dictionary.c b/lib/transaction_dictionary.c new file mode 100644 index 00000000..03abbb61 --- /dev/null +++ b/lib/transaction_dictionary.c @@ -0,0 +1,216 @@ +/*- + * Copyright (c) 2009-2011 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 + +#include +#include "xbps_api_impl.h" + +/** + * @file lib/transaction_dictionary.c + * @brief Transaction handling routines + * @defgroup transdict Transaction handling functions + * + * The following image shows off the full transaction dictionary returned + * by xbps_transaction_prepare(). + * + * @image html images/xbps_transaction_dictionary.png + * + * Legend: + * - Salmon bg box: The transaction dictionary. + * - White bg box: mandatory objects. + * - Grey bg box: optional objects. + * - Green bg box: possible value set in the object, only one of them + * will be set. + * + * Text inside of white boxes are the key associated with the object, its + * data type is specified on its edge, i.e string, array, integer, dictionary. + */ + +static prop_dictionary_t transd; +static prop_array_t trans_mdeps; +static bool transd_initialized; +static bool trans_mdeps_initialized; + +static int +create_transaction_dictionary(void) +{ + prop_array_t unsorted; + + if (transd_initialized) + return 0; + + transd = prop_dictionary_create(); + if (transd == NULL) + return ENOMEM; + + unsorted = prop_array_create(); + if (unsorted == NULL) { + prop_object_release(transd); + return ENOMEM; + } + + if (!xbps_add_obj_to_dict(transd, unsorted, "unsorted_deps")) { + prop_object_release(unsorted); + prop_object_release(transd); + return EINVAL; + } + + transd_initialized = true; + return 0; +} + +static int +create_transaction_missingdeps(void) +{ + if (trans_mdeps_initialized) + return 0; + + trans_mdeps = prop_array_create(); + if (trans_mdeps == NULL) + return ENOMEM; + + trans_mdeps_initialized = true; + return 0; +} + +static int +compute_transaction_sizes(void) +{ + prop_object_iterator_t iter; + prop_object_t obj; + uint64_t tsize = 0, dlsize = 0, instsize = 0; + int rv = 0; + const char *tract; + + iter = xbps_get_array_iter_from_dict(transd, "packages"); + if (iter == NULL) + return EINVAL; + + while ((obj = prop_object_iterator_next(iter)) != NULL) { + prop_dictionary_get_cstring_nocopy(obj, "trans-action", &tract); + /* + * Skip pkgs that need to be configured. + */ + if (strcmp(tract, "configure") == 0) + continue; + + prop_dictionary_get_uint64(obj, "filename-size", &tsize); + dlsize += tsize; + tsize = 0; + prop_dictionary_get_uint64(obj, "installed_size", &tsize); + instsize += tsize; + tsize = 0; + } + + /* + * Add object in transaction dictionary with total installed + * size that it will take. + */ + if (!prop_dictionary_set_uint64(transd, + "total-installed-size", instsize)) { + rv = EINVAL; + goto out; + } + /* + * Add object in transaction dictionary with total download + * size that needs to be sucked in. + */ + if (!prop_dictionary_set_uint64(transd, + "total-download-size", dlsize)) { + rv = EINVAL; + goto out; + } +out: + prop_object_iterator_release(iter); + + return rv; +} + +prop_dictionary_t HIDDEN +xbps_transaction_dictionary_get(void) +{ + if (create_transaction_dictionary() != 0) + return NULL; + + return transd; +} + +prop_array_t +xbps_transaction_missingdeps_get(void) +{ + if (create_transaction_missingdeps() != 0) + return NULL; + + return trans_mdeps; +} + +prop_dictionary_t +xbps_transaction_prepare(void) +{ + int rv = 0; + + if (!transd_initialized && !trans_mdeps_initialized) { + errno = ENXIO; + return NULL; + } + /* + * If there are missing deps bail out. + */ + if (prop_array_count(trans_mdeps) > 0) { + prop_object_release(transd); + errno = ENODEV; + return NULL; + } + /* + * Sort package dependencies if necessary. + */ + if ((rv = xbps_sort_pkg_deps()) != 0) { + errno = rv; + prop_object_release(transd); + prop_object_release(trans_mdeps); + return NULL; + } + /* + * Add total transaction installed/download sizes + * to the transaction dictionary. + */ + if ((rv = compute_transaction_sizes()) != 0) { + errno = rv; + prop_object_release(transd); + prop_object_release(trans_mdeps); + return NULL; + } + /* + * The missing deps array is not necessary anymore. + */ + prop_object_release(trans_mdeps); + + return prop_dictionary_copy(transd); +} diff --git a/lib/sortdeps.c b/lib/transaction_sortdeps.c similarity index 94% rename from lib/sortdeps.c rename to lib/transaction_sortdeps.c index 8404d213..a8962b7c 100644 --- a/lib/sortdeps.c +++ b/lib/transaction_sortdeps.c @@ -46,9 +46,10 @@ * it was in the "unsorted_deps" array. */ int HIDDEN -xbps_sort_pkg_deps(prop_dictionary_t transd) +xbps_sort_pkg_deps(void) { - prop_array_t sorted, unsorted, rundeps, missingdeps; + prop_dictionary_t transd; + prop_array_t sorted, unsorted, rundeps; prop_object_t obj, obj2; prop_object_iterator_t iter, iter2; size_t ndeps = 0, rundepscnt = 0, cnt = 0; @@ -56,21 +57,12 @@ xbps_sort_pkg_deps(prop_dictionary_t transd) char *pkgnamedep; int rv = 0; - assert(transd != NULL); + if ((transd = xbps_transaction_dictionary_get()) == NULL) + return EINVAL; - /* - * If there are missing dependencies, bail out. - */ - missingdeps = prop_dictionary_get(transd, "missing_deps"); - if (prop_array_count(missingdeps) > 0) { - xbps_dbg_printf("missing dependencies! won't " - "continue sorting\n"); - return ENOENT; - } sorted = prop_array_create(); if (sorted == NULL) return ENOMEM; - /* * Add sorted packages array into transaction dictionary (empty). */