From 9d731ffe092df51dba684ece50d0f83933abccbd Mon Sep 17 00:00:00 2001 From: Juan RP Date: Sun, 27 Nov 2011 09:05:18 +0100 Subject: [PATCH] Introduce xbps_transaction_remove_pkg() and use it for xbps-bin(8). --- bin/xbps-bin/Makefile | 2 +- bin/xbps-bin/defs.h | 1 + bin/xbps-bin/main.c | 45 +++++++-- bin/xbps-bin/remove.c | 174 ----------------------------------- bin/xbps-bin/transaction.c | 60 +++++++++--- include/xbps_api.h | 19 +++- lib/transaction_dictionary.c | 49 +++++++--- lib/transaction_ops.c | 84 +++++++++++++++++ 8 files changed, 226 insertions(+), 208 deletions(-) delete mode 100644 bin/xbps-bin/remove.c diff --git a/bin/xbps-bin/Makefile b/bin/xbps-bin/Makefile index da4f4f48..749ba00f 100644 --- a/bin/xbps-bin/Makefile +++ b/bin/xbps-bin/Makefile @@ -2,7 +2,7 @@ TOPDIR = ../.. -include $(TOPDIR)/config.mk BIN = xbps-bin -OBJS = transaction.o main.o remove.o show-deps.o +OBJS = transaction.o main.o show-deps.o OBJS += show-info-files.o util.o find-files.o OBJS += question.o fetch_cb.o state_cb.o OBJS += check.o check_pkg_automatic.o check_pkg_files.o diff --git a/bin/xbps-bin/defs.h b/bin/xbps-bin/defs.h index b94f2e6e..6bde053d 100644 --- a/bin/xbps-bin/defs.h +++ b/bin/xbps-bin/defs.h @@ -46,6 +46,7 @@ struct list_pkgver_cb { /* from transaction.c */ int install_new_pkg(const char *); int update_pkg(const char *); +int remove_pkg(const char *, bool, bool); int autoupdate_pkgs(bool, bool); int autoremove_pkgs(bool, bool); int exec_transaction(bool, bool); diff --git a/bin/xbps-bin/main.c b/bin/xbps-bin/main.c index 96901d3c..887ccb8e 100644 --- a/bin/xbps-bin/main.c +++ b/bin/xbps-bin/main.c @@ -62,18 +62,22 @@ cleanup(int signum) int main(int argc, char **argv) { + prop_dictionary_t pkgd; + prop_array_t reqby; struct xbps_handle *xhp; struct xferstat xfer; struct list_pkgver_cb lpc; struct sigaction sa; - const char *rootdir, *cachedir, *confdir, *option; - int i , c, flags, rv; - bool yes, purge, debug, force_rm_with_deps, recursive_rm; + const char *rootdir, *cachedir, *confdir, *option, *pkgver; + size_t x; + int i, c, flags, rv; + bool yes, purge, debug, reqby_force, force_rm_with_deps, recursive_rm; bool install_auto, install_manual, show_download_pkglist_url; rootdir = cachedir = confdir = option = NULL; flags = rv = 0; - yes = purge = force_rm_with_deps = recursive_rm = debug = false; + reqby_force = yes = purge = force_rm_with_deps = false; + recursive_rm = debug = false; install_auto = install_manual = show_download_pkglist_url = false; while ((c = getopt(argc, argv, "AC:c:dDFfMo:pRr:Vvy")) != -1) { @@ -247,12 +251,39 @@ main(int argc, char **argv) rv = exec_transaction(yes, show_download_pkglist_url); } else if (strcasecmp(argv[0], "remove") == 0) { - /* Removes a binary package. */ + /* Removes a package. */ if (argc < 2) usage(xhp); - rv = remove_installed_pkgs(argc, argv, yes, purge, - force_rm_with_deps, recursive_rm); + for (i = 1; i < argc; i++) { + rv = remove_pkg(argv[i], purge, recursive_rm); + if (rv == 0) + continue; + else if (rv != EEXIST) + goto out; + + /* pkg has revdeps */ + pkgd = xbps_find_pkg_dict_installed(argv[i], false); + prop_dictionary_get_cstring_nocopy(pkgd, + "pkgver", &pkgver); + reqby = prop_dictionary_get(pkgd, "requiredby"); + prop_object_release(pkgd); + printf("WARNING: %s IS REQUIRED BY %u PACKAGE%s:\n\n", + pkgver, prop_array_count(reqby), + prop_array_count(reqby) > 1 ? "S" : ""); + for (x = 0; x < prop_array_count(reqby); x++) { + prop_array_get_cstring_nocopy(reqby, x, &pkgver); + print_package_line(pkgver, false); + } + printf("\n\n"); + print_package_line(NULL, true); + reqby_force = true; + } + if (reqby_force && !force_rm_with_deps) { + rv = EINVAL; + goto out; + } + rv = exec_transaction(yes, false); } else if (strcasecmp(argv[0], "show") == 0) { /* Shows info about an installed binary package. */ diff --git a/bin/xbps-bin/remove.c b/bin/xbps-bin/remove.c deleted file mode 100644 index 0727000f..00000000 --- a/bin/xbps-bin/remove.c +++ /dev/null @@ -1,174 +0,0 @@ -/*- - * Copyright (c) 2008-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 "defs.h" -#include "../xbps-repo/defs.h" - -static int -pkg_remove_and_purge(const char *pkgname, const char *version, bool purge) -{ - int rv = 0; - - if ((rv = xbps_remove_pkg(pkgname, version, false)) != 0) - return rv; - - if (purge) - if ((rv = xbps_purge_pkg(pkgname, false)) != 0) - return rv; - - return rv; -} - -int -remove_installed_pkgs(int argc, char **argv, bool yes, bool purge, - bool force_rm_with_deps, bool recursive_rm) -{ - prop_array_t sorted, unsorted, orphans, reqby, orphans_user = NULL; - prop_dictionary_t dict; - size_t x; - const char *version, *pkgver, *pkgname; - int i, rv = 0; - bool found = false, reqby_force = false; - - unsorted = prop_array_create(); - if (unsorted == NULL) - return -1; - - sorted = prop_array_create(); - if (sorted == NULL) - return -1; - /* - * If recursively removing packages, find out which packages - * would be orphans if the supplied packages were already removed. - */ - if (recursive_rm) { - orphans_user = prop_array_create(); - if (orphans_user == NULL) { - xbps_error_printf("NULL orphans_user array\n"); - return ENOMEM; - } - for (x = 0, i = 1; i < argc; i++, x++) - prop_array_set_cstring_nocopy(orphans_user, x, argv[i]); - - orphans = xbps_find_pkg_orphans(orphans_user); - prop_object_release(orphans_user); - if (orphans == NULL) { - xbps_error_printf("NULL orphans array\n"); - return EINVAL; - } - for (x = 0; x < prop_array_count(orphans); x++) - prop_array_add(unsorted, prop_array_get(orphans, x)); - - prop_object_release(orphans); - } - /* - * First check if package is required by other packages. - */ - for (i = 1; i < argc; i++) { - dict = xbps_find_pkg_dict_installed(argv[i], false); - if (dict == NULL) { - printf("Package %s is not installed.\n", argv[i]); - continue; - } - /* - * Check that current package is not required by - * other installed packages. - */ - prop_array_add(sorted, dict); - found = true; - prop_dictionary_get_cstring_nocopy(dict, "pkgver", &pkgver); - reqby = prop_dictionary_get(dict, "requiredby"); - if (reqby == NULL || prop_array_count(reqby) == 0) { - prop_object_release(dict); - continue; - } - - printf("WARNING: %s IS REQUIRED BY %u PACKAGE%s:\n\n", - pkgver, prop_array_count(reqby), - prop_array_count(reqby) > 1 ? "S" : ""); - for (x = 0; x < prop_array_count(reqby); x++) { - prop_array_get_cstring_nocopy(reqby, x, &pkgver); - print_package_line(pkgver, false); - } - printf("\n\n"); - print_package_line(NULL, true); - reqby_force = true; - prop_object_release(dict); - } - if (!found) { - prop_object_release(unsorted); - return 0; - } - if (reqby_force && !force_rm_with_deps) { - prop_object_release(unsorted); - prop_object_release(sorted); - return EINVAL; - } - for (x = 0; x < prop_array_count(unsorted); x++) { - dict = prop_array_get(unsorted, x); - prop_array_add(sorted, dict); - } - prop_object_release(unsorted); - /* - * Show the list of going-to-be removed packages. - */ - printf("%u package%s will be removed%s:\n", - prop_array_count(sorted), - prop_array_count(sorted) == 1 ? "" : "s", - purge ? " and purged" : ""); - - for (x = 0; x < prop_array_count(sorted); x++) { - dict = prop_array_get(sorted, x); - prop_dictionary_get_cstring_nocopy(dict, "pkgver", &pkgver); - print_package_line(pkgver, false); - } - printf("\n\n"); - - if (!yes && !noyes("Do you want to continue?")) { - printf("Cancelling!\n"); - prop_object_release(sorted); - return 0; - } - - for (x = 0; x < prop_array_count(sorted); x++) { - dict = prop_array_get(sorted, x); - prop_dictionary_get_cstring_nocopy(dict, "pkgname", &pkgname); - prop_dictionary_get_cstring_nocopy(dict, "version", &version); - if ((rv = pkg_remove_and_purge(pkgname, version, purge)) != 0) { - prop_object_release(sorted); - return rv; - } - } - prop_object_release(sorted); - - return 0; -} diff --git a/bin/xbps-bin/transaction.c b/bin/xbps-bin/transaction.c index 80ca7e20..fc467b5e 100644 --- a/bin/xbps-bin/transaction.c +++ b/bin/xbps-bin/transaction.c @@ -121,7 +121,7 @@ show_package_list(prop_object_iterator_t iter, const char *match) static int show_transaction_sizes(struct transaction *trans) { - uint64_t dlsize = 0, instsize = 0; + uint64_t dlsize = 0, instsize = 0, rmsize = 0; char size[8]; /* @@ -155,26 +155,38 @@ show_transaction_sizes(struct transaction *trans) show_package_list(trans->iter, "remove"); printf("\n"); } - /* - * Show total download/installed size for all required packages. + * Show total download/installed/removed size for all required packages. */ + printf("\n"); prop_dictionary_get_uint64(trans->d, "total-download-size", &dlsize); + if (dlsize > 0) { + if (xbps_humanize_number(size, (int64_t)dlsize) == -1) { + xbps_error_printf("xbps-bin: error: humanize_number returns " + "%s\n", strerror(errno)); + return -1; + } + printf("Total download size:\t%6s\n", size); + } prop_dictionary_get_uint64(trans->d, "total-installed-size", &instsize); - if (xbps_humanize_number(size, (int64_t)dlsize) == -1) { - xbps_error_printf("xbps-bin: error: humanize_number returns " - "%s\n", strerror(errno)); - return -1; + if (instsize > 0) { + if (xbps_humanize_number(size, (int64_t)instsize) == -1) { + xbps_error_printf("xbps-bin: error: humanize_number2 returns " + "%s\n", strerror(errno)); + return -1; + } + printf("Total installed size:\t%6s\n\n", size); } - printf("\nTotal download size:\t%6s\n", size); - if (xbps_humanize_number(size, (int64_t)instsize) == -1) { - xbps_error_printf("xbps-bin: error: humanize_number2 returns " - "%s\n", strerror(errno)); - return -1; + prop_dictionary_get_uint64(trans->d, "total-removed-size", &rmsize); + if (rmsize > 0) { + if (xbps_humanize_number(size, (int64_t)rmsize) == -1) { + xbps_error_printf("xbps-bin: error: humanize_number3 returns " + "%s\n", strerror(errno)); + return -1; + } + printf("Total removed size:\t%6s\n\n", size); } - printf("Total installed size:\t%6s\n\n", size); - return 0; } @@ -309,6 +321,26 @@ update_pkg(const char *pkgname) return rv; } +int +remove_pkg(const char *pkgname, bool purge, bool recursive) +{ + int rv; + + rv = xbps_transaction_remove_pkg(pkgname, purge, recursive); + if (rv == EEXIST) + return rv; + else if (rv == ENOENT) { + printf("Package `%s' is not currently installed.\n", pkgname); + return 0; + } else { + xbps_error_printf("Failed to queue `%s' for removing: %s\n", + pkgname, strerror(rv)); + return rv; + } + + return 0; +} + int exec_transaction(bool yes, bool show_download_urls) { diff --git a/include/xbps_api.h b/include/xbps_api.h index f634e962..13b65128 100644 --- a/include/xbps_api.h +++ b/include/xbps_api.h @@ -55,7 +55,7 @@ */ #define XBPS_PKGINDEX_VERSION "1.3" -#define XBPS_API_VERSION "20111125-2" +#define XBPS_API_VERSION "20111127" #define XBPS_VERSION "0.11.0" /** @@ -1176,6 +1176,23 @@ int xbps_transaction_update_pkg(const char *pkgname); */ int xbps_transaction_update_packages(void); +/** + * Removes a package currently installed. The package dictionary will + * be added into the transaction dictionary. + * + * @param[in] pkgname Package name to be removed. + * @param[in] purge If true package will also be purged. + * @param[in] recursive If true, all packages that are currently depending + * on the package to be removed, and if they are orphans, will be added. + * + * @return 0 on success, ENOENT if pkg is not installed, EEXIST if package + * has reverse dependencies, EINVAL or ENXIO if a problem ocurred in the + * process. + */ +int xbps_transaction_remove_pkg(const char *pkgname, + bool purge, + bool recursive); + /** * Finds all package orphans currently installed and adds them into * the transaction dictionary. diff --git a/lib/transaction_dictionary.c b/lib/transaction_dictionary.c index ba471729..2480326d 100644 --- a/lib/transaction_dictionary.c +++ b/lib/transaction_dictionary.c @@ -102,15 +102,16 @@ create_transaction_missingdeps(void) static int compute_transaction_stats(void) { + prop_dictionary_t pkg_metad; prop_object_iterator_t iter; prop_object_t obj; - uint64_t tsize, dlsize, instsize; + uint64_t tsize, dlsize, instsize, rmsize; uint32_t inst_pkgcnt, up_pkgcnt, cf_pkgcnt, rm_pkgcnt; int rv = 0; - const char *tract; + const char *tract, *pkgname; inst_pkgcnt = up_pkgcnt = cf_pkgcnt = rm_pkgcnt = 0; - tsize = dlsize = instsize = 0; + tsize = dlsize = instsize = rmsize = 0; iter = xbps_array_iter_from_dict(transd, "packages"); if (iter == NULL) @@ -160,22 +161,39 @@ compute_transaction_stats(void) prop_object_iterator_reset(iter); while ((obj = prop_object_iterator_next(iter)) != NULL) { + prop_dictionary_get_cstring_nocopy(obj, "pkgname", &pkgname); prop_dictionary_get_cstring_nocopy(obj, "transaction", &tract); /* * Only process pkgs to be installed or updated. */ - if ((strcmp(tract, "configure") == 0) || - (strcmp(tract, "remove") == 0)) + 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; + /* + * If removing a package, get installed_size from + * pkg's metadata dictionary. + */ + if (strcmp(tract, "remove") == 0) { + pkg_metad = + xbps_dictionary_from_metadata_plist(pkgname, + XBPS_PKGPROPS); + prop_dictionary_get_uint64(pkg_metad, + "installed_size", &tsize); + prop_object_release(pkg_metad); + rmsize += tsize; + } else { + prop_dictionary_get_uint64(obj, + "installed_size", &tsize); + instsize += tsize; + prop_dictionary_get_uint64(obj, + "filename-size", &tsize); + dlsize += tsize; + } } - + /* installed - removed */ + if (rmsize > 0 && instsize > 0) + instsize -= rmsize; /* * Add object in transaction dictionary with total installed * size that it will take. @@ -194,6 +212,15 @@ compute_transaction_stats(void) rv = EINVAL; goto out; } + /* + * Add object in transaction dictionary with total size to be + * freed from packages to be removed. + */ + if (!prop_dictionary_set_uint64(transd, + "total-removed-size", rmsize)) { + rv = EINVAL; + goto out; + } out: prop_object_iterator_release(iter); diff --git a/lib/transaction_ops.c b/lib/transaction_ops.c index ae534e37..10da9dc7 100644 --- a/lib/transaction_ops.c +++ b/lib/transaction_ops.c @@ -237,6 +237,90 @@ xbps_transaction_install_pkg(const char *pkgpattern) return transaction_find_pkg(pkgpattern, "install"); } +int +xbps_transaction_remove_pkg(const char *pkgname, bool purge, bool recursive) +{ + prop_dictionary_t transd, pkgd; + prop_array_t mdeps, orphans, orphans_pkg, unsorted, reqby; + prop_object_t obj; + const char *pkgver; + size_t count; + int rv = 0; + + assert(pkgname != NULL); + + pkgd = xbps_find_pkg_dict_installed(pkgname, false); + if (prop_object_type(pkgd) != PROP_TYPE_DICTIONARY) { + /* pkg not installed */ + rv = ENOENT; + goto out; + } + /* + * Prepare transaction dictionary and missing deps array. + */ + if ((transd = xbps_transaction_dictionary_get()) == NULL) { + rv = ENXIO; + goto out; + } + if ((mdeps = xbps_transaction_missingdeps_get()) == NULL) { + rv = ENXIO; + goto out; + } + unsorted = prop_dictionary_get(transd, "unsorted_deps"); + if (!recursive) + goto rmpkg; + /* + * If recursive is set, find out which packages would be orphans + * if the supplied package were already removed. + */ + orphans_pkg = prop_array_create(); + if (orphans_pkg == NULL) { + rv = ENOMEM; + goto out; + } + prop_array_set_cstring_nocopy(orphans_pkg, 0, pkgname); + orphans = xbps_find_pkg_orphans(orphans_pkg); + prop_object_release(orphans_pkg); + if (prop_object_type(orphans) != PROP_TYPE_ARRAY) { + rv = EINVAL; + goto out; + } + count = prop_array_count(orphans); + while (count--) { + obj = prop_array_get(orphans, count); + prop_dictionary_get_cstring_nocopy(obj, "pkgver", &pkgver); + prop_dictionary_set_cstring_nocopy(obj, "transaction", "remove"); + if (purge) + prop_dictionary_set_bool(obj, "remove-and-purge", true); + prop_array_add(unsorted, obj); + xbps_dbg_printf("%s: added into transaction (remove).\n", pkgver); + } + prop_object_release(orphans); +rmpkg: + /* + * Add pkg dictionary into the unsorted_deps array. + */ + prop_dictionary_get_cstring_nocopy(pkgd, "pkgver", &pkgver); + prop_dictionary_set_cstring_nocopy(pkgd, "transaction", "remove"); + if (purge) + prop_dictionary_set_bool(pkgd, "remove-and-purge", true); + prop_array_add(unsorted, pkgd); + xbps_dbg_printf("%s: added into transaction (remove).\n", pkgver); + reqby = prop_dictionary_get(pkgd, "requiredby"); + /* + * If target pkg is required by any installed pkg, the client must be aware + * of this to take appropiate action. + */ + if ((prop_object_type(reqby) == PROP_TYPE_ARRAY) && + (prop_array_count(reqby) > 0)) + rv = EEXIST; +out: + if (prop_object_type(pkgd) == PROP_TYPE_DICTIONARY) + prop_object_release(pkgd); + + return rv; +} + int xbps_transaction_autoremove_pkgs(bool purge) {