bin/xbps-remove: allow removing uninstalled packages from the cache

Change "obsolete packages" to "outdated packages" when describing the
old behaviour.
This commit is contained in:
Duncan Overbruck 2023-01-30 15:57:01 +01:00
parent 6d940e647f
commit ee770cb8e4
No known key found for this signature in database
GPG Key ID: 335C1D17EC3D6E35
5 changed files with 77 additions and 23 deletions

View File

@ -64,22 +64,23 @@ binpkg_parse(char *buf, size_t bufsz, const char *path, const char **pkgver, con
return 0; return 0;
} }
struct cleaner_data {
bool dry;
bool uninstalled;
};
static int static int
cleaner_cb(struct xbps_handle *xhp, xbps_object_t obj, cleaner_cb(struct xbps_handle *xhp, xbps_object_t obj,
const char *key UNUSED, void *arg, const char *key UNUSED, void *arg,
bool *done UNUSED) bool *done UNUSED)
{ {
char buf[PATH_MAX]; char buf[PATH_MAX];
xbps_dictionary_t repo_pkgd; xbps_dictionary_t pkgd;
const char *binpkg, *rsha256; const char *binpkg, *rsha256;
const char *binpkgver, *binpkgarch; const char *binpkgver, *binpkgarch;
bool drun = false; struct cleaner_data *data = arg;
int r; int r;
/* Extract drun (dry-run) flag from arg*/
if (arg != NULL)
drun = *(bool*)arg;
binpkg = xbps_string_cstring_nocopy(obj); binpkg = xbps_string_cstring_nocopy(obj);
r = binpkg_parse(buf, sizeof(buf), binpkg, &binpkgver, &binpkgarch); r = binpkg_parse(buf, sizeof(buf), binpkg, &binpkgver, &binpkgarch);
if (r < 0) { if (r < 0) {
@ -96,9 +97,13 @@ cleaner_cb(struct xbps_handle *xhp, xbps_object_t obj,
* Remove binary pkg if it's not registered in any repository * Remove binary pkg if it's not registered in any repository
* or if hash doesn't match. * or if hash doesn't match.
*/ */
repo_pkgd = xbps_rpool_get_pkg(xhp, binpkgver); if (data->uninstalled) {
if (repo_pkgd) { pkgd = xbps_pkgdb_get_pkg(xhp, binpkgver);
xbps_dictionary_get_cstring_nocopy(repo_pkgd, } else {
pkgd = xbps_rpool_get_pkg(xhp, binpkgver);
}
if (pkgd) {
xbps_dictionary_get_cstring_nocopy(pkgd,
"filename-sha256", &rsha256); "filename-sha256", &rsha256);
r = xbps_file_sha256_check(binpkg, rsha256); r = xbps_file_sha256_check(binpkg, rsha256);
if (r == 0) { if (r == 0) {
@ -111,13 +116,13 @@ cleaner_cb(struct xbps_handle *xhp, xbps_object_t obj,
} }
} }
snprintf(buf, sizeof(buf), "%s.sig", binpkg); snprintf(buf, sizeof(buf), "%s.sig", binpkg);
if (!drun && unlink(binpkg) == -1) { if (!data->dry && unlink(binpkg) == -1) {
xbps_error_printf("Failed to remove `%s': %s\n", xbps_error_printf("Failed to remove `%s': %s\n",
binpkg, strerror(errno)); binpkg, strerror(errno));
} else { } else {
printf("Removed %s from cachedir (obsolete)\n", binpkg); printf("Removed %s from cachedir (obsolete)\n", binpkg);
} }
if (!drun && unlink(buf) == -1 && errno != ENOENT) { if (!data->dry && unlink(buf) == -1 && errno != ENOENT) {
xbps_error_printf("Failed to remove `%s': %s\n", xbps_error_printf("Failed to remove `%s': %s\n",
buf, strerror(errno)); buf, strerror(errno));
} }
@ -126,7 +131,7 @@ cleaner_cb(struct xbps_handle *xhp, xbps_object_t obj,
} }
int int
clean_cachedir(struct xbps_handle *xhp, bool drun) clean_cachedir(struct xbps_handle *xhp, bool uninstalled, bool drun)
{ {
xbps_array_t array = NULL; xbps_array_t array = NULL;
DIR *dirp; DIR *dirp;
@ -158,7 +163,11 @@ clean_cachedir(struct xbps_handle *xhp, bool drun)
(void)closedir(dirp); (void)closedir(dirp);
if (xbps_array_count(array)) { if (xbps_array_count(array)) {
rv = xbps_array_foreach_cb_multi(xhp, array, NULL, cleaner_cb, (void*)&drun); struct cleaner_data data = {
.dry = drun,
.uninstalled = uninstalled,
};
rv = xbps_array_foreach_cb_multi(xhp, array, NULL, cleaner_cb, (void*)&data);
xbps_object_release(array); xbps_object_release(array);
} }
return rv; return rv;

View File

@ -27,6 +27,6 @@
#define _XBPS_REMOVE_DEFS_H_ #define _XBPS_REMOVE_DEFS_H_
/* From clean-cache.c */ /* From clean-cache.c */
int clean_cachedir(struct xbps_handle *, bool drun); int clean_cachedir(struct xbps_handle *, bool uninstalled, bool drun);
#endif /* !_XBPS_REMOVE_DEFS_H_ */ #endif /* !_XBPS_REMOVE_DEFS_H_ */

View File

@ -53,7 +53,8 @@ usage(bool fail)
" -f, --force Force package files removal\n" " -f, --force Force package files removal\n"
" -h, --help Show usage\n" " -h, --help Show usage\n"
" -n, --dry-run Dry-run mode\n" " -n, --dry-run Dry-run mode\n"
" -O, --clean-cache Remove obsolete packages in cachedir\n" " -O, --clean-cache Remove outdated packages from the cache\n"
" If specified twice, also remove uninstalled packages\n"
" -o, --remove-orphans Remove package orphans\n" " -o, --remove-orphans Remove package orphans\n"
" -R, --recursive Recursively remove dependencies\n" " -R, --recursive Recursively remove dependencies\n"
" -r, --rootdir <dir> Full path to rootdir\n" " -r, --rootdir <dir> Full path to rootdir\n"
@ -179,12 +180,13 @@ main(int argc, char **argv)
struct xbps_handle xh; struct xbps_handle xh;
const char *rootdir, *cachedir, *confdir; const char *rootdir, *cachedir, *confdir;
int c, flags, rv; int c, flags, rv;
bool yes, drun, recursive, clean_cache, orphans; bool yes, drun, recursive, orphans;
int maxcols, missing; int maxcols, missing;
int clean_cache = 0;
rootdir = cachedir = confdir = NULL; rootdir = cachedir = confdir = NULL;
flags = rv = 0; flags = rv = 0;
drun = recursive = clean_cache = yes = orphans = false; drun = recursive = yes = orphans = false;
while ((c = getopt_long(argc, argv, shortopts, longopts, NULL)) != -1) { while ((c = getopt_long(argc, argv, shortopts, longopts, NULL)) != -1) {
switch (c) { switch (c) {
@ -210,7 +212,7 @@ main(int argc, char **argv)
drun = true; drun = true;
break; break;
case 'O': case 'O':
clean_cache = true; clean_cache++;
break; break;
case 'o': case 'o':
orphans = true; orphans = true;
@ -236,7 +238,7 @@ main(int argc, char **argv)
/* NOTREACHED */ /* NOTREACHED */
} }
} }
if (!clean_cache && !orphans && (argc == optind)) { if (clean_cache == 0 && !orphans && (argc == optind)) {
usage(true); usage(true);
/* NOTREACHED */ /* NOTREACHED */
} }
@ -263,8 +265,8 @@ main(int argc, char **argv)
maxcols = get_maxcols(); maxcols = get_maxcols();
if (clean_cache) { if (clean_cache > 0) {
rv = clean_cachedir(&xh, drun); rv = clean_cachedir(&xh, clean_cache > 1, drun);
if (!orphans || rv) if (!orphans || rv)
exit(rv);; exit(rv);;
} }

View File

@ -79,7 +79,9 @@ Show the help message.
Dry-run mode. Show what actions would be done but don't do anything. The current output Dry-run mode. Show what actions would be done but don't do anything. The current output
prints 6 arguments: "<pkgver> <action> <arch> <repository> <installedsize> <downloadsize>". prints 6 arguments: "<pkgver> <action> <arch> <repository> <installedsize> <downloadsize>".
.It Fl O, Fl -clean-cache .It Fl O, Fl -clean-cache
Cleans cache directory removing obsolete binary packages. Cleans cache directory removing outdated binary packages.
If specified twice,
also remove packages that are not installed from the cache.
.It Fl o, Fl -remove-orphans .It Fl o, Fl -remove-orphans
Removes installed package orphans that were installed automatically Removes installed package orphans that were installed automatically
(as dependencies) and are not currently dependencies of any installed package. (as dependencies) and are not currently dependencies of any installed package.

View File

@ -53,13 +53,15 @@ clean_cache_head() {
} }
clean_cache_body() { clean_cache_body() {
mkdir -p repo pkg_A/B/C mkdir -p repo pkg_A/B/C pkg_B
touch pkg_A/ touch pkg_A/
cd repo cd repo
xbps-create -A noarch -n A-1.0_1 -s "A pkg" ../pkg_A xbps-create -A noarch -n A-1.0_1 -s "A pkg" ../pkg_A
atf_check_equal $? 0 atf_check_equal $? 0
xbps-create -A noarch -n A-1.0_2 -s "A pkg" ../pkg_A xbps-create -A noarch -n A-1.0_2 -s "A pkg" ../pkg_A
atf_check_equal $? 0 atf_check_equal $? 0
xbps-create -A noarch -n B-1.0_1 -s "B pkg" ../pkg_B
atf_check_equal $? 0
xbps-rindex -d -a $PWD/*.xbps xbps-rindex -d -a $PWD/*.xbps
atf_check_equal $? 0 atf_check_equal $? 0
cd .. cd ..
@ -69,12 +71,15 @@ clean_cache_body() {
cp repo/*.xbps root/var/cache/xbps cp repo/*.xbps root/var/cache/xbps
atf_check_equal $? 0 atf_check_equal $? 0
echo "repository=https://localhost/" >root/etc/xbps.d/localrepo.conf echo "repository=https://localhost/" >root/etc/xbps.d/localrepo.conf
xbps-install -r root -C etc/xbps.d -R repo -dvy B
xbps-remove -r root -C etc/xbps.d -dvO xbps-remove -r root -C etc/xbps.d -dvO
atf_check_equal $? 0 atf_check_equal $? 0
test -f root/var/cache/xbps/A-1.0_2.noarch.xbps test -f root/var/cache/xbps/A-1.0_2.noarch.xbps
atf_check_equal $? 0 atf_check_equal $? 0
test -f root/var/cache/xbps/A-1.0_1.noarch.xbps test -f root/var/cache/xbps/A-1.0_1.noarch.xbps
atf_check_equal $? 1 atf_check_equal $? 1
test -f root/var/cache/xbps/B-1.0_1.noarch.xbps
atf_check_equal $? 0
} }
atf_test_case clean_cache_dry_run atf_test_case clean_cache_dry_run
@ -136,10 +141,46 @@ clean_cache_dry_run_perm_body() {
atf_check_equal "$out" "Removed A-1.0_1.noarch.xbps from cachedir (obsolete)" atf_check_equal "$out" "Removed A-1.0_1.noarch.xbps from cachedir (obsolete)"
} }
clean_cache_uninstalled_head() {
atf_set "descr" "xbps-remove(1): clean uninstalled package from cache"
}
clean_cache_uninstalled_body() {
mkdir -p repo pkg_A/B/C pkg_B
touch pkg_A/
cd repo
xbps-create -A noarch -n A-1.0_1 -s "A pkg" ../pkg_A
atf_check_equal $? 0
xbps-create -A noarch -n A-1.0_2 -s "A pkg" ../pkg_A
atf_check_equal $? 0
xbps-create -A noarch -n B-1.0_1 -s "B pkg" ../pkg_B
atf_check_equal $? 0
xbps-rindex -d -a $PWD/*.xbps
atf_check_equal $? 0
cd ..
mkdir -p root/etc/xbps.d root/var/db/xbps/https___localhost_ root/var/cache/xbps
cp repo/*-repodata root/var/db/xbps/https___localhost_
atf_check_equal $? 0
cp repo/*.xbps root/var/cache/xbps
atf_check_equal $? 0
echo "repository=https://localhost/" >root/etc/xbps.d/localrepo.conf
xbps-install -r root -C etc/xbps.d -R repo -dvy B
atf_check_equal $? 0
xbps-remove -r root -C etc/xbps.d -dvOO
atf_check_equal $? 0
test -f root/var/cache/xbps/A-1.0_2.noarch.xbps
atf_check_equal $? 1
test -f root/var/cache/xbps/A-1.0_1.noarch.xbps
atf_check_equal $? 1
test -f root/var/cache/xbps/B-1.0_1.noarch.xbps
atf_check_equal $? 0
}
atf_init_test_cases() { atf_init_test_cases() {
atf_add_test_case remove_directory atf_add_test_case remove_directory
atf_add_test_case remove_orphans atf_add_test_case remove_orphans
atf_add_test_case clean_cache atf_add_test_case clean_cache
atf_add_test_case clean_cache_dry_run atf_add_test_case clean_cache_dry_run
atf_add_test_case clean_cache_dry_run_perm atf_add_test_case clean_cache_dry_run_perm
atf_add_test_case clean_cache_uninstalled
} }