yifengyou / rpms / yum

Forked from rpms/yum 3 years ago
Clone

Blame SOURCES/BZ-1481220-print-disk-usage-on-yum-clean-all.patch

5e9bef
diff --git a/cli.py b/cli.py
5e9bef
index 5d9791bc..403a92f9 100755
5e9bef
--- a/cli.py
5e9bef
+++ b/cli.py
5e9bef
@@ -29,6 +29,7 @@ import math
5e9bef
 from optparse import OptionParser,OptionGroup,SUPPRESS_HELP
5e9bef
 import rpm
5e9bef
 import ctypes
5e9bef
+import glob
5e9bef
 
5e9bef
 from weakref import proxy as weakref
5e9bef
 
5e9bef
@@ -1748,26 +1749,10 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
5e9bef
         msg = self.fmtKeyValFill(_('Cleaning repos: '), 
5e9bef
                         ' '.join([ x.id for x in self.repos.listEnabled()]))
5e9bef
         self.verbose_logger.log(yum.logginglevels.INFO_2, msg)
5e9bef
+        msg = (_('Operating on %s (see CLEAN OPTIONS in yum(8) for details)')
5e9bef
+               % self.conf.cachedir)
5e9bef
+        self.verbose_logger.log(yum.logginglevels.DEBUG_3, msg)
5e9bef
         if 'all' in userlist:
5e9bef
-            self.verbose_logger.log(yum.logginglevels.INFO_2,
5e9bef
-                _('Cleaning up everything'))
5e9bef
-
5e9bef
-            # Print a "maybe you want rm -rf" hint to compensate for the fact
5e9bef
-            # that yum clean all is often misunderstood.  Don't do that,
5e9bef
-            # however, if cachedir is non-default as we would have to replace
5e9bef
-            # arbitrary yum vars with * and that could produce a harmful
5e9bef
-            # command, e.g. for /mydata/$myvar we would say rm -rf /mydata/*
5e9bef
-            cachedir = self.conf.cachedir
5e9bef
-            if cachedir.startswith(('/var/cache/yum', '/var/tmp/yum-')):
5e9bef
-                # Take just the first 3 path components
5e9bef
-                rmdir = '/'.join(cachedir.split('/')[:4])
5e9bef
-                self.verbose_logger.log(
5e9bef
-                    yum.logginglevels.INFO_2,
5e9bef
-                    _('Maybe you want: rm -rf %s, to also free up space taken '
5e9bef
-                      'by orphaned data from disabled or removed repos'
5e9bef
-                      % rmdir),
5e9bef
-                )
5e9bef
-
5e9bef
             pkgcode, pkgresults = self.cleanPackages()
5e9bef
             hdrcode, hdrresults = self.cleanHeaders()
5e9bef
             xmlcode, xmlresults = self.cleanMetadata()
5e9bef
@@ -1780,6 +1765,67 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
5e9bef
                        rpmresults)
5e9bef
             for msg in results:
5e9bef
                 self.logger.debug(msg)
