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

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