commit 979096ddfddb0cc13151c7e223be64e80ec8db44
Author: Nikos Skalkotos <skalkoto@grnet.gr>
Date:   Sat Mar 24 14:54:01 2012 +0200

    Add silent mode option
    
    All printing had to be reordered and now it is done from a central point.

diff --git a/image_creator/disk.py b/image_creator/disk.py
index f78adc5..6b69aad 100644
--- a/image_creator/disk.py
+++ b/image_creator/disk.py
@@ -31,9 +31,9 @@
 # interpreted as representing official policies, either expressed
 # or implied, of GRNET S.A.
 
-from image_creator.util import get_command, warn, progress_generator, success
+from image_creator.util import get_command
+from image_creator.util import warn, progress, success, output
 from image_creator import FatalError
-from clint.textui import puts
 
 import stat
 import os
@@ -101,7 +101,7 @@ class Disk(object):
         the Disk instance.
         """
 
-        puts("Examining source media `%s'..." % self.source, False)
+        output("Examining source media `%s'..." % self.source, False)
         sourcedev = self.source
         mode = os.stat(self.source).st_mode
         if stat.S_ISDIR(mode):
@@ -117,7 +117,7 @@ class Disk(object):
             success('looks like a block device')
 
         # Take a snapshot and return it to the user
-        puts("Snapshotting media source...", False)
+        output("Snapshotting media source...", False)
         size = blockdev('--getsize', sourcedev)
         cowfd, cow = tempfile.mkstemp()
         os.close(cowfd)
@@ -177,7 +177,7 @@ class DiskDevice(object):
 
     def enable(self):
         """Enable a newly created DiskDevice"""
-        self.progressbar = progress_generator("Launching helper VM: ")
+        self.progressbar = progress("Launching helper VM: ")
         self.progressbar.next()
         eh = self.g.set_event_callback(self.progress_callback,
                                                     guestfs.EVENT_PROGRESS)
@@ -188,7 +188,7 @@ class DiskDevice(object):
             self.progressbar.send(100)
             self.progressbar = None
 
-        puts('Inspecting Operating System...', False)
+        output('Inspecting Operating System...', False)
         roots = self.g.inspect_os()
         if len(roots) == 0:
             raise FatalError("No operating system found")
@@ -221,6 +221,8 @@ class DiskDevice(object):
 
     def mount(self):
         """Mount all disk partitions in a correct order."""
+
+        output("Mounting image...", False)
         mps = self.g.inspect_get_mountpoints(self.root)
 
         # Sort the keys to mount the fs in a correct order.
@@ -237,7 +239,8 @@ class DiskDevice(object):
             try:
                 self.g.mount(dev, mp)
             except RuntimeError as msg:
-                print "%s (ignored)" % msg
+                warn("%s (ignored)" % msg)
+        success("done")
 
     def umount(self):
         """Umount all mounted filesystems."""
@@ -250,8 +253,7 @@ class DiskDevice(object):
         disk and then updating the partition table. The new disk size
         (in bytes) is returned.
         """
-        puts("Shrinking image (this may take a while)...", False)
-        sys.stdout.flush()
+        output("Shrinking image (this may take a while)...", False)
 
         dev = self.g.part_to_dev(self.root)
         parttype = self.g.part_get_parttype(dev)
@@ -313,7 +315,7 @@ class DiskDevice(object):
         blocksize = 2 ** 22  # 4MB
         size = self.size()
         progress_size = (size + 2 ** 20 - 1) // 2 ** 20  # in MB
-        progressbar = progress_generator("Dumping image file: ", progress_size)
+        progressbar = progress("Dumping image file: ", progress_size)
 
         source = open(self.device, "r")
         try:
diff --git a/image_creator/main.py b/image_creator/main.py
index bc4a47d..ab69b2d 100755
--- a/image_creator/main.py
+++ b/image_creator/main.py
@@ -37,9 +37,8 @@ from image_creator import get_os_class
 from image_creator import __version__ as version
 from image_creator import FatalError
 from image_creator.disk import Disk
-from image_creator.util import get_command, error, progress_generator, success
-from clint.textui import puts
-
+from image_creator.util import get_command, error, success, output
+from image_creator import util
 import sys
 import os
 import optparse