5e9bef
+
5e9bef
+            # Walk the cachedir, look for any leftovers and categorize them
5e9bef
+            cacheglob = self.getCachedirGlob(['basearch', 'releasever'])
5e9bef
+            paths = glob.glob(cacheglob + '/*')
5e9bef
+            table = ([], [], [], [])  # (enabled, disabled, untracked, other)
5e9bef
+            repos = self.repos.repos
5e9bef
+            for path in paths:
5e9bef
+                base = os.path.basename(path)
5e9bef
+                if os.path.isdir(path):
5e9bef
+                    # Repodir
5e9bef
+                    if base not in repos:
5e9bef
+                        col = 2
5e9bef
+                    elif repos[base].enabled:
5e9bef
+                        col = 0
5e9bef
+                    else:
5e9bef
+                        col = 1
5e9bef
+                    # Recursively gather all files in this repodir
5e9bef
+                    files = yum.misc.getFileList(path, '', [])
5e9bef
+                else:
5e9bef
+                    # Ordinary file (such as timedhosts)
5e9bef
+                    col = 3
5e9bef
+                    files = [path]
5e9bef
+                usage = sum(map(os.path.getsize, files))
5e9bef
+                if usage > 0:
5e9bef
+                    table[col].append((usage, path))
5e9bef
+
5e9bef
+            # Print the table (verbose mode only)
5e9bef
+            lines = [_('Disk usage of %s after cleanup:') % cacheglob]
5e9bef
+            headers = ('enabled repos', 'disabled repos', 'untracked repos',
5e9bef
+                       'other data')
5e9bef
+            totals = [0, 0, 0, 0]
5e9bef
+            for col, header in enumerate(headers):
5e9bef
+                rows = []
5e9bef
+                total = 0
5e9bef
+                # Start with the biggest items
5e9bef
+                for usage, path in sorted(table[col], key=lambda x:x[0],
5e9bef
+                                          reverse=True):
5e9bef
+                    rows.append('  %-5s  %s'
5e9bef
+                                % (self.format_number(usage), path))
5e9bef
+                    total += usage
5e9bef
+                colon = ':' if rows else ''
5e9bef
+                lines += ['%-5s  %s%s'
5e9bef
+                          % (self.format_number(total), _(header), colon)]
5e9bef
+                lines += rows
5e9bef
+                totals[col] = total
5e9bef
+            lines += [_('%-5s  total') % self.format_number(sum(totals))]
5e9bef
+            msg = '\n'.join(lines)
5e9bef
+            self.verbose_logger.log(yum.logginglevels.DEBUG_3, msg)
5e9bef
+
5e9bef
+            # Print a short hint for leftover repos specifically (non-verbose
5e9bef
+            # mode only)
5e9bef
+            total = sum(totals[:3])
5e9bef
+            if self.conf.debuglevel == 6 or not total:
5e9bef
+                return code, []
5e9bef
+            total = self.format_number(total)
5e9bef
+            if total[-1] == ' ':
5e9bef
+                total = total[:-1] + 'bytes'
5e9bef
+            msg = (_('Other repos take up %s of disk space '
5e9bef
+                     '(use --verbose for details)') % total)
5e9bef
+            self.verbose_logger.log(yum.logginglevels.INFO_2, msg)
5e9bef
+
5e9bef
             return code, []
5e9bef
             
5e9bef
         if 'headers' in userlist:
5e9bef
diff --git a/docs/yum.8 b/docs/yum.8
5e9bef
index e3f1d32a..34a27f53 100644
5e9bef
--- a/docs/yum.8
5e9bef
+++ b/docs/yum.8
5e9bef
@@ -1031,11 +1031,37 @@ Or:          \fByum list available 'foo*'\fP
5e9bef
 .IP
5e9bef
 .PP 
5e9bef
 .SH "CLEAN OPTIONS"
