Blame SOURCES/BZ-1062959-add-fs-command.patch

1f1d7d
commit b6f5e550048705c0979f0e5bb88f0b83d5750daf
1f1d7d
Author: James Antill <james@and.org>
1f1d7d
Date:   Wed Feb 12 15:59:20 2014 -0500
1f1d7d
1f1d7d
    Fix yum repo-pkgs <blah> install exist-other-repo.
1f1d7d
1f1d7d
diff --git a/yum/__init__.py b/yum/__init__.py
1f1d7d
index 0604d63..622bc14 100644
1f1d7d
--- a/yum/__init__.py
1f1d7d
+++ b/yum/__init__.py
1f1d7d
@@ -4714,6 +4714,8 @@ much more problems).
1f1d7d
                         arg)
1f1d7d
 
1f1d7d
                     mypkgs = self.returnPackagesByDep(arg)
1f1d7d
+                    if repoid:
1f1d7d
+                        mypkgs = misc.filter_pkgs_repoid(mypkgs, repoid)
1f1d7d
                     if not misc.re_glob(arg):
1f1d7d
                         mypkgs = self.bestPackagesFromList(mypkgs,
1f1d7d
                                                            single_name=True,
1f1d7d
commit 26128173b362474456e8f0642073ecb0322ed031
1f1d7d
Author: James Antill <james@and.org>
1f1d7d
Date:   Wed Feb 12 16:06:00 2014 -0500
1f1d7d
1f1d7d
    Add override_install_langs configuration, for container install needs.
1f1d7d
1f1d7d
diff --git a/docs/yum.conf.5 b/docs/yum.conf.5
1f1d7d
index c66eba8..bf3c442 100644
1f1d7d
--- a/docs/yum.conf.5
1f1d7d
+++ b/docs/yum.conf.5
1f1d7d
@@ -329,6 +329,12 @@ context of an rpm transaction set you're best leaving it alone. Default is
1f1d7d
 an empty list.
1f1d7d
 
1f1d7d
 .IP
1f1d7d
+\fBoverride_install_langs\fR
1f1d7d
+This is a way to override rpm's _install_langs macro. without having to change
1f1d7d
+it within rpm's macro file.
1f1d7d
+Default is nothing (so does nothing).
1f1d7d
+
1f1d7d
+.IP
1f1d7d
 \fBrecent\fR
1f1d7d
 Number of days back to look for `recent' packages added to a repository.
1f1d7d
 Used by the \fBlist recent\fR command. Default is `7'.
1f1d7d
diff --git a/yum/config.py b/yum/config.py
1f1d7d
index c38d574..09a4dcc 100644
1f1d7d
--- a/yum/config.py
1f1d7d
+++ b/yum/config.py
1f1d7d
@@ -768,6 +768,7 @@ class YumConf(StartupConf):
1f1d7d
             'kernel-hugemem', 'kernel-enterprise', 'kernel-bigmem',
1f1d7d
             'kernel-devel', 'kernel-PAE', 'kernel-PAE-debug'])
1f1d7d
     tsflags = ListOption()
1f1d7d
+    override_install_langs = Option()
1f1d7d
 
1f1d7d
     assumeyes = BoolOption(False)
1f1d7d
     assumeno  = BoolOption(False)
1f1d7d
diff --git a/yum/depsolve.py b/yum/depsolve.py
1f1d7d
index 8a675eb..1840b43 100644
1f1d7d
--- a/yum/depsolve.py
1f1d7d
+++ b/yum/depsolve.py
1f1d7d
@@ -180,6 +180,13 @@ class Depsolve(object):
1f1d7d
     def initActionTs(self):
1f1d7d
         """Set up the transaction set that will be used for all the work."""
1f1d7d
         
1f1d7d
+        # LOL, override rpm transaction macro.
1f1d7d
+        # Must be done before rpmtsCreate()
1f1d7d
+        if self.conf.override_install_langs:
1f1d7d
+            old_install_langs = rpm.expandMacro("%_install_langs")
1f1d7d
+            rpm.expandMacro("%define _install_langs " +
1f1d7d
+                            self.conf.override_install_langs)
1f1d7d
+
1f1d7d
         self._ts = rpmUtils.transaction.TransactionWrapper(self.conf.installroot)
1f1d7d
         ts_flags_to_rpm = { 'noscripts': rpm.RPMTRANS_FLAG_NOSCRIPTS,
1f1d7d
                             'notriggers': rpm.RPMTRANS_FLAG_NOTRIGGERS,
1f1d7d
commit 99540142d78484327716643daab03581fef6ee4b
1f1d7d
Author: James Antill <james@and.org>
1f1d7d
Date:   Wed Feb 12 16:06:56 2014 -0500
1f1d7d
1f1d7d
    Install yumdb keys for install_langs and tsflags values.
1f1d7d
1f1d7d
diff --git a/yum/__init__.py b/yum/__init__.py
1f1d7d
index 622bc14..3b6ed82 100644
1f1d7d
--- a/yum/__init__.py
1f1d7d
+++ b/yum/__init__.py
1f1d7d
@@ -1915,6 +1915,13 @@ much more problems).
1f1d7d
                 txmbr_cb(txmbr, count)
1f1d7d
             return count
1f1d7d
         
1f1d7d
+        oil = self.conf.override_install_langs
1f1d7d
+        if not oil:
1f1d7d
+            oil = rpm.expandMacro("%_install_langs")
1f1d7d
+        if oil == 'all':
1f1d7d
+            oil = ''
1f1d7d
+        elif oil:
1f1d7d
+            oil = ":".join(sorted(oil.split(':')))
1f1d7d
         vt_st = time.time()
1f1d7d
         self.plugins.run('preverifytrans')
1f1d7d
         count = 0
1f1d7d
@@ -1942,6 +1949,17 @@ much more problems).
1f1d7d
                     if var == 'arch':     continue
1f1d7d
                     # Skip uuid?
1f1d7d
                     setattr(po.yumdb_info, 'var_' + var, self.conf.yumvar[var])
1f1d7d
+                if oil:
1f1d7d
+                    po.yumdb_info.ts_install_langs = oil
1f1d7d
+                if 'nocontexts' in self.conf.tsflags:
1f1d7d
+                    po.yumdb_info.tsflag_nocontexts = 'true'
1f1d7d
+                if 'nodocs' in self.conf.tsflags:
1f1d7d
+                    po.yumdb_info.tsflag_nodocs = 'true'
1f1d7d
+                if 'noscripts' in self.conf.tsflags:
1f1d7d
+                    po.yumdb_info.tsflag_noscripts = 'true'
1f1d7d
+                if 'notriggers' in self.conf.tsflags:
1f1d7d
+                    po.yumdb_info.tsflag_notriggers = 'true'
1f1d7d
+
1f1d7d
                 if hasattr(self, 'args') and self.args:
1f1d7d
                     po.yumdb_info.command_line = ' '.join(self.args)
1f1d7d
                 elif hasattr(self, 'cmds') and self.cmds:
1f1d7d
commit 598b2f64f06dc625fca3e5a3b9ef0000f973eb7f
1f1d7d
Author: James Antill <james@and.org>
1f1d7d
Date:   Wed Feb 12 16:07:40 2014 -0500
1f1d7d
1f1d7d
    Add _writeRawConfigFile() so we can change yum.conf values.
1f1d7d
1f1d7d
diff --git a/yum/config.py b/yum/config.py
1f1d7d
index 09a4dcc..f213fc1 100644
1f1d7d
--- a/yum/config.py
1f1d7d
+++ b/yum/config.py
1f1d7d
@@ -1301,6 +1301,48 @@ def writeRawRepoFile(repo,only=None):
1f1d7d
     fp.write(str(ini))
1f1d7d
     fp.close()
1f1d7d
 
1f1d7d
+# Copied from yum-config-manager ... how we alter yu.conf ... used in "yum fs"
1f1d7d
+def _writeRawConfigFile(filename, section_id, yumvar,
1f1d7d
+                        cfgoptions, items, optionobj,
1f1d7d
+                        only=None):
1f1d7d
+    """
1f1d7d
+    From writeRawRepoFile, but so we can alter [main] too.
1f1d7d
+    """
1f1d7d
+    ini = INIConfig(open(filename))
1f1d7d
+
1f1d7d
+    osection_id = section_id
1f1d7d
+    # b/c repoids can have $values in them we need to map both ways to figure
1f1d7d
+    # out which one is which
1f1d7d
+    if section_id not in ini._sections:
1f1d7d
+        for sect in ini._sections.keys():
1f1d7d
+            if varReplace(sect, yumvar) == section_id:
1f1d7d
+                section_id = sect
1f1d7d
+
1f1d7d
+    # Updated the ConfigParser with the changed values
1f1d7d
+    cfgOptions = cfgoptions(osection_id)
1f1d7d
+    for name,value in items():
1f1d7d
+        if value is None: # Proxy
1f1d7d
+            continue
1f1d7d
+
1f1d7d
+        if only is not None and name not in only:
1f1d7d
+            continue
1f1d7d
+
1f1d7d
+        option = optionobj(name)
1f1d7d
+        ovalue = option.tostring(value)
1f1d7d
+        #  If the value is the same, but just interpreted ... when we don't want
1f1d7d
+        # to keep the interpreted values.
1f1d7d
+        if (name in ini[section_id] and
1f1d7d
+            ovalue == varReplace(ini[section_id][name], yumvar)):
1f1d7d
+            ovalue = ini[section_id][name]
1f1d7d
+
1f1d7d
+        if name not in cfgOptions and option.default == value:
1f1d7d
+            continue
1f1d7d
+
1f1d7d
+        ini[section_id][name] = ovalue
1f1d7d
+    fp =file(filename, "w")
1f1d7d
+    fp.write(str(ini))
1f1d7d
+    fp.close()
1f1d7d
+
1f1d7d
 #def main():