@@ -67,25 +66,23 @@ def parse_options(input_args):
         action="store_true", help="overwrite output files if they exist")
 
     parser.add_option("--no-cleanup", dest="cleanup", default=True,
-        help="don't cleanup sensitive data",
-        action="store_false")
+        help="don't cleanup sensitive data", action="store_false")
 
     parser.add_option("--no-sysprep", dest="sysprep", default=True,
-        help="don't perform system preperation",
-        action="store_false")
+        help="don't perform system preperation", action="store_false")
 
     parser.add_option("--no-shrink", dest="shrink", default=True,
-        help="don't shrink any partition",
-        action="store_false")
+        help="don't shrink any partition", action="store_false")
 
     parser.add_option("-o", "--outfile", type="string", dest="outfile",
         default=None, action="callback", callback=check_writable_dir,
-        help="dump image to FILE",
-        metavar="FILE")
+        help="dump image to FILE", metavar="FILE")
+
+    parser.add_option("-s", "--silent", dest="silent", default=False,
+        help="silent mode, only output error", action="store_true")
 
     parser.add_option("-u", "--upload", dest="upload", default=False,
-        help="upload the image to pithos",
-        action="store_true")
+        help="upload the image to pithos", action="store_true")
 
     parser.add_option("-r", "--register", dest="register", default=False,
         help="register the image to ~okeanos", action="store_true")
@@ -108,9 +105,13 @@ def parse_options(input_args):
 
 
 def image_creator():
-    puts('snf-image-creator %s\n' % version)
     options = parse_options(sys.argv[1:])
 
+    if options.silent:
+        util.silent = True
+
+    output('snf-image-creator %s\n' % version)
+
     if os.geteuid() != 0:
         raise FatalError("You must run %s as root" \
                         % os.path.basename(sys.argv[0]))
@@ -131,7 +132,7 @@ def image_creator():
         image_os = osclass(dev.root, dev.g)
         metadata = image_os.get_metadata()
 
-        puts()
+        output()
 
         if options.sysprep:
             image_os.sysprep()
@@ -154,7 +155,7 @@ def image_creator():
 
             dev.dump(options.outfile)
     finally:
-        puts('cleaning up...')
+        output('cleaning up...')
         disk.cleanup()
 
     return 0
diff --git a/image_creator/os_type/__init__.py b/image_creator/os_type/__init__.py
index b9fd4e0..17ca22e 100644
--- a/image_creator/os_type/__init__.py
+++ b/image_creator/os_type/__init__.py
@@ -31,8 +31,9 @@
 # interpreted as representing official policies, either expressed
 # or implied, of GRNET S.A.
 
+from image_creator.util import output
+
 import re
-from clint.textui import indent, puts
 
 
 def add_prefix(target):
@@ -113,7 +114,7 @@ class OSBase(object):
     def data_cleanup(self):
         """Cleanup sensitive data out of the OS image."""
 
-        puts('Cleaning up sensitive data out of the OS image:')
+        output('Cleaning up sensitive data out of the OS image:')
 
         is_cleanup = lambda x: x.startswith('data_cleanup_') and \
                                                     callable(getattr(self, x))
@@ -122,14 +123,14 @@ class OSBase(object):
         cnt = 0
         for task in tasks:
             cnt += 1
-            puts(('(%d/%d)' % (cnt, size)).ljust(7), False)
+            output(('(%d/%d)' % (cnt, size)).ljust(7), False)
             task()
-        puts()
+        output()
 
     def sysprep(self):
         """Prepere system for image creation."""
 
-        puts('Preparing system for image creation:')
+        output('Preparing system for image creation:')
 
         is_sysprep = lambda x: x.startswith('sysprep_') and \
                                                     callable(getattr(self, x))
@@ -138,8 +139,8 @@ class OSBase(object):
         cnt = 0
         for task in tasks:
             cnt += 1
-            puts(('(%d/%d)' % (cnt, size)).ljust(7), False)
+            output(('(%d/%d)' % (cnt, size)).ljust(7), False)
             task()
-        puts()
+        output()
 
 # vim: set sta sts=4 shiftwidth=4 sw=4 et ai :
diff --git a/image_creator/os_type/linux.py b/image_creator/os_type/linux.py
index f22eb06..7a6fab1 100644
--- a/image_creator/os_type/linux.py
+++ b/image_creator/os_type/linux.py
@@ -32,9 +32,7 @@
 # or implied, of GRNET S.A.
 
 from image_creator.os_type.unix import Unix
-from image_creator.util import warn
-
-from clint.textui import puts, indent
+from image_creator.util import warn, output
 
 import re
 import time
@@ -64,7 +62,7 @@ class Linux(Unix):
         """
 
         if print_header:
-            print 'Fixing acpid powerdown action'
+            output('Fixing acpid powerdown action')
 
         powerbtn_action = '#!/bin/sh\n\nPATH=/sbin:/bin:/usr/bin\n' \
                                 'shutdown -h now \"Power button pressed\"\n'
@@ -119,7 +117,7 @@ class Linux(Unix):
         """
 
         if print_header:
-            puts('Removing persistent network interface names')
+            output('Removing persistent network interface names')
 
         rule_file = '/etc/udev/rules.d/70-persistent-net.rules'
         if self.g.is_file(rule_file):
