yifengyou / rpms / yum

Forked from rpms/yum 3 years ago
Clone

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

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