1f1d7d
 #    mainconf = readMainConfig(readStartupConfig('/etc/yum/yum.conf', '/'))
1f1d7d
 #    print mainconf.cachedir
1f1d7d
commit 6a415f0b18c0533dfdc97fdab3306ec8ccebb52d
1f1d7d
Author: James Antill <james@and.org>
1f1d7d
Date:   Wed Feb 12 16:55:45 2014 -0500
1f1d7d
1f1d7d
    Add fs sub-command and docs. Mostly for small installroot creation.
1f1d7d
1f1d7d
diff --git a/cli.py b/cli.py
1f1d7d
index eed63a2..7173688 100755
1f1d7d
--- a/cli.py
1f1d7d
+++ b/cli.py
1f1d7d
@@ -112,6 +112,7 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
1f1d7d
         self.registerCommand(yumcommands.UpdateinfoCommand())
1f1d7d
         self.registerCommand(yumcommands.UpdateMinimalCommand())
1f1d7d
         self.registerCommand(yumcommands.FSSnapshotCommand())
1f1d7d
+        self.registerCommand(yumcommands.FSCommand())
1f1d7d
 
1f1d7d
     def registerCommand(self, command):
1f1d7d
         """Register a :class:`yumcommands.YumCommand` so that it can be called by
1f1d7d
diff --git a/docs/yum.8 b/docs/yum.8
1f1d7d
index c9b529e..31c1c88 100644
1f1d7d
--- a/docs/yum.8
1f1d7d
+++ b/docs/yum.8
1f1d7d
@@ -86,6 +86,8 @@ gnome\-packagekit application\&.
1f1d7d
 .br
1f1d7d
 .I \fR * fssnapshot [summary | list | have-space | create | delete]
1f1d7d
 .br
1f1d7d
+.I \fR * fs [filters | refilter | refilter-cleanup | du]
1f1d7d
+.br
1f1d7d
 .I \fR * check
1f1d7d
 .br 
1f1d7d
 .I \fR * help [command] 
1f1d7d
@@ -718,6 +720,36 @@ then you can create and delete snapshots using:
1f1d7d
 Configuration Options: \fBfssnap_automatic_pre\fP, \fBfssnap_automatic_post\fP, \fBfssnap_automatic_keep\fP, \fBfssnap_percentage\fP, \fBfssnap_devices\fP
1f1d7d
 
1f1d7d
 .IP
1f1d7d
+.IP "\fBfs\fP"
1f1d7d
+This command has a few sub-commands to act on the filesystem data of the host,
1f1d7d
+mainly for removing languages/documentation for minimal installs:
1f1d7d
+
1f1d7d
+.br 
1f1d7d
+.I \fR yum fs filters
1f1d7d
+
1f1d7d
+.br 
1f1d7d
+.I \fR yum fs filter languages en:es
1f1d7d
+
1f1d7d
+.br 
1f1d7d
+.I \fR yum fs filter documentation
1f1d7d
+
1f1d7d
+.br 
1f1d7d
+.I \fR yum fs refilter [package(s)]
1f1d7d
+
1f1d7d
+.br 
1f1d7d
+.I \fR yum fs refilter-cleanup [package(s)]
1f1d7d
+
1f1d7d
+.br 
1f1d7d
+.I \fR yum fs du [path]
1f1d7d
+
1f1d7d
+the first 3 being a simple interface to change yum.conf altering the tsflags
1f1d7d
+and override_install_langs configurations. The refilter command is an optimized
1f1d7d
+way of calling "yum reinstall" to reinstall the packages with the new filters
1f1d7d
+applied. The refilter-cleanup command is needed because rpm doesn't actually
1f1d7d
+remove the files on reinstall, as it should. And the du command is included so
1f1d7d
+you can easily see the space used/saved.
1f1d7d
+
1f1d7d
+.IP
1f1d7d
 .IP "\fBcheck\fP"
1f1d7d
 Checks the local rpmdb and produces information on any problems it finds. You
1f1d7d
 can pass the check command the arguments "dependencies", "duplicates", "obsoletes" or "provides",
1f1d7d
diff --git a/docs/yum.conf.5 b/docs/yum.conf.5
1f1d7d
index bf3c442..4ec7689 100644
1f1d7d
--- a/docs/yum.conf.5
1f1d7d
+++ b/docs/yum.conf.5
1f1d7d
@@ -327,12 +327,14 @@ with newer rpm versions.
1f1d7d
 You can set all/any of them. However, if you don't know what these do in the
1f1d7d
 context of an rpm transaction set you're best leaving it alone. Default is
1f1d7d
 an empty list.
1f1d7d
+Also see the "yum fs" command, for excluding docs.
1f1d7d
 
1f1d7d
 .IP
1f1d7d
 \fBoverride_install_langs\fR
1f1d7d
 This is a way to override rpm's _install_langs macro. without having to change
1f1d7d
 it within rpm's macro file.
1f1d7d
 Default is nothing (so does nothing).
1f1d7d
+Also see the "yum fs" command.
1f1d7d
 
1f1d7d
 .IP
1f1d7d
 \fBrecent\fR
1f1d7d
diff --git a/yumcommands.py b/yumcommands.py
1f1d7d
index 4214383..03450c4 100644
1f1d7d
--- a/yumcommands.py
1f1d7d
+++ b/yumcommands.py
1f1d7d
@@ -4291,3 +4291,457 @@ class FSSnapshotCommand(YumCommand):
1f1d7d
             print msg % (len(snaps), base.format_number(used), len(dev_oris))
1f1d7d
 
1f1d7d
         return 0, [basecmd + ' ' + subcommand + ' done']
1f1d7d
+
1f1d7d
+
1f1d7d
+class FSCommand(YumCommand):
1f1d7d
+    def getNames(self):
1f1d7d
+        return ['fs']
1f1d7d
+
1f1d7d
+    def getUsage(self):
1f1d7d
+        return "[]"
1f1d7d
+
1f1d7d
+    def getSummary(self):
1f1d7d
+        return _("Creates filesystem snapshots, or lists/deletes current snapshots.")
1f1d7d
+
1f1d7d
+    def doCheck(self, base, basecmd, extcmds):
1f1d7d
+        """Verify that conditions are met so that this command can run.
1f1d7d
+        These include that the program is being run by the root user,
1f1d7d
+        that there are enabled repositories with gpg keys, and that
1f1d7d
+        this command is called with appropriate arguments.
1f1d7d
+
1f1d7d
+        :param base: a :class:`yum.Yumbase` object
1f1d7d
+        :param basecmd: the name of the command
1f1d7d
+        :param extcmds: the command line arguments passed to *basecmd*
1f1d7d
+        """
1f1d7d
+        checkRootUID(base)
1f1d7d
+
1f1d7d
+    def _fs_pkg_walk(self, pkgs, prefix, modified=False, verbose=False):
1f1d7d
+
1f1d7d
+        pfr = {'norm' : {},
1f1d7d
+               'mod' : {},
1f1d7d
+               'ghost' : {},
1f1d7d
+               'miss' : {},
1f1d7d
+               'not' : {}
1f1d7d
+               }
1f1d7d
+
1f1d7d
+        def quick_match(pkgs):
1f1d7d
+            for pkg in pkgs:
1f1d7d
+                for fname in pkg.filelist + pkg.dirlist:
1f1d7d
+                    if not fname.startswith(prefix):
1f1d7d
+                        continue
1f1d7d
+                    pfr['norm'][fname] = pkg
1f1d7d
+                for fname in pkg.ghostlist:
1f1d7d
+                    if not fname.startswith(prefix):
1f1d7d
+                        continue
1f1d7d
+                    pfr['ghost'][fname] = pkg
1f1d7d
+            return pfr
1f1d7d
+
1f1d7d
+        def _quick_match_iter(pkgs):
1f1d7d
+            # Walking the fi information is much slower than filelist/dirlist
1f1d7d
+            for pkg in pkgs:
1f1d7d
+                found = False
1f1d7d
+                for fname in pkg.dirlist:
1f1d7d
+                    if fname.startswith(prefix):
1f1d7d
+                        yield pkg
1f1d7d
+                        found = True
1f1d7d
+                        break
1f1d7d
+                if found:
1f1d7d
+                    continue
1f1d7d
+                for fname in pkg.filelist:
1f1d7d
+                    if fname.startswith(prefix):
1f1d7d
+                        yield pkg
1f1d7d
+                        found = True
1f1d7d
+                        break
1f1d7d
+                if found:
1f1d7d
+                    continue
1f1d7d
+                for fname in pkg.ghostlist:
1f1d7d
+                    if fname.startswith(prefix):
1f1d7d
+                        yield pkg
1f1d7d
+                        break
1f1d7d
+
1f1d7d
+        def verify_match(pkgs):
1f1d7d
+            _pfs = []
1f1d7d
+            def scoop_pfs(pfs):
1f1d7d
+                _pfs.append(pfs)
1f1d7d
+
1f1d7d
+                if not modified:
1f1d7d
+                    return []
1f1d7d
+
1f1d7d
+                return pfs
1f1d7d
+
1f1d7d
+            if prefix != '/':
1f1d7d
+                pkgs = _quick_match_iter(pkgs)
1f1d7d
+            for pkg in pkgs:
1f1d7d
+                _pfs = []
1f1d7d
+                probs = pkg.verify(patterns=[prefix+'*'], fake_problems=False,
1f1d7d
+                                   callback=scoop_pfs)
1f1d7d
+
1f1d7d
+                for pf in _pfs[0]:
1f1d7d
+                    if pf.filename in probs:
1f1d7d
+                        pfr['mod'][pf.filename] = pkg
1f1d7d
+                    elif pf.rpmfile_state == 'not installed':
1f1d7d
+                        pfr['not'][pf.filename] = pkg
1f1d7d
+                    elif 'ghost' in pf.rpmfile_types:
1f1d7d
+                        pfr['ghost'][pf.filename] = pkg
1f1d7d
+                    elif 'missing ok' in pf.rpmfile_types:
1f1d7d
+                        pfr['miss'][pf.filename] = pkg
1f1d7d
+                    else:
1f1d7d
+                        pfr['norm'][pf.filename] = pkg
1f1d7d
+            return pfr
1f1d7d
+
1f1d7d
+        # return quick_match(pkgs)
1f1d7d
+        return verify_match(pkgs)
1f1d7d
+
1f1d7d
+    def _fs_du(self, base, extcmds):
1f1d7d
+        def _dir_prefixes(path):
1f1d7d
+            while path != '/':
1f1d7d
+                path = os.path.dirname(path)
1f1d7d
+                yield path
1f1d7d
+
1f1d7d
+        def loc_num(x):
1f1d7d
+            """ String of a number in the readable "locale" format. """
1f1d7d
+            return locale.format("%d", int(x), True)
1f1d7d
+
1f1d7d
+        data = {'pkgs_size' : {},
1f1d7d
+                'pkgs_not_size' : {},
1f1d7d
+                'pkgs_ghost_size' : {},
1f1d7d
+                'pkgs_miss_size' : {},
1f1d7d
+                'pkgs_mod_size' : {},
1f1d7d
+
1f1d7d
+                'pres_size' : {},
1f1d7d
+                'data_size' : {},
1f1d7d
+                'data_not_size' : {},
1f1d7d
+
1f1d7d
+                'pkgs_count' : 0,
1f1d7d
+                'pkgs_not_count' : 0,
1f1d7d
+                'pkgs_ghost_count' : 0,
1f1d7d
+                'pkgs_miss_count' : 0,
1f1d7d
+                'pkgs_mod_count' : 0,
1f1d7d
+
1f1d7d
+                'data_count' : 0} # data_not_count == pkgs_not_count
1f1d7d
+
1f1d7d
+        def _add_size(d, v, size):
1f1d7d
+            if v not in d:
1f1d7d
+                d[v] = 0
1f1d7d
+            d[v] += size
1f1d7d
+
1f1d7d
+        def deal_with_file(fpath, need_prefix=True):
1f1d7d
+            size = os.path.getsize(fpath)
1f1d7d
+            if fpath in pfr['norm']:
1f1d7d
+                data['pkgs_count'] += size
1f1d7d
+                _add_size(data['pkgs_size'], pfr['norm'][fpath], size)
1f1d7d
+            elif fpath in pfr['ghost']:
1f1d7d
+                data['pkgs_ghost_count'] += size
1f1d7d
+                _add_size(data['pkgs_ghost_size'], pfr['ghost'][fpath], size)
1f1d7d
+            elif fpath in pfr['not']:
1f1d7d
+                data['pkgs_not_count'] += size
1f1d7d
+                _add_size(data['pkgs_not_size'], pfr['not'][fpath], size)
1f1d7d
+                data['data_not_size'][fpath] = size
1f1d7d
+            elif fpath in pfr['miss']:
1f1d7d
+                data['pkgs_miss_count'] += size
1f1d7d
+                _add_size(data['pkgs_miss_size'], pfr['miss'][fpath], size)
1f1d7d
+            elif fpath in pfr['mod']:
1f1d7d
+                data['pkgs_mod_count'] += size
1f1d7d
+                _add_size(data['pkgs_mod_size'], pfr['mod'][fpath], size)
1f1d7d
+            elif need_prefix and False:
1f1d7d
+                for fpre_path in _dir_prefixes(fpath):
1f1d7d
+                    if fpre_path not in pkg_files:
1f1d7d
+                        continue
1f1d7d
+                    _add_size(data['pres_size'], pkg_files[fpre_path], size)
1f1d7d
+                    break
1f1d7d
+                data['data_count'] += size
1f1d7d
+                data['data_size'][fpath] = size
1f1d7d
+            else:
1f1d7d
+                data['data_count'] += size
1f1d7d
+                data['data_size'][fpath] = size
1f1d7d
+
1f1d7d
+        prefix = "."
1f1d7d
+        if extcmds:
1f1d7d
+            prefix = extcmds[0]
1f1d7d
+            extcmds = extcmds[1:]
1f1d7d
+
1f1d7d
+        if not os.path.exists(prefix):
1f1d7d
+            return 1, [_('No such file or directory: ' + prefix)]
1f1d7d
+
1f1d7d
+        max_show_len = 4
1f1d7d
+        if extcmds:
1f1d7d
+            try:
1f1d7d
+                max_show_len = int(extcmds[0])
1f1d7d
+            except:
1f1d7d
+                pass
1f1d7d
+
1f1d7d
+        verbose = base.verbose_logger.isEnabledFor(logginglevels.DEBUG_3)
1f1d7d
+
1f1d7d
+        pfr = self._fs_pkg_walk(base.rpmdb, prefix, verbose=verbose)
1f1d7d
+
1f1d7d
+        base.closeRpmDB() # C-c ftw.
1f1d7d
+
1f1d7d
+        num = 0
1f1d7d
+        if os.path.isfile(prefix):
1f1d7d
+            num += 1
1f1d7d
+            deal_with_file(prefix)
1f1d7d
+
1f1d7d
+        for root, dirs, files in os.walk(prefix):
1f1d7d
+            for fname in files:
1f1d7d
+                num += 1
1f1d7d
+                fpath = os.path.normpath(root + '/' + fname)
1f1d7d
+                if os.path.islink(fpath):
1f1d7d
+                    continue
1f1d7d
+
1f1d7d
+                deal_with_file(fpath, need_prefix=verbose)
1f1d7d
+
1f1d7d
+        # output
1f1d7d
+        print "Files            :", loc_num(num)
1f1d7d
+        tot = 0
1f1d7d
+        tot += data['pkgs_count']
1f1d7d
+        tot += data['pkgs_ghost_count']
1f1d7d
+        tot += data['pkgs_not_count']
1f1d7d
+        tot += data['pkgs_miss_count']
1f1d7d
+        tot += data['pkgs_mod_count']
1f1d7d
+        tot += data['data_count']
1f1d7d
+        print "Total size       :", base.format_number(tot)
1f1d7d
+        if not tot:
1f1d7d
+            return
1f1d7d
+
1f1d7d
+        num = data['pkgs_count']
1f1d7d
+        if not verbose:
1f1d7d
+            num += data['pkgs_ghost_count']
1f1d7d
+            num += data['pkgs_miss_count']
1f1d7d
+            num += data['pkgs_mod_count']
1f1d7d
+        print "       Pkgs size :", "%-5s" % base.format_number(num),
1f1d7d
+        print "(%3.0f%%)" % ((num * 100.0) / tot)
1f1d7d
+        if verbose:
1f1d7d
+            for (title, num) in ((_(" Ghost pkgs size :"),
1f1d7d
+                                  data['pkgs_ghost_count']),
1f1d7d
+                                 (_(" Not pkgs size :"),
1f1d7d
+                                  data['pkgs_not_count']),
1f1d7d
+                                 (_(" Miss pkgs size :"),
1f1d7d
+                                  data['pkgs_miss_count']),
1f1d7d
+                                 (_(" Mod. pkgs size :"),
1f1d7d
+                                  data['pkgs_mod_count'])):
1f1d7d
+                if not num:
1f1d7d
+                    continue
1f1d7d
+                print title, "%-5s" % base.format_number(num),
1f1d7d
+                print "(%3.0f%%)" % ((num * 100.0) / tot)
1f1d7d
+        num = data['data_count']
1f1d7d
+        if not verbose:
1f1d7d
+            num += data['pkgs_not_count']
1f1d7d
+        print _("       Data size :"), "%-5s" % base.format_number(num),
1f1d7d
+        print "(%3.0f%%)" % ((num * 100.0) / tot)
1f1d7d
+        if verbose:
1f1d7d
+            print ''
1f1d7d
+            print _("Pkgs       :"), loc_num(len(data['pkgs_size']))
1f1d7d
+            print _("Ghost Pkgs :"), loc_num(len(data['pkgs_ghost_size']))
1f1d7d
+            print _("Not Pkgs   :"), loc_num(len(data['pkgs_not_size']))
1f1d7d
+            print _("Miss. Pkgs :"), loc_num(len(data['pkgs_miss_size']))
1f1d7d
+            print _("Mod. Pkgs  :"), loc_num(len(data['pkgs_mod_size']))
1f1d7d
+
1f1d7d
+        def _pkgs(p_size, msg):
1f1d7d
+            tot = min(max_show_len, len(p_size))
1f1d7d
+            if tot:
1f1d7d
+                print ''
1f1d7d
+                print msg % tot
1f1d7d
+            num = 0
1f1d7d
+            for pkg in sorted(p_size, key=lambda x: p_size[x], reverse=True):
1f1d7d
+                num += 1
1f1d7d
+                print _("%*d. %60s %-5s") % (len(str(tot)), num, pkg,
1f1d7d
+                                             base.format_number(p_size[pkg]))
1f1d7d
+                if num >= tot:
1f1d7d
+                    break
1f1d7d
+
1f1d7d
+        if verbose:
1f1d7d
+            _pkgs(data['pkgs_size'], _('Top %d packages:'))
1f1d7d
+            _pkgs(data['pkgs_ghost_size'], _('Top %d ghost packages:'))
1f1d7d
+            _pkgs(data['pkgs_not_size'], _('Top %d not. packages:'))
1f1d7d
+            _pkgs(data['pkgs_miss_size'], _('Top %d miss packages:'))
1f1d7d
+            _pkgs(data['pkgs_mod_size'], _('Top %d mod. packages:'))
1f1d7d
+            _pkgs(data['pres_size'], _('Top %d prefix packages:'))
1f1d7d
+        else:
1f1d7d
+            tmp = {}
1f1d7d
+            tmp.update(data['pkgs_size'])
1f1d7d
+            for d in data['pkgs_ghost_size']:
1f1d7d
+                _add_size(tmp, d, data['pkgs_ghost_size'][d])
1f1d7d
+            for d in data['pkgs_miss_size']:
1f1d7d
+                _add_size(tmp, d, data['pkgs_miss_size'][d])
1f1d7d
+            for d in data['pkgs_mod_size']:
1f1d7d
+                _add_size(tmp, d, data['pkgs_mod_size'][d])
1f1d7d
+            _pkgs(tmp, _('Top %d packages:'))
1f1d7d
+
1f1d7d
+        print ''
1f1d7d
+        if verbose:
1f1d7d
+            data_size = data['data_size']
1f1d7d
+        else:
1f1d7d
+            data_size = {}
1f1d7d
+            data_size.update(data['data_size'])
1f1d7d
+            data_size.update(data['data_not_size'])
1f1d7d
+
1f1d7d
+        tot = min(max_show_len, len(data_size))
1f1d7d
+        if tot:
1f1d7d
+            print _('Top %d non-package files:') % tot
1f1d7d
+        num = 0
1f1d7d
+        for fname in sorted(data_size,
1f1d7d
+                            key=lambda x: data_size[x],
1f1d7d
+                            reverse=True):
1f1d7d
+            num += 1
1f1d7d
+            dsznum = data_size[fname]
1f1d7d
+            print _("%*d. %60s %-5s") % (len(str(tot)), num, fname,
1f1d7d
+                                         base.format_number(dsznum))
1f1d7d
+            if num >= tot:
1f1d7d
+                break
1f1d7d
+
1f1d7d
+    def _fs_filters(self, base, extcmds):
1f1d7d
+        writeRawConfigFile = yum.config._writeRawConfigFile
1f1d7d
+
1f1d7d
+        if not extcmds:
1f1d7d
+            oil = base.conf.override_install_langs
1f1d7d
+            if not oil:
1f1d7d
+                oil = "rpm: " + rpm.expandMacro("%_install_langs")
1f1d7d
+            print "File system filters:"
1f1d7d
+            print "  Nodocs:", 'nodocs' in base.conf.tsflags
1f1d7d
+            print "  Languages:", oil
1f1d7d
+        elif extcmds[0] in ('docs', 'nodocs',
1f1d7d
+                            'documentation', 'nodocumentation'):
1f1d7d
+            c_f = 'nodocs' in base.conf.tsflags
1f1d7d
+            n_f = extcmds[0].startswith('no')
1f1d7d
+            if n_f == c_f:
1f1d7d
+                return
1f1d7d
+
1f1d7d
+            nts = base.conf.tsflags
1f1d7d
+            if n_f:
1f1d7d
+                nts = nts + ['nodocs']
1f1d7d
+            else:
1f1d7d
+                nts = [x for x in nts if x != 'nodocs']
1f1d7d
+            base.conf.tsflags = " ".join(nts)
1f1d7d
+
1f1d7d
+            fn = '/etc/yum/yum.conf'
1f1d7d
+            if not os.path.exists(fn):
1f1d7d
+                # Try the old default
1f1d7d
+                fn = '/etc/yum.conf'
1f1d7d
+            ybc = base.conf
1f1d7d
+            writeRawConfigFile(fn, 'main', ybc.yumvar,
1f1d7d
+                               ybc.cfg.options, ybc.iteritems,
1f1d7d
+                               ybc.optionobj,
1f1d7d
+                               only=['tsflags'])
1f1d7d
+        elif extcmds[0] in ('langs', 'nolangs', 'lang', 'nolang',
1f1d7d
+                            'languages', 'nolanguages',
1f1d7d
+                            'language', 'nolanguage'):
1f1d7d
+            if extcmds[0].startswith('no') or len(extcmds) < 2 or 'all' in extcmds:
1f1d7d
+                val = 'all'
1f1d7d
+            else:
1f1d7d
+                val = ":".join(extcmds[1:])
1f1d7d
+
1f1d7d
+            if val == base.conf.override_install_langs:
1f1d7d
+                return
1f1d7d
+
1f1d7d
+            base.conf.override_install_langs = val
1f1d7d
+
1f1d7d
+            fn = '/etc/yum/yum.conf'
1f1d7d
+            if not os.path.exists(fn):
1f1d7d
+                # Try the old default
1f1d7d
+                fn = '/etc/yum.conf'
1f1d7d
+            ybc = base.conf
1f1d7d
+            writeRawConfigFile(fn, 'main', ybc.yumvar,
1f1d7d
+                               ybc.cfg.options, ybc.iteritems,
1f1d7d
+                               ybc.optionobj,
1f1d7d
+                               only=['override_install_langs'])
1f1d7d
+        else:
1f1d7d
+            return 1, [_('Not a valid sub-command of fs filter')]
1f1d7d
+
1f1d7d
+    def _fs_refilter(self, base, extcmds):
1f1d7d
+        c_f = 'nodocs' in base.conf.tsflags
1f1d7d
+        # FIXME: C&P from init.
1f1d7d
+        oil = base.conf.override_install_langs
1f1d7d
+        if not oil:
1f1d7d
+            oil = rpm.expandMacro("%_install_langs")
1f1d7d
+        if oil == 'all':
1f1d7d
+            oil = ''
1f1d7d
+        elif oil:
1f1d7d
+            oil = ":".join(sorted(oil.split(':')))
1f1d7d
+
1f1d7d
+        found = False
1f1d7d
+        num = 0
1f1d7d
+        for pkg in base.rpmdb.returnPackages(patterns=extcmds):
1f1d7d
+            if False: pass
1f1d7d
+            elif oil != pkg.yumdb_info.get('ts_install_langs', ''):
1f1d7d
+                txmbrs = base.reinstall(po=pkg)
1f1d7d
+                num += len(txmbrs)
1f1d7d
+            elif c_f != ('true' == pkg.yumdb_info.get('tsflag_nodocs')):
1f1d7d
+                txmbrs = base.reinstall(po=pkg)
1f1d7d
+                num += len(txmbrs)
1f1d7d
+            else:
1f1d7d
+                found = True
1f1d7d
+
1f1d7d
+        if num:
1f1d7d
+            return 2,P_('%d package to reinstall','%d packages to reinstall',
1f1d7d
+                        num)
1f1d7d
+
1f1d7d
+        if not found:
1f1d7d
+            return 1, [_('No valid packages: %s') % " ".join(extcmds)]
1f1d7d
+
1f1d7d
+    def _fs_refilter_cleanup(self, base, extcmds):
1f1d7d
+        pkgs = base.rpmdb.returnPackages(patterns=extcmds)
1f1d7d
+
1f1d7d
+        verbose = base.verbose_logger.isEnabledFor(logginglevels.DEBUG_3)
1f1d7d
+
1f1d7d
+        pfr = self._fs_pkg_walk(pkgs, "/", verbose=verbose, modified=True)
1f1d7d
+
1f1d7d
+        base.closeRpmDB() # C-c ftw.
1f1d7d
+
1f1d7d
+        for fname in sorted(pfr['not']):
1f1d7d
+            print _('Removing:'), fname
1f1d7d
+            misc.unlink_f(fname)
1f1d7d
+
1f1d7d
+    def _fs_diff(self, base, extcmds):
1f1d7d
+        pass
1f1d7d
+    def _fs_status(self, base, extcmds):
1f1d7d
+        pass
1f1d7d
+
1f1d7d
+    def doCommand(self, base, basecmd, extcmds):
1f1d7d
+        """Execute this command.
1f1d7d
+
1f1d7d
+        :param base: a :class:`yum.Yumbase` object
1f1d7d
+        :param basecmd: the name of the command
1f1d7d
+        :param extcmds: the command line arguments passed to *basecmd*
1f1d7d
+        :return: (exit_code, [ errors ])
1f1d7d
+
1f1d7d
+        exit_code is::
1f1d7d
+
1f1d7d
+            0 = we're done, exit
1f1d7d
+            1 = we've errored, exit with error string
1f1d7d
+            2 = we've got work yet to do, onto the next stage
1f1d7d
+        """
1f1d7d
+        if extcmds and extcmds[0] in ('filters', 'filter',
1f1d7d
+                                      'refilter', 'refilter-cleanup',
1f1d7d
+                                      'du', 'status', 'diff'):
1f1d7d
+            subcommand = extcmds[0]
1f1d7d
+            extcmds = extcmds[1:]
1f1d7d
+        else:
1f1d7d
+            subcommand = 'filters'
1f1d7d
+
1f1d7d
+        if False: pass
1f1d7d
+
1f1d7d
+        elif subcommand == 'du':
1f1d7d
+            ret = self._fs_du(base, extcmds)
1f1d7d
+
1f1d7d
+        elif subcommand in ('filter', 'filters'):
1f1d7d
+            ret = self._fs_filters(base, extcmds)
1f1d7d
+
1f1d7d
+        elif subcommand == 'refilter':
1f1d7d
+            ret = self._fs_refilter(base, extcmds)
1f1d7d
+
1f1d7d
+        elif subcommand == 'refilter-cleanup':
1f1d7d
+            ret = self._fs_refilter_cleanup(base, extcmds)
1f1d7d
+
1f1d7d
+        elif False and subcommand == 'diff':
1f1d7d
+            ret = self._fs_diff(base, extcmds)
1f1d7d
+
1f1d7d
+        elif False and subcommand == 'status':
1f1d7d
+            ret = self._fs_status(base, extcmds)
1f1d7d
+
1f1d7d
+        else:
1f1d7d
+            return 1, [_('Not a valid sub-command of %s') % basecmd]
1f1d7d
+
1f1d7d
+        if ret is not None:
1f1d7d
+            return ret
1f1d7d
+
1f1d7d
+        return 0, [basecmd + ' ' + subcommand + ' done']
1f1d7d
commit 5dd124173de6c9ac1ce53b507f9aaa9cae6d030a
1f1d7d
Author: James Antill <james@and.org>
1f1d7d
Date:   Wed Feb 12 16:56:33 2014 -0500
1f1d7d
1f1d7d
    Optimize pkg.verify() for "fs du" and "fs refilter".
1f1d7d
1f1d7d
diff --git a/yum/packages.py b/yum/packages.py
1f1d7d
index cc1f1e3..1b3061b 100644
1f1d7d
--- a/yum/packages.py
1f1d7d
+++ b/yum/packages.py
1f1d7d
@@ -1779,6 +1779,7 @@ class YUMVerifyPackage:
1f1d7d
         self._files = {}
1f1d7d
 
1f1d7d
 
1f1d7d
+_last_fnmatch = {}
1f1d7d
 class _RPMVerifyPackage(YUMVerifyPackage):
1f1d7d
     def __init__(self, po, fi, def_csum_type, patterns, all):
1f1d7d
         YUMVerifyPackage.__init__(self, po)
1f1d7d
@@ -1791,18 +1792,30 @@ class _RPMVerifyPackage(YUMVerifyPackage):
1f1d7d
         (fi, def_csum_type, patterns, all) = self._presetup
1f1d7d
         del self._presetup
1f1d7d
 
1f1d7d
+        global _last_fnmatch
1f1d7d
+        _this_fnmatch = {}
1f1d7d
         for ft in fi:
1f1d7d
             fn = ft[0]
1f1d7d
             if patterns:
1f1d7d
                 matched = False
1f1d7d
                 for p in patterns:
1f1d7d
-                    if fnmatch.fnmatch(fn, p):
1f1d7d
+                    if p in _last_fnmatch:
1f1d7d
+                        match = _last_fnmatch[p]
1f1d7d
+                    elif p in _this_fnmatch:
1f1d7d
+                        match = _this_fnmatch[p]
1f1d7d
+                    else:
1f1d7d
+                        match = misc.compile_pattern(p)
1f1d7d
+                    _this_fnmatch[p] = match
1f1d7d
+
1f1d7d
+                    if match(fn):
1f1d7d
                         matched = True
1f1d7d
                         break
1f1d7d
                 if not matched: 
1f1d7d
                     continue
1f1d7d
 
1f1d7d
             self.add(_RPMVerifyPackageFile(fi, ft, def_csum_type, all))
1f1d7d
+        if _this_fnmatch:
1f1d7d
+            _last_fnmatch = _this_fnmatch
1f1d7d
 
1f1d7d
     def __contains__(self, *args, **kwargs):
1f1d7d
         self._setup()
1f1d7d
@@ -1834,7 +1847,8 @@ class YumInstalledPackage(YumHeaderPackage):
1f1d7d
             self.yumdb_info = yumdb.get_package(self)
1f1d7d
 
1f1d7d
     def verify(self, patterns=[], deps=False, script=False,
1f1d7d
-               fake_problems=True, all=False, fast=False, callback=None):
1f1d7d
+               fake_problems=True, all=False, fast=False, callback=None,
1f1d7d
+               failfast=False):
1f1d7d
         """verify that the installed files match the packaged checksum