5e9bef
-The following are the ways which you can invoke \fByum\fP in clean
5e9bef
-mode. Note that "all files" in the commands below means 
5e9bef
-"all files in currently enabled repositories". 
5e9bef
-If you want to also clean any (temporarily) disabled repositories you need to
5e9bef
-use \fB\-\-enablerepo='*'\fP option.
5e9bef
+The following are the ways which you can invoke \fByum\fP in clean mode.
5e9bef
+
5e9bef
+Note that these commands only operate on files in currently enabled
5e9bef
+repositories.
5e9bef
+If you use substitution variables (such as $releasever) in your \fBcachedir\fP
5e9bef
+configuration, the operation is further restricted to the current values of
5e9bef
+those variables.
5e9bef
+
5e9bef
+For fine-grained control over what is being cleaned, you can use
5e9bef
+\fB\-\-enablerepo\fP, \fB\-\-disablerepo\fP and \fB\-\-releasever\fP as
5e9bef
+desired.
5e9bef
+Note, however, that you cannot use \fB\-\-releasever='*'\fP to do the cleaning
5e9bef
+for all values previously used.
5e9bef
+Also note that untracked (no longer configured) repositories will not be
5e9bef
+automatically cleaned.
5e9bef
+
5e9bef
+To purge the entire cache in one go, the easiest way is to delete the files
5e9bef
+manually.
5e9bef
+Depending on your \fBcachedir\fP configuration, this usually means treating any
5e9bef
+variables as shell wildcards and recursively removing matching directories.
5e9bef
+For example, if your \fBcachedir\fP is /var/cache/yum/$basearch/$releasever,
5e9bef
+then the whole /var/cache/yum directory has to be removed.
5e9bef
+If you do this, \fByum\fP will rebuild the cache as required the next time it
5e9bef
+is run (this may take a while).
5e9bef
+
5e9bef
+As a convenience, when you run \fByum clean all\fP, a recursive lookup will be
5e9bef
+done to detect any repositories not cleaned due to the above restrictions.
5e9bef
+If some are found, a message will be printed stating how much disk space they
5e9bef
+occupy and thus how much you can reclaim by cleaning them.
5e9bef
+If you also supply \fB\-\-verbose\fP, a more detailed breakdown will be
5e9bef
+printed.
5e9bef
 
5e9bef
 .IP "\fByum clean expire-cache\fP"
5e9bef
 Eliminate the local data saying when the metadata and mirrorlists were downloaded for each repo. This means yum will revalidate the cache for each repo. next time it is used. However if the cache is still valid, nothing significant was deleted.
5e9bef
diff --git a/yum/__init__.py b/yum/__init__.py
5e9bef
index a156a6a6..c6ced7d5 100644
5e9bef
--- a/yum/__init__.py
5e9bef
+++ b/yum/__init__.py
5e9bef
@@ -2890,6 +2890,16 @@ much more problems).
5e9bef
             filelist = misc.getFileList(cachedir, '', [])
5e9bef
         return self._cleanFilelist('rpmdb', filelist)
5e9bef
 
5e9bef
+    def getCachedirGlob(self, dynvar):
5e9bef
+        """Return a glob matching all dirs where yum stores cache files, based
5e9bef
+        on cachedir and the given list of dynamic vars."""
5e9bef
+        yumvar = self.conf.yumvar.copy()
5e9bef
+        for d in dynvar:
5e9bef
+            yumvar[d] = '*'
5e9bef
+        instroot = config.varReplace(self.conf.installroot, self.conf.yumvar)
5e9bef
+        cachedir = config.varReplace(self.conf._pristine_cachedir, yumvar)
5e9bef
+        return (instroot + cachedir).replace('//', '/')
5e9bef
+
5e9bef
     def _cleanFiles(self, exts, pathattr, filetype):
5e9bef
         filelist = []
5e9bef
         for ext in exts:
5e9bef
diff --git a/yum/config.py b/yum/config.py
5e9bef
index 5eac325e..76128fa5 100644
5e9bef
--- a/yum/config.py
5e9bef
+++ b/yum/config.py
5e9bef
@@ -945,6 +945,9 @@ class YumConf(StartupConf):
5e9bef
 
5e9bef
     _reposlist = []
5e9bef
 
5e9bef
+    # cachedir before variable substitutions
5e9bef
+    _pristine_cachedir = None
5e9bef
+
5e9bef
     def dump(self):
5e9bef
         """Return a string representing the values of all the
5e9bef
         configuration options.
5e9bef
@@ -1147,6 +1150,9 @@ def readMainConfig(startupconf):
5e9bef
     yumconf = YumConf()
5e9bef
     yumconf.populate(startupconf._parser, 'main')
5e9bef
 
5e9bef
+    # Store the original cachedir (for later reference in clean commands)
5e9bef
+    yumconf._pristine_cachedir = yumconf.cachedir
5e9bef
+
5e9bef
     # Apply the installroot to directory options
5e9bef
     def _apply_installroot(yumconf, option):
5e9bef
         path = getattr(yumconf, option)