@@ -131,7 +129,7 @@ class Linux(Unix):
         """
 
         if print_header:
-            puts('Replacing fstab & grub non-persistent device appearences')
+            output('Replacing fstab & grub non-persistent device appearences')
 
         # convert all devices in fstab to persistent
         persistent_root = self._persistent_fstab()
diff --git a/image_creator/os_type/unix.py b/image_creator/os_type/unix.py
index 36a5cd6..75c4797 100644
--- a/image_creator/os_type/unix.py
+++ b/image_creator/os_type/unix.py
@@ -35,8 +35,7 @@ import re
 import sys
 
 from image_creator.os_type import OSBase
-from image_creator.util import warn
-from clint.textui import puts
+from image_creator.util import warn, output
 
 
 class Unix(OSBase):
@@ -75,7 +74,7 @@ class Unix(OSBase):
         """Remove all regular files under /var/cache"""
 
         if print_header:
-            puts('Removing files under /var/cache')
+            output('Removing files under /var/cache')
 
         self.foreach_file('/var/cache', self.g.rm, ftype='r')
 
@@ -83,7 +82,7 @@ class Unix(OSBase):
         """Remove all files under /tmp and /var/tmp"""
 
         if print_header:
-            puts('Removing files under /tmp and /var/tmp')
+            output('Removing files under /tmp and /var/tmp')
 
         self.foreach_file('/tmp', self.g.rm_rf, maxdepth=1)
         self.foreach_file('/var/tmp', self.g.rm_rf, maxdepth=1)
@@ -92,7 +91,7 @@ class Unix(OSBase):
         """Empty all files under /var/log"""
 
         if print_header:
-            puts('Emptying all files under /var/log')
+            output('Emptying all files under /var/log')
 
         self.foreach_file('/var/log', self.g.truncate, ftype='r')
 
@@ -100,7 +99,7 @@ class Unix(OSBase):
         """Remove all files under /var/mail and /var/spool/mail"""
 
         if print_header:
-            puts('Removing files under /var/mail and /var/spool/mail')
+            output('Removing files under /var/mail and /var/spool/mail')
 
         self.foreach_file('/var/spool/mail', self.g.rm_rf, maxdepth=1)
         self.foreach_file('/var/mail', self.g.rm_rf, maxdepth=1)
@@ -111,7 +110,8 @@ class Unix(OSBase):
         homedirs = ['/root'] + self.ls('/home/')
 
         if print_header:
-            puts('Removing sensitive user data under %s' % " ".join(homedirs))
+            output('Removing sensitive user data under %s' % " ".
+                                                        join(homedirs))
 
         for homedir in homedirs:
             for data in self.sensitive_userdata:
diff --git a/image_creator/util.py b/image_creator/util.py
index 50304f0..588d2b0 100644
--- a/image_creator/util.py
+++ b/image_creator/util.py
@@ -31,8 +31,11 @@
 # interpreted as representing official policies, either expressed
 # or implied, of GRNET S.A.
 
+import sys
 import pbs
-from clint.textui import puts, puts_err, colored, progress
+from clint.textui import colored, progress as uiprogress
+
+silent = False
 
 
 def get_command(command):
@@ -50,23 +53,45 @@ def get_command(command):
 
 
 def error(msg, new_line=True):
-    puts_err(colored.red("Error: %s\n" % msg), new_line)
+    nl = "\n" if new_line else ''
+    sys.stderr.write('Error: %s' % msg + nl)
 
 
 def warn(msg, new_line=True):
-    puts_err(colored.yellow("Warning: %s" % msg), new_line)
+    if not silent:
+        nl = "\n" if new_line else ''
+        sys.stderr.write(colored.yellow("Warning: %s" % msg) + nl)
 
 
 def success(msg, new_line=True):
-    puts(colored.green(msg), new_line)
+    if not silent:
+        nl = "\n" if new_line else ''
+        sys.stdout.write(colored.green(msg) + nl)
+        if not nl:
+            sys.stdout.flush()
+
+
+def output(msg="", new_line=True):
+    if not silent:
+        nl = "\n" if new_line else ''
+        sys.stdout.write(msg + nl)
+        if not nl:
+            sys.stdout.flush()
+
+
+def progress(label='', n=100):
 
+    PROGRESS_LENGTH = 32
+    MESSAGE_LENGTH = 32
 
-def progress_generator(label='', n=100):
-    position = 0
-    for i in progress.bar(range(n), label):
-        if i < position:
-            continue
-        position = yield
-    yield  # suppress the StopIteration exception
+    def progress_generator(label, n):
+        position = 0
+        for i in uiprogress.bar(range(n), label.ljust(MESSAGE_LENGTH), \
+                                                    PROGRESS_LENGTH, silent):
+            if i < position:
+                continue
+            position = yield
+        yield  # suppress the StopIteration exception
+    return progress_generator(label, n)
 
 # vim: set sta sts=4 shiftwidth=4 sw=4 et ai :