1f1d7d
            optionally verify they match only if they are in the 'pattern' list
1f1d7d
            returns a tuple """
1f1d7d
@@ -1973,6 +1987,8 @@ class YumInstalledPackage(YumHeaderPackage):
1f1d7d
                 verify_digest = pf.verify_digest
1f1d7d
                 if fast and not problems and (my_st_size == pf.size):
1f1d7d
                     verify_digest = False
1f1d7d
+                if failfast and problems:
1f1d7d
+                    verify_digest = False
1f1d7d
                 if not pf.digest:
1f1d7d
                     verify_digest = False
1f1d7d
 
1f1d7d
diff --git a/yumcommands.py b/yumcommands.py
1f1d7d
index 03450c4..c5abfba 100644
1f1d7d
--- a/yumcommands.py
1f1d7d
+++ b/yumcommands.py
1f1d7d
@@ -4374,7 +4374,7 @@ class FSCommand(YumCommand):
1f1d7d
             for pkg in pkgs:
1f1d7d
                 _pfs = []
1f1d7d
                 probs = pkg.verify(patterns=[prefix+'*'], fake_problems=False,
1f1d7d
-                                   callback=scoop_pfs)
1f1d7d
+                                   callback=scoop_pfs, failfast=True)
1f1d7d
 
1f1d7d
                 for pf in _pfs[0]:
1f1d7d
                     if pf.filename in probs:
1f1d7d
commit 6e4a68cf40283f3a110c049d5e81db886ef593e1
1f1d7d
Author: James Antill <james@and.org>
1f1d7d
Date:   Wed Feb 12 17:56:42 2014 -0500
1f1d7d
1f1d7d
    Add the fs status/diff commands.
1f1d7d
1f1d7d
diff --git a/docs/yum.8 b/docs/yum.8
1f1d7d
index 31c1c88..6794581 100644
1f1d7d
--- a/docs/yum.8
1f1d7d
+++ b/docs/yum.8
1f1d7d
@@ -742,12 +742,19 @@ mainly for removing languages/documentation for minimal installs:
1f1d7d
 .br 
1f1d7d
 .I \fR yum fs du [path]
1f1d7d
 
1f1d7d
+.br 
1f1d7d
+.I \fR yum fs status [path]
1f1d7d
+
1f1d7d
+.br 
1f1d7d
+.I \fR yum fs diff [path]
1f1d7d
+
1f1d7d
+
1f1d7d
 the first 3 being a simple interface to change yum.conf altering the tsflags
1f1d7d
 and override_install_langs configurations. The refilter command is an optimized
1f1d7d
 way of calling "yum reinstall" to reinstall the packages with the new filters
1f1d7d
 applied. The refilter-cleanup command is needed because rpm doesn't actually
1f1d7d
-remove the files on reinstall, as it should. And the du command is included so
1f1d7d
-you can easily see the space used/saved.
1f1d7d
+remove the files on reinstall, as it should. And the du/status/diff commands are
1f1d7d
+included so you can easily see the space used/saved and any other changes.
1f1d7d
 
1f1d7d
 .IP
1f1d7d
 .IP "\fBcheck\fP"
1f1d7d
diff --git a/yumcommands.py b/yumcommands.py
1f1d7d
index c5abfba..b4e172c 100644
1f1d7d
--- a/yumcommands.py
1f1d7d
+++ b/yumcommands.py
1f1d7d
@@ -21,6 +21,7 @@ Classes for subcommands of the yum command line interface.
1f1d7d
 """
