[node-patches] Change in ovirt-node[node-3.0]: spec: Add minimizer subpackage

fabiand at fedoraproject.org fabiand at fedoraproject.org
Tue Apr 1 19:06:24 UTC 2014


Fabian Deutsch has uploaded a new change for review.

Change subject: spec: Add minimizer subpackage
......................................................................

spec: Add minimizer subpackage

This subpackage bundles the image-minimizer tool to make it available on
el6.

Change-Id: I1de0066fdc7bf5ca9c441f6a65b495eb73754c40
Signed-off-by: Fabian Deutsch <fabiand at fedoraproject.org>
---
M ovirt-node.spec.in
M tools/Makefile.am
M tools/edit-node
A tools/image-minimizer
4 files changed, 240 insertions(+), 4 deletions(-)


  git pull ssh://gerrit.ovirt.org:29418/ovirt-node refs/changes/41/26341/1

diff --git a/ovirt-node.spec.in b/ovirt-node.spec.in
index a9ee25b..d5ee35f 100644
--- a/ovirt-node.spec.in
+++ b/ovirt-node.spec.in
@@ -14,6 +14,9 @@
 # Igor can only be shipped on Fedora (because of python-uinput)
 %define with_igor 0%{?is_min_f19}
 
+# The minimizer is only bundled on el6, because it is available on Fedora
+%define with_minimizer 0%{?is_el6}
+
 
 Summary:        The %{product_family} daemons/scripts
 Name:           ovirt-node
@@ -120,7 +123,7 @@
 %else
 Requires:       livecd-tools >= 1:16.0
 %endif
-Requires:       appliance-tools-minimizer
+Requires:       ovirt-node-minimizer
 Requires:       libselinux-python
 
 %define tools_root %{_datadir}/ovirt-node-tools
@@ -354,6 +357,24 @@
 %endif
 
 
+#
+# minimizer subpackage
+#
+%if 0%{?with_minimizer}
+%package minimizer
+Summary:        The image-minimizer tool
+Group:          Applications/System
+Obsoletes:      appliance-tools-minimizer
+
+
+%description minimizer
+This package ships the image-minimizer tool.
+This tool is used to remove unneeded rpms and files from a filesystem tree.
+
+# </minimizer subpackage>
+%endif
+
+
 %prep
 %setup -q
 
@@ -423,6 +444,11 @@
        %{buildroot}/usr/libexec/ovirt-node-igor-slave
 %endif
 
+# Remove minimizer if unneeded
+%if ! 0%{?with_minimizer}
+rm -vf %{buildroot}/%{_sbindir}/image-minimizer
+%endif
+
 
 %clean
 %{__rm} -rf %{buildroot}
@@ -472,6 +498,11 @@
 # remove symlink to keep original redhat-release
 rm -f /etc/system-release
 echo "%{product_family} release %{product_release}" > /etc/system-release
+
+# Remove minimizer if not needed
+%if ! 0%{?with_minimizer}
+rm -v %{buildroot}/%{_sbindir}/image-minimizer
+%endif
 
 # Remove igor stuff if not needed
 %if ! 0%{?with_igor}
