From 7da33469cc0cc613f7fedd4ec99042e2d89bce01 Mon Sep 17 00:00:00 2001 From: Juan RP Date: Sun, 30 Jan 2011 08:08:34 +0100 Subject: [PATCH] xbps-bin(8): added -R option to recursively remove pkgs that were instaled automatically. --- NEWS | 4 +++ bin/xbps-bin/defs.h | 2 +- bin/xbps-bin/main.c | 13 +++++--- bin/xbps-bin/remove.c | 52 +++++++++++++++++++++++------ bin/xbps-bin/xbps-bin.8 | 30 ++++++++++++----- include/xbps_api.h | 8 +++-- lib/package_orphans.c | 72 +++++++++++++++++++++++++++++++++-------- 7 files changed, 141 insertions(+), 40 deletions(-) diff --git a/NEWS b/NEWS index 469ebcf8..eb91ae0c 100644 --- a/NEWS +++ b/NEWS @@ -1,5 +1,9 @@ xbps-0.8.0 (???): + * xbps-bin(8): added -R option for the "remove" target, to recursively + remove packages that were installed automatically by the package(s) + that we want to remove, and no other package currently depends on. + * xbps-bin(8): added -D option to only show the URLs to download the binary packages required by the "install", "update" and "autoupdate" targets. diff --git a/bin/xbps-bin/defs.h b/bin/xbps-bin/defs.h index 4a5a820d..c6cd174b 100644 --- a/bin/xbps-bin/defs.h +++ b/bin/xbps-bin/defs.h @@ -37,7 +37,7 @@ int xbps_update_pkg(const char *); int xbps_autoupdate_pkgs(bool, bool); int xbps_autoremove_pkgs(bool, bool); int xbps_exec_transaction(bool, bool); -int xbps_remove_installed_pkgs(int, char **, bool, bool, bool); +int xbps_remove_installed_pkgs(int, char **, bool, bool, bool, bool); int xbps_check_pkg_integrity(const char *); int xbps_check_pkg_integrity_all(void); int xbps_show_pkg_deps(const char *); diff --git a/bin/xbps-bin/main.c b/bin/xbps-bin/main.c index a84009a4..531cbc4e 100644 --- a/bin/xbps-bin/main.c +++ b/bin/xbps-bin/main.c @@ -121,7 +121,7 @@ show_orphans(void) prop_object_t obj; const char *pkgver; - orphans = xbps_find_pkg_orphans(); + orphans = xbps_find_pkg_orphans(NULL); if (orphans == NULL) return EINVAL; @@ -155,13 +155,13 @@ main(int argc, char **argv) struct list_pkgver_cb lpc; struct sigaction sa; int i , c, flags, rv; - bool yes, purge, with_debug, force_rm_with_deps; + bool yes, purge, with_debug, force_rm_with_deps, recursive_rm; bool show_download_pkglist_url = false; i = c = flags = rv = 0; - yes = purge = force_rm_with_deps = with_debug = false; + yes = purge = force_rm_with_deps = recursive_rm = with_debug = false; - while ((c = getopt(argc, argv, "VcdDFfpr:vy")) != -1) { + while ((c = getopt(argc, argv, "VcdDFfpRr:vy")) != -1) { switch (c) { case 'c': xbps_set_cachedir(optarg); @@ -181,6 +181,9 @@ main(int argc, char **argv) case 'p': purge = true; break; + case 'R': + recursive_rm = true; + break; case 'r': /* To specify the root directory */ xbps_set_rootdir(optarg); @@ -304,7 +307,7 @@ main(int argc, char **argv) usage(); rv = xbps_remove_installed_pkgs(argc, argv, yes, purge, - force_rm_with_deps); + force_rm_with_deps, recursive_rm); } 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 index a43db1e1..d2a4ff8a 100644 --- a/bin/xbps-bin/remove.c +++ b/bin/xbps-bin/remove.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2008-2010 Juan Romero Pardines. + * Copyright (c) 2008-2011 Juan Romero Pardines. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -74,7 +74,7 @@ xbps_autoremove_pkgs(bool yes, bool purge) * as dependency and any installed package does not depend * on it currently. */ - orphans = xbps_find_pkg_orphans(); + orphans = xbps_find_pkg_orphans(NULL); if (orphans == NULL) return errno; @@ -120,11 +120,14 @@ out: } int -xbps_remove_installed_pkgs(int argc, char **argv, bool yes, bool purge, - bool force_rm_with_deps) +xbps_remove_installed_pkgs(int argc, + char **argv, + bool yes, + bool purge, + bool force_rm_with_deps, + bool recursive_rm) { - prop_array_t sorted_pkgs; - prop_array_t reqby; + prop_array_t sorted_pkgs, orphans, reqby, orphans_user = NULL; prop_dictionary_t dict; size_t x; const char *version, *pkgver, *pkgname; @@ -135,6 +138,32 @@ xbps_remove_installed_pkgs(int argc, char **argv, bool yes, bool purge, if (sorted_pkgs == NULL) return -1; + /* + * If recursively removing packages, find out which packages + * would be orphans if the supplied package names were 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; + } + /* in reverse order */ + x = prop_array_count(orphans); + while (x--) + prop_array_add(sorted_pkgs, prop_array_get(orphans, x)); + + prop_object_release(orphans); + } /* * First check if package is required by other packages. */ @@ -144,13 +173,18 @@ xbps_remove_installed_pkgs(int argc, char **argv, bool yes, bool purge, 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_pkgs, dict); prop_dictionary_get_cstring_nocopy(dict, "pkgver", &pkgver); found = true; reqby = prop_dictionary_get(dict, "requiredby"); if (reqby != NULL && prop_array_count(reqby) > 0) { - xbps_warn_printf("%s IS REQUIRED BY %u PACKAGES!\n", - pkgver, prop_array_count(reqby)); + xbps_printf("WARNING: %s IS REQUIRED BY %u " + "PACKAGE%s!\n", pkgver, prop_array_count(reqby), + prop_array_count(reqby) > 1 ? "S" : ""); reqby_force = true; } prop_object_release(dict); @@ -159,8 +193,6 @@ xbps_remove_installed_pkgs(int argc, char **argv, bool yes, bool purge, prop_object_release(sorted_pkgs); return 0; } - - /* * Show the list of going-to-be removed packages. */ diff --git a/bin/xbps-bin/xbps-bin.8 b/bin/xbps-bin/xbps-bin.8 index a4e7383b..13e12619 100644 --- a/bin/xbps-bin/xbps-bin.8 +++ b/bin/xbps-bin/xbps-bin.8 @@ -1,4 +1,4 @@ -.TH "XBPS\-BIN" "8" "27/01/2011" "\ \&" "\ \&" +.TH "XBPS\-BIN" "8" "30/01/2011" "\ \&" "\ \&" .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- @@ -77,6 +77,14 @@ and targets, if enabled after removing a package it is also purged\&. .RE .PP +\fB\-R\fR +.RS 4 +Used currently in the +\fIremove\fR +target, to recursively remove packages that aren\(cqt required by other installed +packages and that were installed by the package that we want to remove\&. +.RE +.PP \fB\-r\fR \fIrootdir\fR .RS 4 Sets the @@ -222,7 +230,7 @@ state, it must be \fBpurged\fR with the \fBpurge\fR -command\&. If +command or alternatively use the \fI\-p\fR flag \&. If \fB\-f\fR option is used, package files will be removed even if its SHA256 hash doesn\(cqt match\&. .RE @@ -329,35 +337,41 @@ directory for downloaded binary packages\&. .RE .SH "EXAMPLES" .PP -\fBInstall a package by specifying its name:\fR +Install a package by specifying its name: .RS 4 $ xbps\-bin install foo .RE .PP -\fBInstall a package by specifying a package pattern:\fR +Install a package by specifying a package pattern: .RS 4 $ xbps\-bin install "\fBfoo>=3\&.0\fR" .RE .PP -\fBInstall multiple packages by specifying names and package patterns:\fR +Install multiple packages by specifying names and package patterns: .RS 4 $ xbps\-bin install foo "\fBblah⇐4\&.0\fR" baz\-2\&.0 "\fBblob>4\&.[0\-9]\fR" .RE .PP -\fBFind the package that owns the file \fB/bin/mount\fR:\fR +Find the package that owns the file \fB/bin/mount\fR: .RS 4 $ xbps\-bin find\-files /bin/mount .RE .PP -\fBFind the packages that match the pattern "\fB/usr/lib/libav\&*\fR": +Find the packages that match the pattern "\fB/usr/lib/libav\&*\fR": .RS 4 $ xbps\-bin find\-files "/usr/lib/libav\&*" .RE .PP -\fBRemove and purge the package \fBproplib-devel\fR:\fR +Remove and purge the package \fBproplib-devel\fR: .RS 4 $ xbps\-bin -yp remove proplib\-devel +.RE .PP +Remove and purge the package \fBbsdtar\fR and recursively all packages that +were installed automatically by it: +.RS 4 +$ xbps\-bin -Rp remove bsdtar +.RE .SH "BUGS" .sp Probably, but I try to make this not happen\&. Use it under your own responsability and enjoy your life\&. diff --git a/include/xbps_api.h b/include/xbps_api.h index 8c07e8b6..5c74ae05 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 "20110129" +#define XBPS_RELVER "20110130" /** * @def XBPS_META_PATH @@ -294,16 +294,18 @@ const char *xbps_fetch_error_string(void); /*@}*/ - /** * @ingroup pkg_orphans * * Finds all package orphans currently installed. * + * @param[in] orphans Proplib array of strings with package names of + * packages that should be treated as they were already removed (optional). + * * @return A proplib array of dictionaries with all orphans found, * on error NULL is returned and errno is set appropiately. */ -prop_array_t xbps_find_pkg_orphans(void); +prop_array_t xbps_find_pkg_orphans(prop_array_t orphans); /** * @ingroup vermatch diff --git a/lib/package_orphans.c b/lib/package_orphans.c index 23b44a0d..ee5d083a 100644 --- a/lib/package_orphans.c +++ b/lib/package_orphans.c @@ -60,15 +60,23 @@ * dictionary. */ +struct orphan_data { + prop_array_t array; + prop_array_t orphans_user; +}; + static int find_orphan_pkg(prop_object_t obj, void *arg, bool *loop_done) { - prop_array_t reqby, orphans = arg; + struct orphan_data *od = arg; + prop_array_t reqby; prop_object_t obj2; prop_object_iterator_t iter; - const char *pkgdep; + const char *pkgdep, *curpkgname; + char *pkgdepname; unsigned int ndep = 0, cnt = 0; bool automatic = false; + size_t i; int rv = 0; pkg_state_t state; @@ -82,7 +90,6 @@ find_orphan_pkg(prop_object_t obj, void *arg, bool *loop_done) if ((rv = xbps_get_pkg_state_dictionary(obj, &state)) != 0) return rv; - /* * Skip packages that aren't fully installed. */ @@ -92,39 +99,75 @@ find_orphan_pkg(prop_object_t obj, void *arg, bool *loop_done) reqby = prop_dictionary_get(obj, "requiredby"); if (prop_object_type(reqby) != PROP_TYPE_ARRAY) return EINVAL; - - if ((cnt = prop_array_count(reqby)) == 0) { - prop_array_add(orphans, obj); + /* + * Add packages with empty "requiredby" arrays. + */ + cnt = prop_array_count(reqby); + if (cnt == 0) { + prop_array_add(od->array, obj); return 0; } + /* + * Add packages that only have 1 entry matching any pkgname + * object in the user supplied array of strings. + */ + if (od->orphans_user != NULL && cnt == 1) { + for (i = 0; i < prop_array_count(od->orphans_user); i++) { + prop_array_get_cstring_nocopy(od->orphans_user, + i, &curpkgname); + if (xbps_find_pkgname_in_array(reqby, curpkgname)) { + prop_array_add(od->array, obj); + return 0; + } + } + } iter = prop_array_iterator(reqby); if (iter == NULL) return ENOMEM; - + /* + * Iterate over the requiredby array and add current pkg + * when all pkg dependencies are already in requiredby + * or any pkgname object in the user supplied array of + * strings match. + */ while ((obj2 = prop_object_iterator_next(iter)) != NULL) { pkgdep = prop_string_cstring_nocopy(obj2); if (pkgdep == NULL) { prop_object_iterator_release(iter); return EINVAL; } - if (xbps_find_pkg_in_array_by_pattern(orphans, pkgdep)) + if (xbps_find_pkg_in_array_by_pattern(od->array, pkgdep)) ndep++; + if (od->orphans_user == NULL) + continue; + + pkgdepname = xbps_get_pkg_name(pkgdep); + assert(pkgdepname != NULL); + for (i = 0; i < prop_array_count(od->orphans_user); i++) { + prop_array_get_cstring_nocopy(od->orphans_user, + i, &curpkgname); + if (strcmp(curpkgname, pkgdepname) == 0) { + ndep++; + break; + } + } } prop_object_iterator_release(iter); if (ndep != cnt) return 0; - if (!prop_array_add(orphans, obj)) + if (!prop_array_add(od->array, obj)) return EINVAL; return 0; } prop_array_t -xbps_find_pkg_orphans(void) +xbps_find_pkg_orphans(prop_array_t orphans_user) { prop_array_t array = NULL; prop_dictionary_t dict; + struct orphan_data od; int rv = 0; if ((dict = xbps_regpkgdb_dictionary_get()) == NULL) @@ -132,20 +175,23 @@ xbps_find_pkg_orphans(void) /* * Prepare an array with all packages previously found. */ - if ((array = prop_array_create()) == NULL) + if ((od.array = prop_array_create()) == NULL) goto out; /* * Find out all orphans by looking at the * regpkgdb dictionary and iterate in reverse order * in which packages were installed. */ + od.orphans_user = orphans_user; rv = xbps_callback_array_iter_reverse_in_dict(dict, "packages", - find_orphan_pkg, array); + find_orphan_pkg, &od); if (rv != 0) { errno = rv; - prop_object_release(array); + prop_object_release(od.array); array = NULL; + goto out; } + array = prop_array_copy(od.array); out: xbps_regpkgdb_dictionary_release();