1f1d7d
 
1f1d7d
 import os
1f1d7d
+import sys
1f1d7d
 import cli
1f1d7d
 from yum import logginglevels
1f1d7d
 from yum import _, P_
1f1d7d
@@ -4692,9 +4693,112 @@ class FSCommand(YumCommand):
1f1d7d
             misc.unlink_f(fname)
1f1d7d
 
1f1d7d
     def _fs_diff(self, base, extcmds):
1f1d7d
-        pass
1f1d7d
+        def deal_with_file(fpath):
1f1d7d
+            if fpath in pfr['norm']:
1f1d7d
+                pass
1f1d7d
+            elif fpath in pfr['ghost']:
1f1d7d
+                pass
1f1d7d
+            elif fpath in pfr['not']:
1f1d7d
+                print >>sys.stderr, _('Not installed:'), fpath
1f1d7d
+            elif fpath in pfr['miss']:
1f1d7d
+                pass
1f1d7d
+            elif fpath in pfr['mod']:
1f1d7d
+                pkg = apkgs[pfr['mod'][fpath].pkgtup]
1f1d7d
+                # Hacky ... but works.
1f1d7d
+                sys.stdout.flush()
1f1d7d
+                extract_cmd = "cd %s; rpm2cpio %s | cpio --quiet -id .%s"
1f1d7d
+                extract_cmd =  extract_cmd % (tmpdir, pkg.localPkg(), fpath)
1f1d7d
+                os.system(extract_cmd)
1f1d7d
+                diff_cmd = "diff -ru %s %s" % (tmpdir + fpath, fpath)
1f1d7d
+                print diff_cmd
1f1d7d
+                sys.stdout.flush()
1f1d7d
+                os.system(diff_cmd)
1f1d7d
+            else:
1f1d7d
+                print >>sys.stderr, _('Not packaged?:'), fpath
1f1d7d
+
1f1d7d
+        prefix = "."
1f1d7d
+        if extcmds:
1f1d7d
+            prefix = extcmds[0]
1f1d7d
+            extcmds = extcmds[1:]
1f1d7d
+
1f1d7d
+        pkgs = base.rpmdb.returnPackages(patterns=extcmds)
1f1d7d
+
1f1d7d
+        verbose = base.verbose_logger.isEnabledFor(logginglevels.DEBUG_3)
1f1d7d
+
1f1d7d
+        pfr = self._fs_pkg_walk(pkgs, prefix, verbose=verbose, modified=True)
1f1d7d
+
1f1d7d
+        base.closeRpmDB() # C-c ftw.
1f1d7d
+
1f1d7d
+        apkgs = {}
1f1d7d
+        downloadpkgs = []
1f1d7d
+        for ipkg in set(pfr['mod'].values()):
1f1d7d
+            for apkg in base.pkgSack.searchPkgTuple(ipkg.pkgtup):
1f1d7d
+                iyi = ipkg.yumdb_info
1f1d7d
+                if ('checksum_type' in iyi and
1f1d7d
+                    'checksum_data' in iyi and
1f1d7d
+                    iyi.checksum_type == apkg.checksum_type and
1f1d7d
+                    iyi.checksum_data == apkg.pkgId):
1f1d7d
+                    apkgs[ipkg.pkgtup] = apkg
1f1d7d
+                    downloadpkgs.append(apkg)
1f1d7d
+                    break
1f1d7d
+            if ipkg.pkgtup not in apkgs:
1f1d7d
+                raise yum.Errors.YumBaseError, _("Can't find package: %s") %ipkg
1f1d7d
+
1f1d7d
+        if downloadpkgs:
1f1d7d
+            tmpdir = tempfile.mkdtemp()
1f1d7d
+            problems = base.downloadPkgs(downloadpkgs, callback_total=base.download_callback_total_cb) 
1f1d7d
+            if len(problems) > 0:
1f1d7d
+                errstring = ''
1f1d7d
+                errstring += _('Error downloading packages:\n')
1f1d7d
+                for key in problems:
1f1d7d
+                    errors = yum.misc.unique(problems[key])
1f1d7d
+                    for error in errors:
1f1d7d
+                        errstring += '  %s: %s\n' % (key, error)
1f1d7d
+                raise yum.Errors.YumBaseError, errstring
1f1d7d
+
1f1d7d
+        for root, dirs, files in os.walk(prefix):
1f1d7d
+            for fname in files:
1f1d7d
+                fpath = os.path.normpath(root + '/' + fname)
1f1d7d
+                if os.path.islink(fpath):
1f1d7d
+                    continue
1f1d7d
+
1f1d7d
+                deal_with_file(fpath)
1f1d7d
+
1f1d7d
     def _fs_status(self, base, extcmds):