@@ -593,6 +624,12 @@
 %{_datadir}/selinux/*/%{modulename}.pp
 
 
+%if 0%{?with_minimizer}
+%files minimizer
+%{_sbindir}/image-minimizer
+%endif
+
+
 %files
 %defattr(-,root,root)
 %config(noreplace) %attr(0644,root,root) %{_sysconfdir}/default/ovirt
diff --git a/tools/Makefile.am b/tools/Makefile.am
index 600353d..ddcb01a 100644
--- a/tools/Makefile.am
+++ b/tools/Makefile.am
@@ -17,7 +17,8 @@
 
 dist_sbin_SCRIPTS = \
   edit-node \
-  testable-node
+  testable-node \
+  image-minimizer
 
 EXTRA_DIST = \
   edit-node.8
diff --git a/tools/edit-node b/tools/edit-node
index 582a811..b57fb4a 100755
--- a/tools/edit-node
+++ b/tools/edit-node
@@ -1047,8 +1047,9 @@
 
     def _minimize(self):
         print "Running Minimizer"
-        minimizer = "/usr/bin/image-minimizer"
-        if os.path.exists(minimizer):
+        minimizer = "image-minimizer"
+        if (os.path.exists("/usr/bin/" + minimizer) or
+            os.path.exists("/usr/sbin/" + minimizer)):
             print glob.glob("%s/etc/ovirt-plugins.d/*.minimize"
                             % self._instroot)
             for f in glob.glob("%s/etc/ovirt-plugins.d/*.minimize"
diff --git a/tools/image-minimizer b/tools/image-minimizer
new file mode 100755
index 0000000..8ed1808
--- /dev/null
+++ b/tools/image-minimizer
@@ -0,0 +1,197 @@
+#!/usr/bin/python
+#
+# image-minimizer: removes files and packages on the filesystem
+#
+# Copyright 2007-2010 Red Hat  Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU Library General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+import glob
+import optparse
+import os
+import shutil
+import sys
+import rpm
+
+class ImageMinimizer:
+    filename = ''
+    dryrun = False
+    verbose = False
+    prefix = None
+    drops = set()
+    visited = set()
+    drops_rpm = set()
+    ts = None
+
+    def __init__(self, filename, root, dryrun, verbose):
+        self.filename = filename
+        self.prefix = root
+        self.dryrun = dryrun
+        self.verbose = verbose
+        self.ts = None
+
+    # Recursively adds all files and directories.
+    # This is done becuase globbing does not allow
+    # ** for arbitrary nesting.
+    def add_directory(self, files, dirname):
+        self.visited.add(dirname)
+        for root, dirs, items in os.walk(dirname):
+            for dir in dirs:
+                self.visited.add(os.path.join(root, dir))
+            for name in items:
+                files.add(os.path.join(root, name))
+
+    def add_pattern(self, files, pattern):
+        globs = glob.glob(pattern)
+        if self.verbose and len(globs) == 0:
+            print "%s file not found" % pattern
+        for g in globs:
+            if os.path.isdir(g):
+                self.add_directory(files, g)
+            else:
+                files.add(g)
+
+    def add_pattern_rpm(self, rpms, pattern):
+        if self.ts is None:
+            if self.prefix is None:
+                raise Exception ('Must specify installation root for droprpm/keeprpm')
+            self.ts = rpm.TransactionSet(self.prefix)
+        mi = self.ts.dbMatch()
+        mi.pattern('name', rpm.RPMMIRE_GLOB, pattern)
+        not_found = True
+        for hdr in mi:
+            not_found = False
+            rpms.add(hdr['name'])
+        if self.verbose and not_found:
+            print "%s package not found" % pattern
+
+    # Parses each line in the ifle
+    def parse_line(self, line):
+        command = ""
+        pattern = ""
+        tok = line.split(None,1)
+        if len(tok) > 0:
+            command = tok[0].lower()
+            if len(tok) > 1:
+                pattern = tok[1].strip()
+
+        # Strip out all the comments and blank lines
+        if not (command.startswith('#') or command==''):
+            if command == 'keep':
+                if self.prefix is not None :
+                    pattern = pattern.lstrip('/')
+                    pattern = os.path.join(self.prefix, pattern)
+                keeps = set()
+                self.add_pattern(keeps, pattern)
+                self.drops.difference_update(keeps)
+                keeps = None
+            elif command == 'drop':
+                if self.prefix is not None :
+                    pattern = pattern.lstrip('/')
+                    pattern = os.path.join(self.prefix, pattern)
+                self.add_pattern(self.drops, pattern)
+            elif command == 'keeprpm':
+                keeps_rpm = set()
+                self.add_pattern_rpm(keeps_rpm, pattern)
+                self.drops_rpm.difference_update(keeps_rpm)
+                keeps_rpm = None
+            elif command == 'droprpm':
+                self.add_pattern_rpm(self.drops_rpm, pattern)
+            else:
+                raise Exception ('Unknown Command: ' + command)
+
+    def remove(self):
+        for tag in sorted(self.drops, reverse=True):
+            self.visited.add(os.path.split(tag)[0])
+            if os.path.isdir(tag):
+                self.visited.add(tag)
+            else:
+                if self.dryrun:
+                    print 'rm ' + tag
+                else:
+                    if self.verbose:
+                        print 'rm ' + tag
+                    os.remove(tag)
+
+        #remove all empty directory. Every 8k counts!
+        for dir in sorted(self.visited, reverse=True):
+            if len(os.listdir(dir)) == 0:
+                if self.dryrun:
+                    print 'rm -rf ' + dir
+                else:
+                    if self.verbose:
+                        print 'rm -rf ' + dir
+                    os.rmdir(dir)
+
+    def remove_rpm(self):
+
+        def runCallback(reason, amount, total, key, client_data):
+            if self.verbose and reason == rpm.RPMCALLBACK_UNINST_STOP:
+                print key, "erased"
+
+        if len(self.drops_rpm) == 0:
+            return
+
+        for pkg in self.drops_rpm:
+            if self.dryrun:
+                print "erasing ", pkg
+            else:
+                self.ts.addErase(pkg)
+        if not self.dryrun:
+            # skip ts.check(), equivalent to --nodeps
+            self.ts.run(runCallback, "erase")
+
+    def filter(self):
+        for line in (open(self.filename).readlines()):
+            self.parse_line(line.strip())
+        self.remove()
+        self.remove_rpm()
+
+
+def parse_options():
+    usage = "usage: %prog [options] filename"
+    parser = optparse.OptionParser(usage=usage)
+
+    parser.set_defaults(root=os.environ.get('INSTALL_ROOT'), dry_run=False)
+
+    parser.add_option("-i", "--installroot", type="string", dest="root",
+        help="Root path to prepend to all file patterns and installation root for RPM operations.  Defaults to INSTALL_ROOT")
+
+    parser.add_option("--dryrun", action="store_true", dest="dryrun",
+        help="If set, no filesystem changes are made.")
+
+    parser.add_option("-v", "--verbose", action="store_true", dest="verbose",
+        help="Display every action as it is performed.")
+
+    (options, args) = parser.parse_args()
+    if len(args) == 0:
+        parser.print_help()
+        sys.exit(1)
+
+    return (options, args)
+
+
+if __name__ == "__main__":
+    try:
+        (options, args) = parse_options()
+        filename = args[0]
+        minimizer = ImageMinimizer(filename, options.root, options.dryrun,
+                                    options.verbose)
+        minimizer.filter()
+    except SystemExit, e:
+        sys.exit(e.code)
+    except KeyboardInterrupt, e:
+        print >> sys.stderr, _("Aborted at user request")
+    except Exception, e:
+        print e
+        sys.exit(1)


-- 
To view, visit http://gerrit.ovirt.org/26341
To unsubscribe, visit http://gerrit.ovirt.org/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: I1de0066fdc7bf5ca9c441f6a65b495eb73754c40
Gerrit-PatchSet: 1
Gerrit-Project: ovirt-node
Gerrit-Branch: node-3.0
Gerrit-Owner: Fabian Deutsch <fabiand at fedoraproject.org>



More information about the node-patches mailing list