Introduce xbps_transaction_remove_pkg() and use it for xbps-bin(8).

This commit is contained in:
Juan RP 2011-11-27 09:05:18 +01:00
parent dcac4ec153
commit 9d731ffe09
8 changed files with 226 additions and 208 deletions

View File

@ -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

View File

@ -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);

View File

@ -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;
const char *rootdir, *cachedir, *confdir, *option, *pkgver;
size_t x;
int i, c, flags, rv;
bool yes, purge, debug, force_rm_with_deps, recursive_rm;
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. */

View File

@ -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 <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <xbps_api.h>
#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;
}

View File

@ -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);
prop_dictionary_get_uint64(trans->d, "total-installed-size",
&instsize);
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("\nTotal download size:\t%6s\n", size);
printf("Total download size:\t%6s\n", size);
}
prop_dictionary_get_uint64(trans->d, "total-installed-size",
&instsize);
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);
}
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);
}
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)
{

View File

@ -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.

View File

@ -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);
/*
* 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;
tsize = 0;
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);

View File

@ -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)
{