1f1d7d
-        pass
1f1d7d
+        def deal_with_file(fpath):
1f1d7d
+            if fpath in pfr['norm']:
1f1d7d
+                pass
1f1d7d
+            elif fpath in pfr['ghost']:
1f1d7d
+                pass
1f1d7d
+            elif fpath in pfr['not']:
1f1d7d
+                print _('Not installed:'), fpath
1f1d7d
+            elif fpath in pfr['miss']:
1f1d7d
+                pass
1f1d7d
+            elif fpath in pfr['mod']:
1f1d7d
+                print _('Modified:'), fpath
1f1d7d
+            else:
1f1d7d
+                print _('Not packaged?:'), fpath
1f1d7d
+
1f1d7d
+        prefix = "."
1f1d7d
+        if extcmds:
1f1d7d
+            prefix = extcmds[0]
1f1d7d
+            extcmds = extcmds[1:]
1f1d7d
+
1f1d7d
+        pkgs = base.rpmdb.returnPackages(patterns=extcmds)
1f1d7d
+
1f1d7d
+        verbose = base.verbose_logger.isEnabledFor(logginglevels.DEBUG_3)
1f1d7d
+
1f1d7d
+        pfr = self._fs_pkg_walk(pkgs, prefix, verbose=verbose, modified=True)
1f1d7d
+
1f1d7d
+        base.closeRpmDB() # C-c ftw.
1f1d7d
+
1f1d7d
+        for root, dirs, files in os.walk(prefix):
1f1d7d
+            for fname in files:
1f1d7d
+                fpath = os.path.normpath(root + '/' + fname)
1f1d7d
+                if os.path.islink(fpath):
1f1d7d
+                    continue
1f1d7d
+
1f1d7d
+                deal_with_file(fpath)
1f1d7d
 
