No reason to disallow this- it allows keeping even more packages around in the cache. Test cases included for this case and to ensure the default behavior is preserved. Signed-off-by: Dan McGee <dan@archlinux.org> --- doc/pacman.conf.5.txt | 6 ++- src/pacman/conf.h | 4 +- src/pacman/pacman.c | 22 +++++++----- src/pacman/sync.c | 78 +++++++++++++++++++++-------------------- test/pacman/tests/clean004.py | 30 ++++++++++++++++ test/pacman/tests/clean005.py | 29 +++++++++++++++ 6 files changed, 118 insertions(+), 51 deletions(-) create mode 100644 test/pacman/tests/clean004.py create mode 100644 test/pacman/tests/clean005.py diff --git a/doc/pacman.conf.5.txt b/doc/pacman.conf.5.txt index ae4d748..cb4c589 100644 --- a/doc/pacman.conf.5.txt +++ b/doc/pacman.conf.5.txt @@ -136,14 +136,16 @@ Options These files refer to files in the package archive, so do not include the leading slash (the RootDir) when specifying them. -*CleanMethod =* KeepInstalled | KeepCurrent:: +*CleanMethod =* KeepInstalled &| KeepCurrent:: If set to `KeepInstalled` (the default), the '-Sc' operation will clean packages that are no longer installed (not present in the local database). If set to `KeepCurrent`, '-Sc' will clean outdated packages (not present in any sync database). The second behavior is useful when the package cache is shared among multiple machines, where the local databases are usually different, but the - sync databases in use could be the same. + sync databases in use could be the same. If both values are specified, + packages are only cleaned if not installed locally and not present in any + known sync database. *UseSyslog*:: Log action messages through syslog(). This will insert log entries into diff --git a/src/pacman/conf.h b/src/pacman/conf.h index ff7a9c7..92c379f 100644 --- a/src/pacman/conf.h +++ b/src/pacman/conf.h @@ -111,8 +111,8 @@ enum { /* clean method */ enum { - PM_CLEAN_KEEPINST = 0, /* default */ - PM_CLEAN_KEEPCUR + PM_CLEAN_KEEPINST = 1, + PM_CLEAN_KEEPCUR = (1 << 1) }; /* global config variable */ diff --git a/src/pacman/pacman.c b/src/pacman/pacman.c index 45500cf..21d0210 100644 --- a/src/pacman/pacman.c +++ b/src/pacman/pacman.c @@ -792,6 +792,18 @@ static void option_add_syncfirst(const char *name) { config->syncfirst = alpm_list_add(config->syncfirst, strdup(name)); } +/* helper for being used with setrepeatingoption */ +static void option_add_cleanmethod(const char *value) { + if (strcmp(value, "KeepInstalled") == 0) { + config->cleanmethod |= PM_CLEAN_KEEPINST; + } else if (strcmp(value, "KeepCurrent") == 0) { + config->cleanmethod |= PM_CLEAN_KEEPCUR; + } else { + pm_printf(PM_LOG_ERROR, _("invalid value for 'CleanMethod' : '%s'\n"), + value); + } +} + /** Add repeating options such as NoExtract, NoUpgrade, etc to libalpm * settings. Refactored out of the parseconfig code since all of them did * the exact same thing and duplicated code. @@ -1008,15 +1020,7 @@ static int _parse_options(char *key, char *value) alpm_option_set_fetchcb(download_with_xfercommand); pm_printf(PM_LOG_DEBUG, "config: xfercommand: %s\n", value); } else if (strcmp(key, "CleanMethod") == 0) { - if (strcmp(value, "KeepInstalled") == 0) { - config->cleanmethod = PM_CLEAN_KEEPINST; - } else if (strcmp(value, "KeepCurrent") == 0) { - config->cleanmethod = PM_CLEAN_KEEPCUR; - } else { - pm_printf(PM_LOG_ERROR, _("invalid value for 'CleanMethod' : '%s'\n"), value); - return(1); - } - pm_printf(PM_LOG_DEBUG, "config: cleanmethod: %s\n", value); + setrepeatingoption(value, "CleanMethod", option_add_cleanmethod); } else { pm_printf(PM_LOG_ERROR, _("directive '%s' with a value not recognized\n"), key); return(1); diff --git a/src/pacman/sync.c b/src/pacman/sync.c index b3f5891..fc23fd1 100644 --- a/src/pacman/sync.c +++ b/src/pacman/sync.c @@ -151,23 +151,23 @@ static int sync_cleancache(int level) printf(_("Cache directory: %s\n"), (char*)alpm_list_getdata(i)); } + if(!config->cleanmethod) { + /* default to KeepInstalled if user did not specify */ + config->cleanmethod = PM_CLEAN_KEEPINST; + } + if(level == 1) { - switch(config->cleanmethod) { - case PM_CLEAN_KEEPINST: - if(!yesno(_("Do you want to remove uninstalled packages from cache?"))) { - return(0); - } - break; - case PM_CLEAN_KEEPCUR: - if(!yesno(_("Do you want to remove outdated packages from cache?"))) { - return(0); - } - break; - default: - /* this should not happen : the config parsing doesn't set any other value */ - return(1); + printf(_("Packages to keep:\n")); + if(config->cleanmethod & PM_CLEAN_KEEPINST) { + printf(_(" All locally installed packages\n")); + } + if(config->cleanmethod & PM_CLEAN_KEEPCUR) { + printf(_(" All current sync database packages\n")); + } + if(!yesno(_("Do you want to remove all other packages from cache?"))) { + return(0); } - printf(_("removing old packages from cache...\n")); + printf(_("removing stale packages from cache...\n")); } else { if(!noyes(_("Do you want to remove ALL files from cache?"))) { return(0); @@ -193,6 +193,7 @@ static int sync_cleancache(int level) char path[PATH_MAX]; int delete = 1; pmpkg_t *localpkg = NULL, *pkg = NULL; + const char *local_name, *local_version; alpm_list_t *j; if(strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0) { @@ -219,32 +220,33 @@ static int sync_cleancache(int level) } continue; } - switch(config->cleanmethod) { - case PM_CLEAN_KEEPINST: - /* check if this package is in the local DB */ - pkg = alpm_db_get_pkg(db_local, alpm_pkg_get_name(localpkg)); - if(pkg != NULL && alpm_pkg_vercmp(alpm_pkg_get_version(localpkg), + local_name = alpm_pkg_get_name(localpkg); + local_version = alpm_pkg_get_version(localpkg); + + if(config->cleanmethod & PM_CLEAN_KEEPINST) { + /* check if this package is in the local DB */ + pkg = alpm_db_get_pkg(db_local, local_name); + if(pkg != NULL && alpm_pkg_vercmp(local_version, + alpm_pkg_get_version(pkg)) == 0) { + /* package was found in local DB and version matches, keep it */ + pm_printf(PM_LOG_DEBUG, "pkg %s-%s found in local db\n", + local_name, local_version); + delete = 0; + } + } + if(config->cleanmethod & PM_CLEAN_KEEPCUR) { + /* check if this package is in a sync DB */ + for(j = sync_dbs; j && delete; j = alpm_list_next(j)) { + pmdb_t *db = alpm_list_getdata(j); + pkg = alpm_db_get_pkg(db, local_name); + if(pkg != NULL && alpm_pkg_vercmp(local_version, alpm_pkg_get_version(pkg)) == 0) { - /* package was found in local DB and version matches, keep it */ + /* package was found in a sync DB and version matches, keep it */ + pm_printf(PM_LOG_DEBUG, "pkg %s-%s found in sync db\n", + local_name, local_version); delete = 0; } - break; - case PM_CLEAN_KEEPCUR: - /* check if this package is in a sync DB */ - for(j = sync_dbs; j && delete; j = alpm_list_next(j)) { - pmdb_t *db = alpm_list_getdata(j); - pkg = alpm_db_get_pkg(db, alpm_pkg_get_name(localpkg)); - if(pkg != NULL && alpm_pkg_vercmp(alpm_pkg_get_version(localpkg), - alpm_pkg_get_version(pkg)) == 0) { - /* package was found in a sync DB and version matches, keep it */ - delete = 0; - } - } - break; - default: - /* this should not happen : the config parsing doesn't set any other value */ - delete = 0; - break; + } } /* free the local file package */ alpm_pkg_free(localpkg); diff --git a/test/pacman/tests/clean004.py b/test/pacman/tests/clean004.py new file mode 100644 index 0000000..09137f3 --- /dev/null +++ b/test/pacman/tests/clean004.py @@ -0,0 +1,30 @@ +self.description = "CleanMethod = KeepInstalled KeepCurrent" + +sp = pmpkg("dummy", "2.0-1") +self.addpkg2db("sync", sp) + +sp = pmpkg("bar", "2.0-1") +self.addpkg2db("sync", sp) + +sp = pmpkg("baz", "2.0-1") +self.addpkg2db("sync", sp) + +lp = pmpkg("dummy", "1.0-1") +self.addpkg2db("local", lp) + +lp = pmpkg("bar", "2.0-1") +self.addpkg2db("local", lp) + +op = pmpkg("foo", "2.0-1") +self.addpkg(op) + +self.args = "-Sc" +self.option['CleanMethod'] = ['KeepInstalled KeepCurrent'] +self.createlocalpkgs = True + +self.addrule("PACMAN_RETCODE=0") +self.addrule("CACHE_EXISTS=dummy|2.0-1") +self.addrule("CACHE_EXISTS=dummy|1.0-1") +self.addrule("CACHE_EXISTS=bar|2.0-1") +self.addrule("CACHE_EXISTS=baz|2.0-1") +self.addrule("!CACHE_EXISTS=foo|2.0-1") diff --git a/test/pacman/tests/clean005.py b/test/pacman/tests/clean005.py new file mode 100644 index 0000000..f85248e --- /dev/null +++ b/test/pacman/tests/clean005.py @@ -0,0 +1,29 @@ +self.description = "CleanMethod = unspecified" + +sp = pmpkg("dummy", "2.0-1") +self.addpkg2db("sync", sp) + +sp = pmpkg("bar", "2.0-1") +self.addpkg2db("sync", sp) + +sp = pmpkg("baz", "2.0-1") +self.addpkg2db("sync", sp) + +lp = pmpkg("dummy", "1.0-1") +self.addpkg2db("local", lp) + +lp = pmpkg("bar", "2.0-1") +self.addpkg2db("local", lp) + +op = pmpkg("foo", "2.0-1") +self.addpkg(op) + +self.args = "-Sc" +self.createlocalpkgs = True + +self.addrule("PACMAN_RETCODE=0") +self.addrule("!CACHE_EXISTS=dummy|2.0-1") +self.addrule("CACHE_EXISTS=dummy|1.0-1") +self.addrule("CACHE_EXISTS=bar|2.0-1") +self.addrule("!CACHE_EXISTS=baz|2.0-1") +self.addrule("!CACHE_EXISTS=foo|2.0-1") -- 1.7.3.5