summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDan McGee <dan@archlinux.org>2007-09-25 22:07:36 -0500
committerDan McGee <dan@archlinux.org>2007-09-28 00:16:43 -0500
commit16cb8e6e61c542731814192fc03e3988c7a26325 (patch)
tree130921d619bba25c07d37b00799b2ba3738a2d47
parentf7bbfe4052ca1060d2d1021dacd77923d8ab6786 (diff)
downloadpacman-16cb8e6e61c542731814192fc03e3988c7a26325.tar.xz
Reimplement pacman cache cleaning the right way
Partial cache cleaning was eliminated in a previous commit because it relied on package naming conventions. Re-add it the correct way- we actually open up each package in the cache and get a name and version out of it. If the name and version match that of an installed package, keep it. If the package is not installed or the version does not match the locally-installed version, get rid of it. This can easily be modified if some other heuristic of keeping and removing packages is desired, or if we should clean out the cache dir of any files that are not packages, etc. The biggest current problem with this new approach- speed. Here is one run on my local machine, going from 1643 to 729 packages in the cache (753 in the local DB): real 4m25.829s user 3m22.527s sys 0m6.713s This is likely best addressed by the package loading scheme, which may be loading the entirety of each package archive, which is a waste when we only need the .PKGINFO file read. Signed-off-by: Dan McGee <dan@archlinux.org>
-rw-r--r--src/pacman/sync.c59
1 files changed, 54 insertions, 5 deletions
diff --git a/src/pacman/sync.c b/src/pacman/sync.c
index 251de0c2..bb4926e2 100644
--- a/src/pacman/sync.c
+++ b/src/pacman/sync.c
@@ -41,6 +41,7 @@
#include "conf.h"
extern config_t *config;
+extern pmdb_t *db_local;
static int sync_cleancache(int level)
{
@@ -50,14 +51,62 @@ static int sync_cleancache(int level)
if(level == 1) {
/* incomplete cleanup */
- printf(_("Partial cache cleaning functionality in pacman needs a lot of work.\n"
- "For now it is recommended to use one of the many external tools, such\n"
- "as a python script, to do so.\n"));
- return(1);
+ DIR *dir;
+ struct dirent *ent;
+ /* Let's vastly improve the way this is done. Before, we went by package
+ * name. Instead, let's only keep packages we have installed. Open up each
+ * package and see if it has an entry in the local DB; if not, delete it.
+ */
+ printf(_("Cache directory: %s\n"), cachedir);
+ if(!yesno(_("Do you want to remove non-installed packages from cache? [Y/n] "))) {
+ return(0);
+ }
+ printf(_("removing old packages from cache... "));
+
+ dir = opendir(cachedir);
+ if(dir == NULL) {
+ fprintf(stderr, _("error: could not access cache directory\n"));
+ return(1);
+ }
+
+ rewinddir(dir);
+ /* step through the directory one file at a time */
+ while((ent = readdir(dir)) != NULL) {
+ char path[PATH_MAX];
+ pmpkg_t *localpkg = NULL, *dbpkg = NULL;
+
+ if(!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, "..")) {
+ continue;
+ }
+ /* build the full filepath */
+ snprintf(path, PATH_MAX, "%s/%s", cachedir, ent->d_name);
+
+ /* attempt to load the package, skip file on failures as we may have
+ * files here that aren't valid packages */
+ if(alpm_pkg_load(path, &localpkg) != 0 || localpkg == NULL) {
+ continue;
+ }
+ /* check if this package is in the local DB */
+ dbpkg = alpm_db_get_pkg(db_local, alpm_pkg_get_name(localpkg));
+ if(dbpkg == NULL) {
+ /* delete package, not present in local DB */
+ unlink(path);
+ } else if(alpm_pkg_vercmp(alpm_pkg_get_version(localpkg),
+ alpm_pkg_get_version(dbpkg)) != 0) {
+ /* delete package, it was found but version differs */
+ unlink(path);
+ }
+ /* else version was the same, so keep the package */
+ /* free the local file package */
+ alpm_pkg_free(localpkg);
+ }
+ printf(_("done.\n"));
} else {
/* full cleanup */
- if(!yesno(_("Do you want to remove all packages from cache? [Y/n] ")))
+ printf(_("Cache directory: %s\n"), cachedir);
+ if(!yesno(_("Do you want to remove ALL packages from cache? [Y/n] "))) {
return(0);
+ }
printf(_("removing all packages from cache... "));
if(rmrf(cachedir)) {