1f1d7d
     def doCommand(self, base, basecmd, extcmds):
1f1d7d
         """Execute this command.
1f1d7d
@@ -4732,10 +4836,10 @@ class FSCommand(YumCommand):
1f1d7d
         elif subcommand == 'refilter-cleanup':
1f1d7d
             ret = self._fs_refilter_cleanup(base, extcmds)
1f1d7d
 
1f1d7d
-        elif False and subcommand == 'diff':
1f1d7d
+        elif subcommand == 'diff':
1f1d7d
             ret = self._fs_diff(base, extcmds)
1f1d7d
 
1f1d7d
-        elif False and subcommand == 'status':
1f1d7d
+        elif subcommand == 'status':
1f1d7d
             ret = self._fs_status(base, extcmds)
1f1d7d
 
1f1d7d
         else:
1f1d7d
commit df42263f375b032b73d9732a8b051e57a35973ab
1f1d7d
Author: James Antill <james@and.org>
1f1d7d
Date:   Wed Feb 12 18:17:31 2014 -0500
1f1d7d
1f1d7d
    Move exactarchlist_default to ditro. variable.
1f1d7d
1f1d7d
diff --git a/yum/config.py b/yum/config.py
1f1d7d
index f213fc1..69f8e2e 100644
1f1d7d
--- a/yum/config.py
1f1d7d
+++ b/yum/config.py
1f1d7d
@@ -50,6 +50,10 @@ __main_multilib_policy_default__ = 'all'
1f1d7d
 __main_failovermethod_default__ = 'roundrobin'
1f1d7d
 __main_installonly_limit_default__ = 0
1f1d7d
 __group_command_default__ = 'compat'
1f1d7d
+__exactarchlist_default__ = ['kernel', 'kernel-smp',
1f1d7d
+                             'kernel-hugemem', 'kernel-enterprise',
1f1d7d
+                             'kernel-bigmem',
1f1d7d
+                             'kernel-devel', 'kernel-PAE', 'kernel-PAE-debug']
1f1d7d
 
1f1d7d
 class Option(object):
1f1d7d
     """
1f1d7d
@@ -764,9 +768,7 @@ class YumConf(StartupConf):
1f1d7d
                                           names_of_0=["0", "<off>"])
1f1d7d
     kernelpkgnames = ListOption(['kernel','kernel-smp', 'kernel-enterprise',
1f1d7d
             'kernel-bigmem', 'kernel-BOOT', 'kernel-PAE', 'kernel-PAE-debug'])
1f1d7d
-    exactarchlist = ListOption(['kernel', 'kernel-smp',
1f1d7d
-            'kernel-hugemem', 'kernel-enterprise', 'kernel-bigmem',
1f1d7d
-            'kernel-devel', 'kernel-PAE', 'kernel-PAE-debug'])
1f1d7d
+    exactarchlist = ListOption(__exactarchlist_default__)
1f1d7d
     tsflags = ListOption()
1f1d7d
     override_install_langs = Option()
1f1d7d
 
1f1d7d
commit 7e890388473519d8374e228783150f4e11dff3e0
1f1d7d
Author: James Antill <james@and.org>
1f1d7d
Date:   Wed Feb 12 18:59:42 2014 -0500
1f1d7d
1f1d7d
    Add override_install_langs to test.FakeConf.
1f1d7d
1f1d7d
diff --git a/test/testbase.py b/test/testbase.py
1f1d7d
index 9d331c6..e2a1d05 100644
1f1d7d
--- a/test/testbase.py
1f1d7d
+++ b/test/testbase.py
1f1d7d
@@ -66,6 +66,7 @@ class FakeConf(object):
1f1d7d
         self.reposdir = '/tmp/XXXX'
1f1d7d
         self.diskspacecheck = True
1f1d7d
         self.depsolve_loop_limit = 10
1f1d7d
+        self.override_install_langs = ''
1f1d7d
 
1f1d7d
 class FakeSack:
1f1d7d
     """ Fake PackageSack to use with FakeRepository"""
1f1d7d
commit 57e62d0ab105727689a2cbc690ff5d62137be676
1f1d7d
Author: James Antill <james@and.org>
1f1d7d
Date:   Fri Feb 14 14:58:31 2014 -0500
1f1d7d
1f1d7d
    Auto-enable repos. that contain packages we need in fs diff.
1f1d7d
1f1d7d
diff --git a/yumcommands.py b/yumcommands.py
1f1d7d
index b4e172c..475d982 100644
1f1d7d
--- a/yumcommands.py
1f1d7d
+++ b/yumcommands.py
1f1d7d
@@ -4732,8 +4732,14 @@ class FSCommand(YumCommand):
1f1d7d
         apkgs = {}
1f1d7d
         downloadpkgs = []
1f1d7d
         for ipkg in set(pfr['mod'].values()):
1f1d7d
+            iyi = ipkg.yumdb_info
1f1d7d
+            if 'from_repo' in iyi: # Updates-testing etc.
1f1d7d
+                if iyi.from_repo in base.repos.repos:
1f1d7d
+                    repo = base.repos.getRepo(iyi.from_repo)
1f1d7d
+                    if not repo.isEnabled():
1f1d7d
+                        base.repos.enableRepo(repo.id)
1f1d7d
+
1f1d7d
             for apkg in base.pkgSack.searchPkgTuple(ipkg.pkgtup):
1f1d7d
-                iyi = ipkg.yumdb_info
1f1d7d
                 if ('checksum_type' in iyi and
1f1d7d
                     'checksum_data' in iyi and
1f1d7d
                     iyi.checksum_type == apkg.checksum_type and
1f1d7d
commit 81b9dc2fc39ed6960f061cdc1c84f37aada0fd0a
1f1d7d
Author: James Antill <james@and.org>
1f1d7d
Date:   Fri Feb 14 15:02:58 2014 -0500
1f1d7d
1f1d7d
    Cleanup tmpdir for fs diff.
1f1d7d
1f1d7d
diff --git a/yumcommands.py b/yumcommands.py
1f1d7d
index 475d982..c93faa1 100644
1f1d7d
--- a/yumcommands.py
1f1d7d
+++ b/yumcommands.py
1f1d7d
@@ -33,6 +33,7 @@ import fnmatch
1f1d7d
 import time
1f1d7d
 from yum.i18n import utf8_width, utf8_width_fill, to_unicode, exception2msg
1f1d7d
 import tempfile
1f1d7d
+import shutil
1f1d7d
 import glob
1f1d7d
 
1f1d7d
 import yum.config
1f1d7d
@@ -4770,6 +4771,9 @@ class FSCommand(YumCommand):
1f1d7d
 
1f1d7d
                 deal_with_file(fpath)
1f1d7d
 
1f1d7d
+        if downloadpkgs:
1f1d7d
+            shutil.rmtree(tmpdir)
1f1d7d
+
1f1d7d
     def _fs_status(self, base, extcmds):
1f1d7d
         def deal_with_file(fpath):
1f1d7d
             if fpath in pfr['norm']:
1f1d7d
commit f932ddc40d8452c1a7d46d7c7fd8eb90b6f5cac2
1f1d7d
Author: James Antill <james@and.org>
1f1d7d
Date:   Fri Feb 21 16:15:01 2014 -0500
1f1d7d
1f1d7d
    Add spec requires for fs sub-command.
1f1d7d
1f1d7d
diff --git a/yum.spec b/yum.spec
1f1d7d
index 93cfa14..854baf3 100644
1f1d7d
--- a/yum.spec
1f1d7d
+++ b/yum.spec
1f1d7d
@@ -98,6 +98,9 @@ Requires: pygpgme
1f1d7d
 Requires: pyliblzma
1f1d7d
 # Not really a suggests anymore, due to metadata using it.
1f1d7d
 Requires: pyxattr
1f1d7d
+# Suggests, needed for yum fs diff
1f1d7d
+Requires: diffutils
1f1d7d
+Requires: cpio
1f1d7d
 
1f1d7d
 Conflicts: rpm >= 5-0
1f1d7d
 # Zif is a re-implementation of yum in C, however:
1f1d7d
commit 00aec000813db1b45a7b38e1aa396b1bb8764eb7
1f1d7d
Author: James Antill <james@and.org>
1f1d7d
Date:   Fri Feb 21 16:19:28 2014 -0500
1f1d7d
1f1d7d
    Copy packages in/out of an installroot, for no downloads creating containers.
1f1d7d
1f1d7d
diff --git a/yum/__init__.py b/yum/__init__.py
1f1d7d
index 37ab468..dc468cb 100644
1f1d7d
--- a/yum/__init__.py
1f1d7d
+++ b/yum/__init__.py
1f1d7d
@@ -45,6 +45,7 @@ import logging
1f1d7d
 import logging.config
1f1d7d
 import operator
1f1d7d
 import tempfile
1f1d7d
+import shutil
1f1d7d
 
1f1d7d
 import yum.i18n
1f1d7d
 # This is required to make gaftonmode work...
1f1d7d
@@ -689,6 +690,12 @@ class YumBase(depsolve.Depsolve):
1f1d7d
         if hasattr(self, 'prerepoconf'):
1f1d7d
             self.conf # touch the config class first
1f1d7d
 
1f1d7d
+            if (self.conf.installroot != '/' and
1f1d7d
+                not hasattr(self, '_old_cachedir')):
1f1d7d
+                # Try loading cache from outside...
1f1d7d
+                ir = len(self.conf.installroot)
1f1d7d
+                self._old_cachedir = self.conf.cachedir[ir:]
1f1d7d
+
1f1d7d
             self.getReposFromConfig()
1f1d7d
 
1f1d7d
         #  For rhnplugin, and in theory other stuff, calling
1f1d7d
@@ -2398,6 +2405,9 @@ much more problems).
1f1d7d
                 self.verbose_logger.warn(_("ignoring a dupe of %s") % po)
1f1d7d
                 return True
1f1d7d
             beenthere.add(local)
1f1d7d
+            if downloadonly and not os.path.exists(local):
1f1d7d
+              # Check before we munge the name...
1f1d7d
+              po.repo._preload_pkg_from_system_cache(po)
1f1d7d
             if os.path.exists(local):
1f1d7d
                 if self.verifyPkg(local, po, False):
1f1d7d
                     self.verbose_logger.debug(_("using local copy of %s") % po)
1f1d7d
@@ -2442,6 +2452,22 @@ much more problems).
1f1d7d
                 format_number(rpmsize), format_number(deltasize), 100 - deltasize*100.0/rpmsize)
1f1d7d
 
1f1d7d
         if downloadonly:
1f1d7d
+            if hasattr(self, '_old_cachedir'):
1f1d7d
+              # Try to link/copy them out, if we have somewhere to put them.
1f1d7d
+
1f1d7d
+              for po in pkglist:
1f1d7d
+                if not po.localpath.startswith(self.conf.cachedir):
1f1d7d
+                  continue
1f1d7d
+
1f1d7d
+                end = po.localpath[len(self.conf.cachedir):]
1f1d7d
+                try:
1f1d7d
+                  os.link(po.localpath, self._old_cachedir + end)
1f1d7d
+                except:
1f1d7d
+                  try:
1f1d7d
+                    shutil.copy2(po.localpath, self._old_cachedir + end)
1f1d7d
+                  except:
1f1d7d
+                    pass
1f1d7d
+
1f1d7d
             # close DBs, unlock
1f1d7d
             self.repos.close()
1f1d7d
             self.closeRpmDB()
1f1d7d
commit fcec4d88fa18c30e1aeabf724bec11dcfb1e2655
1f1d7d
Author: James Antill <james@and.org>
1f1d7d
Date:   Fri Feb 21 16:16:23 2014 -0500
1f1d7d
1f1d7d
     A few cleanups for the fs sub-command:
1f1d7d
    
1f1d7d
    . Add checks for diff/cpio/rpm2cpio.
1f1d7d
    . Add missing import for rpm, when override_install_langs isn't set.
1f1d7d
    . Allow users to run some of the commands.
1f1d7d
    . Map fs snap to fssnap command.
1f1d7d
    . Add translations and add messages when you alter the filters.
1f1d7d
    . Save config. file inside the chroot.
1f1d7d
1f1d7d
diff --git a/yumcommands.py b/yumcommands.py
1f1d7d
index 52b8c90..4385a34 100644
1f1d7d
--- a/yumcommands.py
1f1d7d
+++ b/yumcommands.py
1f1d7d
@@ -23,6 +23,7 @@ Classes for subcommands of the yum command line interface.
1f1d7d
 import os
1f1d7d
 import sys
1f1d7d
 import cli
1f1d7d
+import rpm
1f1d7d
 from yum import logginglevels
1f1d7d
 from yum import _, P_
1f1d7d
 from yum import misc
1f1d7d
@@ -34,6 +35,7 @@ import time
1f1d7d
 from yum.i18n import utf8_width, utf8_width_fill, to_unicode, exception2msg
1f1d7d
 import tempfile
1f1d7d
 import shutil
1f1d7d
+import distutils.spawn
1f1d7d
 import glob
1f1d7d
 
1f1d7d
 import yum.config
1f1d7d
@@ -4334,6 +4336,14 @@ class FSCommand(YumCommand):
1f1d7d
         :param basecmd: the name of the command
1f1d7d
         :param extcmds: the command line arguments passed to *basecmd*
1f1d7d
         """
1f1d7d
+        if extcmds and extcmds[0] in ('du', 'status', 'diff'):
1f1d7d
+            # Anyone can go for it...
1f1d7d
+            return
1f1d7d
+
1f1d7d
+        if len(extcmds) == 1 and extcmds[0] in ('filters', 'filter'):
1f1d7d
+            # Can look, but not touch.
1f1d7d
+            return
1f1d7d
+
1f1d7d
         checkRootUID(base)
1f1d7d
 
1f1d7d
     def _fs_pkg_walk(self, pkgs, prefix, modified=False, verbose=False):
1f1d7d
@@ -4611,22 +4621,48 @@ class FSCommand(YumCommand):
1f1d7d
                 break
1f1d7d
 
1f1d7d
     def _fs_filters(self, base, extcmds):
1f1d7d
-        writeRawConfigFile = yum.config._writeRawConfigFile
1f1d7d
+        def _save(confkey):
1f1d7d
+            writeRawConfigFile = yum.config._writeRawConfigFile
1f1d7d
+
1f1d7d
+            # Always create installroot, so we can change it.
1f1d7d
+            if not os.path.exists(base.conf.installroot + '/etc/yum'):
1f1d7d
+                os.makedirs(base.conf.installroot + '/etc/yum')
1f1d7d
+
1f1d7d
+            fn = base.conf.installroot+'/etc/yum/yum.conf'
1f1d7d
+            if not os.path.exists(fn):
1f1d7d
+                # Try the old default
1f1d7d
+                nfn = base.conf.installroot+'/etc/yum.conf'
1f1d7d
+                if not os.path.exists(nfn):
1f1d7d
+                    shutil.copy2(base.conf.config_file_path, fn)
1f1d7d
+            ybc = base.conf
1f1d7d
+            writeRawConfigFile(fn, 'main', ybc.yumvar,
1f1d7d
+                               ybc.cfg.options, ybc.iteritems,
1f1d7d
+                               ybc.optionobj,
1f1d7d
+                               only=[confkey])
1f1d7d
 
1f1d7d
         if not extcmds:
1f1d7d
             oil = base.conf.override_install_langs
1f1d7d
             if not oil:
1f1d7d
                 oil = "rpm: " + rpm.expandMacro("%_install_langs")
1f1d7d
-            print "File system filters:"
1f1d7d
-            print "  Nodocs:", 'nodocs' in base.conf.tsflags
1f1d7d
-            print "  Languages:", oil
1f1d7d
+            print _("File system filters:")
1f1d7d
+            print _("  Nodocs:"), 'nodocs' in base.conf.tsflags
1f1d7d
+            print _("  Languages:"), oil
1f1d7d
         elif extcmds[0] in ('docs', 'nodocs',
1f1d7d
                             'documentation', 'nodocumentation'):
1f1d7d
             c_f = 'nodocs' in base.conf.tsflags
1f1d7d
-            n_f = extcmds[0].startswith('no')
1f1d7d
+            n_f = not extcmds[0].startswith('no')
1f1d7d
             if n_f == c_f:
1f1d7d
+                if n_f:
1f1d7d
+                    print _("Already enabled documentation filter.")
1f1d7d
+                else:
1f1d7d
+                    print _("Already disabled documentation filter.")
1f1d7d
                 return
1f1d7d
 
1f1d7d
+            if n_f:
1f1d7d
+                print _("Enabling documentation filter.")
1f1d7d
+            else:
1f1d7d
+                print _("Disabling documentation filter.")
1f1d7d
+
1f1d7d
             nts = base.conf.tsflags
1f1d7d
             if n_f:
1f1d7d
                 nts = nts + ['nodocs']
1f1d7d
@@ -4634,15 +4670,8 @@ class FSCommand(YumCommand):
1f1d7d
                 nts = [x for x in nts if x != 'nodocs']
1f1d7d
             base.conf.tsflags = " ".join(nts)
1f1d7d
 
1f1d7d
-            fn = '/etc/yum/yum.conf'
1f1d7d
-            if not os.path.exists(fn):
1f1d7d
-                # Try the old default
1f1d7d
-                fn = '/etc/yum.conf'
1f1d7d
-            ybc = base.conf
1f1d7d
-            writeRawConfigFile(fn, 'main', ybc.yumvar,
1f1d7d
-                               ybc.cfg.options, ybc.iteritems,
1f1d7d
-                               ybc.optionobj,
1f1d7d
-                               only=['tsflags'])
1f1d7d
+            _save('tsflags')
1f1d7d
+
1f1d7d
         elif extcmds[0] in ('langs', 'nolangs', 'lang', 'nolang',
1f1d7d
                             'languages', 'nolanguages',
1f1d7d
                             'language', 'nolanguage'):
1f1d7d
@@ -4652,19 +4681,21 @@ class FSCommand(YumCommand):
1f1d7d
                 val = ":".join(extcmds[1:])
1f1d7d
 
1f1d7d
             if val == base.conf.override_install_langs:
1f1d7d
+                if val:
1f1d7d
+                    print _("Already filtering languages to: %s") % val
1f1d7d
+                else:
1f1d7d
+                    print _("Already disabled language filter.")
1f1d7d
                 return
1f1d7d
 
1f1d7d
+            if val:
1f1d7d
+                print _("Setting language filter to: %s") % val
1f1d7d
+            else:
1f1d7d
+                print _("Disabling language filter.")
1f1d7d
+
1f1d7d
             base.conf.override_install_langs = val
1f1d7d
 
1f1d7d
-            fn = '/etc/yum/yum.conf'
1f1d7d
-            if not os.path.exists(fn):
1f1d7d
-                # Try the old default
1f1d7d
-                fn = '/etc/yum.conf'
1f1d7d
-            ybc = base.conf
1f1d7d
-            writeRawConfigFile(fn, 'main', ybc.yumvar,
1f1d7d
-                               ybc.cfg.options, ybc.iteritems,
1f1d7d
-                               ybc.optionobj,
1f1d7d
-                               only=['override_install_langs'])
1f1d7d
+            _save('override_install_langs')
1f1d7d
+
1f1d7d
         else:
1f1d7d
             return 1, [_('Not a valid sub-command of fs filter')]
1f1d7d
 
1f1d7d
@@ -4736,6 +4767,14 @@ class FSCommand(YumCommand):
1f1d7d
             else:
1f1d7d
                 print >>sys.stderr, _('Not packaged?:'), fpath
1f1d7d
 
1f1d7d
+        if not distutils.spawn.find_executable("diff"):
1f1d7d
+            raise yum.Errors.YumBaseError, _("Can't find diff command")
1f1d7d
+        # These just shouldn't happen...
1f1d7d
+        if not distutils.spawn.find_executable("cpio"):
1f1d7d
+            raise yum.Errors.YumBaseError, _("Can't find cpio command")
1f1d7d
+        if not distutils.spawn.find_executable("rpm2cpio"):
1f1d7d
+            raise yum.Errors.YumBaseError, _("Can't find rpm2cpio command")
1f1d7d
+
1f1d7d
         prefix = "."
1f1d7d
         if extcmds:
1f1d7d
             prefix = extcmds[0]
1f1d7d
@@ -4845,7 +4884,7 @@ class FSCommand(YumCommand):
1f1d7d
         """
1f1d7d
         if extcmds and extcmds[0] in ('filters', 'filter',
1f1d7d
                                       'refilter', 'refilter-cleanup',
1f1d7d
-                                      'du', 'status', 'diff'):
1f1d7d
+                                      'du', 'status', 'diff', 'snap'):
1f1d7d
             subcommand = extcmds[0]
1f1d7d
             extcmds = extcmds[1:]
1f1d7d
         else:
1f1d7d
@@ -4871,6 +4910,9 @@ class FSCommand(YumCommand):
1f1d7d
         elif subcommand == 'status':
1f1d7d
             ret = self._fs_status(base, extcmds)
1f1d7d
 
1f1d7d
+        elif subcommand == 'snap':
1f1d7d
+            ret = FSSnapshotCommand().doCommand(base, 'fs snap', args)
1f1d7d
+
1f1d7d
         else:
1f1d7d
             return 1, [_('Not a valid sub-command of %s') % basecmd]
1f1d7d
 
1f1d7d
commit 77c85efcb09f0121d6a611d92e1fc6a237179656
1f1d7d
Author: James Antill <james@and.org>
1f1d7d
Date:   Sun Feb 23 20:57:06 2014 -0500
1f1d7d
1f1d7d
    Choose yum.conf correctly for fs filter saving.
1f1d7d
1f1d7d
diff --git a/yumcommands.py b/yumcommands.py
1f1d7d
index 4385a34..ef84c1f 100644
1f1d7d
--- a/yumcommands.py
1f1d7d
+++ b/yumcommands.py
1f1d7d
@@ -4632,7 +4632,9 @@ class FSCommand(YumCommand):
1f1d7d
             if not os.path.exists(fn):
1f1d7d
                 # Try the old default
1f1d7d
                 nfn = base.conf.installroot+'/etc/yum.conf'
1f1d7d
-                if not os.path.exists(nfn):
1f1d7d
+                if os.path.exists(nfn):
1f1d7d
+                    fn = nfn
1f1d7d
+                else:
1f1d7d
                     shutil.copy2(base.conf.config_file_path, fn)
1f1d7d
             ybc = base.conf
1f1d7d
             writeRawConfigFile(fn, 'main', ybc.yumvar,
1f1d7d
commit 02a2d73afe6ea19ae17cbab2192c1d7e12be5ec2
1f1d7d
Author: James Antill <james@and.org>
1f1d7d
Date:   Mon Mar 24 16:17:19 2014 -0400
1f1d7d
1f1d7d
    No error for refilter cleanup, rm dirs. and eat all errors. BZ 1062959.
1f1d7d
1f1d7d
diff --git a/yumcommands.py b/yumcommands.py
1f1d7d
index 75b3ce2..c76e192 100644
1f1d7d
--- a/yumcommands.py
1f1d7d
+++ b/yumcommands.py
1f1d7d
@@ -37,6 +37,7 @@ import tempfile
1f1d7d
 import shutil
1f1d7d
 import distutils.spawn
1f1d7d
 import glob
1f1d7d
+import errno
1f1d7d
 
1f1d7d
 import yum.config
1f1d7d
 from yum import updateinfo
1f1d7d
@@ -4742,7 +4743,16 @@ class FSCommand(YumCommand):
1f1d7d
 
1f1d7d
         for fname in sorted(pfr['not']):
1f1d7d
             print _('Removing:'), fname
1f1d7d
-            misc.unlink_f(fname)
1f1d7d
+            try: # Ignore everything, unlink_f() doesn't.
1f1d7d
+                os.unlink(fname)
1f1d7d
+            except OSError, e:
1f1d7d
+                if e.errno == errno.EISDIR:
1f1d7d
+                    try:
1f1d7d
+                        os.rmdir(fname)
1f1d7d
+                    except:
1f1d7d
+                        pass
1f1d7d
+            except:
1f1d7d
+                pass
1f1d7d
 
1f1d7d
     def _fs_diff(self, base, extcmds):
1f1d7d
         def deal_with_file(fpath):