From: Nikos Skalkotos Date: Tue, 5 Jun 2012 15:36:17 +0000 (+0300) Subject: Unify output by creating a seperated output module X-Git-Tag: v0.1~89 X-Git-Url: https://code.grnet.gr/git/snf-image-creator/commitdiff_plain/e77e66a923367afd618cb5d7b977095cac119b75 Unify output by creating a seperated output module All image-creator components now output messages using an instance of one of the output classes. --- diff --git a/image_creator/disk.py b/image_creator/disk.py index 6632b3e..20ce9f5 100644 --- a/image_creator/disk.py +++ b/image_creator/disk.py @@ -32,7 +32,7 @@ # or implied, of GRNET S.A. from image_creator.util import get_command -from image_creator.util import warn, progress, success, output, FatalError +from image_creator.util import FatalError from image_creator.gpt import GPTPartitionTable import stat import os @@ -62,12 +62,13 @@ class Disk(object): the Linux kernel. """ - def __init__(self, source): + def __init__(self, source, output): """Create a new Disk instance out of a source media. The source media can be an image file, a block device or a directory.""" self._cleanup_jobs = [] self._devices = [] self.source = source + self.out = output def _add_cleanup(self, job, *args): self._cleanup_jobs.append((job, args)) @@ -98,7 +99,7 @@ class Disk(object): instance. """ - output("Examining source media `%s'..." % self.source, False) + self.out.output("Examining source media `%s'..." % self.source, False) sourcedev = self.source mode = os.stat(self.source).st_mode if stat.S_ISDIR(mode): @@ -111,10 +112,10 @@ class Disk(object): raise ValueError("Invalid media source. Only block devices, " "regular files and directories are supported.") else: - success('looks like a block device') + self.out.success('looks like a block device') # Take a snapshot and return it to the user - output("Snapshotting media source...", False) + self.out.output("Snapshotting media source...", False) size = blockdev('--getsize', sourcedev) cowfd, cow = tempfile.mkstemp() os.close(cowfd) @@ -137,13 +138,13 @@ class Disk(object): finally: os.unlink(table) - success('done') + self.out.success('done') return "/dev/mapper/%s" % snapshot def get_device(self, media): """Returns a newly created DiskDevice instance.""" - new_device = DiskDevice(media) + new_device = DiskDevice(media, self.out) self._devices.append(new_device) new_device.enable() return new_device @@ -161,10 +162,11 @@ class DiskDevice(object): as created by the device-mapper. """ - def __init__(self, device, bootable=True): + def __init__(self, device, output, bootable=True): """Create a new DiskDevice.""" self.real_device = device + self.out = output self.bootable = bootable self.progress_bar = None self.guestfs_device = None @@ -180,7 +182,7 @@ class DiskDevice(object): def enable(self): """Enable a newly created DiskDevice""" - self.progressbar = progress("Launching helper VM: ", "percent") + self.progressbar = self.out.Progress("Launching helper VM", "percent") self.progressbar.max = 100 self.progressbar.goto(1) eh = self.g.set_event_callback(self.progress_callback, @@ -188,12 +190,10 @@ class DiskDevice(object): self.g.launch() self.guestfs_enabled = True self.g.delete_event_callback(eh) - if self.progressbar is not None: - output("\rLaunching helper VM...\033[K", False) - success("done") - self.progressbar = None + self.progressbar.success('done') + self.progressbar = None - output('Inspecting Operating System...', False) + self.out.output('Inspecting Operating System...', False) roots = self.g.inspect_os() if len(roots) == 0: raise FatalError("No operating system found") @@ -208,7 +208,7 @@ class DiskDevice(object): self.ostype = self.g.inspect_get_type(self.root) self.distro = self.g.inspect_get_distro(self.root) - success('found a(n) %s system' % self.distro) + self.out.success('found a(n) %s system' % self.distro) def destroy(self): """Destroy this DiskDevice instance.""" @@ -229,7 +229,7 @@ class DiskDevice(object): def mount(self): """Mount all disk partitions in a correct order.""" - output("Mounting image...", False) + self.out.output("Mounting image...", False) mps = self.g.inspect_get_mountpoints(self.root) # Sort the keys to mount the fs in a correct order. @@ -246,8 +246,8 @@ class DiskDevice(object): try: self.g.mount(dev, mp) except RuntimeError as msg: - warn("%s (ignored)" % msg) - success("done") + self.out.warn("%s (ignored)" % msg) + self.out.success("done") def umount(self): """Umount all mounted filesystems.""" @@ -307,7 +307,7 @@ class DiskDevice(object): MB = 2 ** 20 - output("Shrinking image (this may take a while)...", False) + self.out.output("Shrinking image (this may take a while)...", False) last_part = None fstype = None @@ -329,7 +329,7 @@ class DiskDevice(object): break if not re.match("ext[234]", fstype): - warn("Don't know how to resize %s partitions." % fstype) + self.out.warn("Don't know how to resize %s partitions." % fstype) return self.meta['SIZE'] part_dev = "%s%d" % (self.guestfs_device, last_part['part_num']) @@ -387,7 +387,7 @@ class DiskDevice(object): part_set_id(last_part['part_num'], last_part['id']) new_size = (end + 1) * sector_size - success("new size is %dMB" % ((new_size + MB - 1) // MB)) + self.out.success("new size is %dMB" % ((new_size + MB - 1) // MB)) if self.meta['PARTITION_TABLE'] == 'gpt': ptable = GPTPartitionTable(self.real_device) @@ -407,7 +407,7 @@ class DiskDevice(object): blocksize = 4 * MB # 4MB size = self.meta['SIZE'] progress_size = (size + MB - 1) // MB # in MB - progressbar = progress("Dumping image file: ", 'mb') + progressbar = self.out.Progress("Dumping image file", 'mb') progressbar.max = progress_size with open(self.real_device, 'r') as src: @@ -421,7 +421,6 @@ class DiskDevice(object): offset += sent left -= sent progressbar.goto((size - left) // MB) - output("\rDumping image file...\033[K", False) - success('image file %s was successfully created' % outfile) + progressbar.success('image file %s was successfully created' % outfile) # vim: set sta sts=4 shiftwidth=4 sw=4 et ai : diff --git a/image_creator/kamaki_wrapper.py b/image_creator/kamaki_wrapper.py index e3c249e..e1f3a02 100644 --- a/image_creator/kamaki_wrapper.py +++ b/image_creator/kamaki_wrapper.py @@ -39,37 +39,17 @@ from kamaki.clients.image import ImageClient from kamaki.clients.pithos import PithosClient from progress.bar import Bar -from image_creator.util import FatalError, output, success +from image_creator.util import FatalError +from image_creator.output import output, warn CONTAINER = "images" -def progress(message): - - MSG_LENGTH = 30 - - def progress_gen(n): - msg = "%s:" % message - - progressbar = Bar(msg.ljust(MSG_LENGTH)) - progressbar.max = n - progressbar.fill = '#' - progressbar.bar_prefix = ' [' - progressbar.bar_suffix = '] ' - - for _ in range(n): - yield - progressbar.next() - output("\r%s...\033[K" % message, False) - success("done") - yield - return progress_gen - - -class Kamaki: - def __init__(self, account, token): +class Kamaki(object): + def __init__(self, account, token, output): self.account = account self.token = token + self.out = output config = Config() @@ -95,8 +75,8 @@ class Kamaki: raise FatalError("Pithos client: %d %s" % \ (e.status, e.message)) try: - hash_cb = progress(hp) if hp is not None else None - upload_cb = progress(up) if up is not None else None + hash_cb = self.out.progress_gen(hp) if hp is not None else None + upload_cb = self.out.progress_gen(up) if up is not None else None self.pithos_client.create_object(remote_path, file_obj, size, hash_cb, upload_cb) return "pithos://%s/%s/%s" % \ diff --git a/image_creator/main.py b/image_creator/main.py index afcdfcd..30fa7d6 100644 --- a/image_creator/main.py +++ b/image_creator/main.py @@ -36,8 +36,8 @@ from image_creator import __version__ as version from image_creator import util from image_creator.disk import Disk -from image_creator.util import get_command, error, success, output, \ - FatalError, progress, md5 +from image_creator.util import get_command, FatalError, MD5 +from image_creator.output import Output, Output_with_progress, Silent, error from image_creator.os_type import get_os_class from image_creator.kamaki_wrapper import Kamaki import sys @@ -153,17 +153,19 @@ def parse_options(input_args): def image_creator(): options = parse_options(sys.argv[1:]) - if options.silent: - util.silent = True - if options.outfile is None and not options.upload \ and not options.print_sysprep: raise FatalError("At least one of `-o', `-u' or `--print-sysprep' " \ "must be set") + if options.silent: + out = Silent() + else: + out = Output_with_progress() + title = 'snf-image-creator %s' % version - output(title) - output('=' * len(title)) + out.output(title) + out.output('=' * len(title)) if os.geteuid() != 0: raise FatalError("You must run %s as root" \ @@ -176,7 +178,7 @@ def image_creator(): raise FatalError("Output file %s exists " "(use --force to overwrite it)." % filename) - disk = Disk(options.source) + disk = Disk(options.source, out) try: snapshot = disk.snapshot() @@ -184,8 +186,8 @@ def image_creator(): dev.mount() osclass = get_os_class(dev.distro, dev.ostype) - image_os = osclass(dev.root, dev.g) - output() + image_os = osclass(dev.root, dev.g, out) + out.output() for sysprep in options.disabled_syspreps: image_os.disable_sysprep(sysprep) @@ -195,7 +197,7 @@ def image_creator(): if options.print_sysprep: image_os.print_syspreps() - output() + out.output() if options.outfile is None and not options.upload: return 0 @@ -206,13 +208,14 @@ def image_creator(): metadata = image_os.meta dev.umount() - size = options.shrink and dev.shrink() or dev.size + size = options.shrink and dev.shrink() or dev.meta['SIZE'] metadata.update(dev.meta) # Add command line metadata to the collected ones... metadata.update(options.metadata) - checksum = md5(snapshot, size) + md5 = MD5(out) + checksum = md5.compute(snapshot, size) metastring = '\n'.join( ['%s=%s' % (key, value) for (key, value) in metadata.items()]) @@ -221,54 +224,54 @@ def image_creator(): if options.outfile is not None: dev.dump(options.outfile) - output('Dumping metadata file...', False) + out.output('Dumping metadata file...', False) with open('%s.%s' % (options.outfile, 'meta'), 'w') as f: f.write(metastring) - success('done') + out.success('done') - output('Dumping md5sum file...', False) + out.output('Dumping md5sum file...', False) with open('%s.%s' % (options.outfile, 'md5sum'), 'w') as f: f.write('%s %s\n' % (checksum, \ os.path.basename(options.outfile))) - success('done') + out.success('done') # Destroy the device. We only need the snapshot from now on disk.destroy_device(dev) - output() + out.output() uploaded_obj = "" if options.upload: - output("Uploading image to pithos:") - kamaki = Kamaki(options.account, options.token) + out.output("Uploading image to pithos:") + kamaki = Kamaki(options.account, options.token, out) with open(snapshot) as f: uploaded_obj = kamaki.upload(f, size, options.upload, "(1/4) Calculating block hashes", "(2/4) Uploading missing blocks") - output("(3/4) Uploading metadata file...", False) + out.output("(3/4) Uploading metadata file...", False) kamaki.upload(StringIO.StringIO(metastring), size=len(metastring), remote_path="%s.%s" % (options.upload, 'meta')) - success('done') - output("(4/4) Uploading md5sum file...", False) + out.success('done') + out.output("(4/4) Uploading md5sum file...", False) md5sumstr = '%s %s\n' % ( checksum, os.path.basename(options.upload)) kamaki.upload(StringIO.StringIO(md5sumstr), size=len(md5sumstr), remote_path="%s.%s" % (options.upload, 'md5sum')) - success('done') - output() + out.success('done') + out.output() if options.register: - output('Registring image to ~okeanos...', False) + out.output('Registring image to ~okeanos...', False) kamaki.register(options.register, uploaded_obj, metadata) - success('done') - output() + out.success('done') + out.output() finally: - output('cleaning up...') + out.output('cleaning up...') disk.cleanup() - success("snf-image-creator exited without errors") + out.success("snf-image-creator exited without errors") return 0 diff --git a/image_creator/os_type/__init__.py b/image_creator/os_type/__init__.py index 8a39846..98d570d 100644 --- a/image_creator/os_type/__init__.py +++ b/image_creator/os_type/__init__.py @@ -31,7 +31,7 @@ # interpreted as representing official policies, either expressed # or implied, of GRNET S.A. -from image_creator.util import output, FatalError +from image_creator.util import FatalError import textwrap import re @@ -70,9 +70,10 @@ def sysprep(enabled=True): class OSBase(object): """Basic operating system class""" - def __init__(self, rootdev, ghandler): + def __init__(self, rootdev, ghandler, output): self.root = rootdev self.g = ghandler + self.out = output # Collect metadata about the OS self.meta = {} @@ -129,23 +130,23 @@ class OSBase(object): wrapper.initial_indent = '\t' wrapper.width = 72 - output("Enabled system preperation operations:") + self.out.output("Enabled system preperation operations:") if len(enabled) == 0: - output("(none)") + self.out.output("(none)") else: for sysprep in enabled: name = sysprep.__name__.replace('_', '-') descr = wrapper.fill(textwrap.dedent(sysprep.__doc__)) - output(' %s:\n%s\n' % (name, descr)) + self.out.output(' %s:\n%s\n' % (name, descr)) - output("Disabled system preperation operations:") + self.out.output("Disabled system preperation operations:") if len(disabled) == 0: - output("(none)") + self.out.output("(none)") else: for sysprep in disabled: name = sysprep.__name__.replace('_', '-') descr = wrapper.fill(textwrap.dedent(sysprep.__doc__)) - output(' %s:\n%s\n' % (name, descr)) + self.out.output(' %s:\n%s\n' % (name, descr)) @add_prefix def ls(self, directory): @@ -202,15 +203,15 @@ class OSBase(object): def do_sysprep(self): """Prepere system for image creation.""" - output('Preparing system for image creation:') + self.out.output('Preparing system for image creation:') tasks, _ = self.list_syspreps() size = len(tasks) cnt = 0 for task in tasks: cnt += 1 - output(('(%d/%d)' % (cnt, size)).ljust(7), False) + self.out.output(('(%d/%d)' % (cnt, size)).ljust(7), False) task() - output() + self.out.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 e128396..9a54eeb 100644 --- a/image_creator/os_type/linux.py +++ b/image_creator/os_type/linux.py @@ -32,15 +32,14 @@ # or implied, of GRNET S.A. from image_creator.os_type.unix import Unix, sysprep -from image_creator.util import warn, output import re import time class Linux(Unix): - def __init__(self, rootdev, ghandler): - super(Linux, self).__init__(rootdev, ghandler) + def __init__(self, rootdev, ghandler, output): + super(Linux, self).__init__(rootdev, ghandler, output) self._uuid = dict() self._persistent = re.compile('/dev/[hsv]d[a-z][1-9]*') @@ -63,14 +62,14 @@ class Linux(Unix): """ if print_header: - output('Fixing acpid powerdown action') + self.out.output('Fixing acpid powerdown action') powerbtn_action = '#!/bin/sh\n\nPATH=/sbin:/bin:/usr/bin\n' \ 'shutdown -h now \"Power button pressed\"\n' events_dir = '/etc/acpi/events' if not self.g.is_dir(events_dir): - warn("No acpid event directory found") + self.out.warn("No acpid event directory found") return event_exp = re.compile('event=(.+)', re.I) @@ -95,18 +94,21 @@ class Linux(Unix): if event.strip() == "button[ /]power": if action: if not self.g.is_file(action): - warn("Acpid action file: %s does not exist" % action) + self.out.warn("Acpid action file: %s does not exist" % + action) return self.g.copy_file_to_file(action, \ "%s.orig.snf-image-creator-%d" % (action, time.time())) self.g.write(action, powerbtn_action) return else: - warn("Acpid event file %s does not contain and action") + self.out.warn( + "Acpid event file %s does not contain and action") return elif event.strip() == ".*": - warn("Found action `.*'. Don't know how to handle this." \ - " Please edit \%s' image file manually to make the " \ + self.out.warn( + "Found action `.*'. Don't know how to handle this. " \ + "Please edit \%s' image file manually to make the " \ "system immediatelly shutdown when an power button acpi " \ "event occures" % action) return @@ -119,7 +121,7 @@ class Linux(Unix): """ if print_header: - output('Removing persistent network interface names') + self.out.output('Removing persistent network interface names') rule_file = '/etc/udev/rules.d/70-persistent-net.rules' if self.g.is_file(rule_file): @@ -134,7 +136,7 @@ class Linux(Unix): """ if print_header: - output('Removing swap entry from fstab') + self.out.output('Removing swap entry from fstab') new_fstab = "" fstab = self.g.cat('/etc/fstab') @@ -155,7 +157,8 @@ class Linux(Unix): """ if print_header: - output('Replacing fstab & grub non-persistent device appearences') + self.out.output( + 'Replacing fstab & grub non-persistent device appearences') # convert all devices in fstab to persistent persistent_root = self._persistent_fstab() @@ -217,7 +220,7 @@ class Linux(Unix): entry = line.split() if len(entry) != 6: - warn("Detected abnormal entry in fstab") + self.out.warn("Detected abnormal entry in fstab") return orig, "", "" dev = entry[0] diff --git a/image_creator/os_type/ubuntu.py b/image_creator/os_type/ubuntu.py index f992981..e5cb07d 100644 --- a/image_creator/os_type/ubuntu.py +++ b/image_creator/os_type/ubuntu.py @@ -35,8 +35,8 @@ from image_creator.os_type.linux import Linux, sysprep class Ubuntu(Linux): - def __init__(self, rootdev, ghandler): - super(Ubuntu, self).__init__(rootdev, ghandler) + def __init__(self, rootdev, ghandler, output): + super(Ubuntu, self).__init__(rootdev, ghandler, output) apps = self.g.inspect_list_applications(self.root) for app in apps: diff --git a/image_creator/os_type/unix.py b/image_creator/os_type/unix.py index 7eb7f76..06eccbf 100644 --- a/image_creator/os_type/unix.py +++ b/image_creator/os_type/unix.py @@ -35,7 +35,6 @@ import re import sys from image_creator.os_type import OSBase, sysprep -from image_creator.util import warn, output class Unix(OSBase): @@ -48,8 +47,8 @@ class Unix(OSBase): '.thunderbird' ] - def __init__(self, rootdev, ghandler): - super(Unix, self).__init__(rootdev, ghandler) + def __init__(self, rootdev, ghandler, output): + super(Unix, self).__init__(rootdev, ghandler, output) self.meta["USERS"] = " ".join(self._get_passworded_users()) @@ -75,7 +74,8 @@ class Unix(OSBase): """Remove all user accounts with id greater than 1000""" if print_header: - output('Removing all user accounts with id greater than 1000') + self.out.output( + 'Removing all user accounts with id greater than 1000') # Remove users from /etc/passwd passwd = [] @@ -123,7 +123,8 @@ class Unix(OSBase): """Remove all passwords and lock all user accounts""" if print_header: - output('Cleaning up passwords & locking all user accounts') + self.out.output( + 'Cleaning up passwords & locking all user accounts') shadow = [] @@ -141,7 +142,7 @@ class Unix(OSBase): """Remove all regular files under /var/cache""" if print_header: - output('Removing files under /var/cache') + self.out.output('Removing files under /var/cache') self.foreach_file('/var/cache', self.g.rm, ftype='r') @@ -150,7 +151,7 @@ class Unix(OSBase): """Remove all files under /tmp and /var/tmp""" if print_header: - output('Removing files under /tmp and /var/tmp') + self.out.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) @@ -160,7 +161,7 @@ class Unix(OSBase): """Empty all files under /var/log""" if print_header: - output('Emptying all files under /var/log') + self.out.output('Emptying all files under /var/log') self.foreach_file('/var/log', self.g.truncate, ftype='r') @@ -169,7 +170,7 @@ class Unix(OSBase): """Remove all files under /var/mail and /var/spool/mail""" if print_header: - output('Removing files under /var/mail and /var/spool/mail') + self.out.output('Removing files under /var/mail & /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) @@ -181,7 +182,7 @@ class Unix(OSBase): homedirs = ['/root'] + self.ls('/home/') if print_header: - output('Removing sensitive user data under %s' % " ". + self.out.output('Removing sensitive user data under %s' % " ". join(homedirs)) for homedir in homedirs: diff --git a/image_creator/output.py b/image_creator/output.py new file mode 100644 index 0000000..0f33f6d --- /dev/null +++ b/image_creator/output.py @@ -0,0 +1,148 @@ +# Copyright 2012 GRNET S.A. All rights reserved. +# +# Redistribution and use in source and binary forms, with or +# without modification, are permitted provided that the following +# conditions are met: +# +# 1. Redistributions of source code must retain the above +# copyright notice, this list of conditions and the following +# disclaimer. +# +# 2. Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following +# disclaimer in the documentation and/or other materials +# provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS +# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR +# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +# The views and conclusions contained in the software and +# documentation are those of the authors and should not be +# interpreted as representing official policies, either expressed +# or implied, of GRNET S.A. + +import sys +from progress.bar import Bar +from colors import red, green, yellow + + +def error(msg, new_line=True): + nl = "\n" if new_line else '' + sys.stderr.write(red('Error: %s' % msg) + nl) + + +def warn(msg, new_line=True): + nl = "\n" if new_line else '' + sys.stderr.write(yellow("Warning: %s" % msg) + nl) + + +def success(msg, new_line=True): + nl = "\n" if new_line else '' + sys.stdout.write(green(msg) + nl) + if not nl: + sys.stdout.flush() + + +def output(msg='', new_line=True): + nl = "\n" if new_line else '' + sys.stdout.write(msg + nl) + if not nl: + sys.stdout.flush() + + +class Output(object): + def error(self, msg, new_line=True): + error(msg, new_line) + + def warn(self, msg, new_line=True): + warn(msg, new_line) + + def success(self, msg, new_line=True): + success(msg, new_line) + + def output(self, msg='', new_line=True): + output(msg, new_line) + + class Progress(object): + def __init__(self, title, bar_type='default'): + output("%s..." % title, False) + + def goto(self, dest): + pass + + def next(self): + pass + + def success(self, result): + sucess(result) + + def progress_gen(self, message): + + progress = getattr(self, 'Progress') + + def generator(n): + progressbar = progress(message, 'default') + + for _ in range(n): + yield + progressbar.next() + + progressbar.success('done') + yield + return generator + + +class Output_with_progress(Output): + class Progress(Bar): + MESSAGE_LENGTH = 30 + + template = { + 'default': '%(index)d/%(max)d', + 'percent': '%(percent)d%%', + 'b': '%(index)d/%(max)d B', + 'kb': '%(index)d/%(max)d KB', + 'mb': '%(index)d/%(max)d MB' + } + + def __init__(self, title, bar_type='default'): + super(Output_with_progress.Progress, self).__init__() + self.title = title + self.fill = '#' + self.bar_prefix = ' [' + self.bar_suffix = '] ' + self.message = ("%s:" % self.title).ljust(self.MESSAGE_LENGTH) + self.suffix = self.template[bar_type] + + def success(self, result): + output("\r%s... \033[K" % self.title, False) + success(result) + + +class Silent(Output): + def warn(self, msg, new_line=True): + pass + + def success(self, msg, new_line=True): + pass + + def output(self, msg='', new_line=True): + pass + + class Progress(Output.Progress): + def __init__(self, title, bar_type): + pass + + def success(self, result): + pass + +# vim: set sta sts=4 shiftwidth=4 sw=4 et ai : diff --git a/image_creator/util.py b/image_creator/util.py index d3d4cc0..161b73d 100644 --- a/image_creator/util.py +++ b/image_creator/util.py @@ -34,17 +34,12 @@ import sys import pbs import hashlib -from colors import red, green, yellow -from progress.bar import Bar class FatalError(Exception): pass -silent = False - - def get_command(command): def find_sbin_command(command, exception): search_paths = ['/usr/local/sbin', '/usr/sbin', '/sbin'] @@ -59,75 +54,29 @@ def get_command(command): return find_sbin_command(command, e) -def error(msg, new_line=True): - nl = "\n" if new_line else '' - sys.stderr.write(red('Error: %s' % msg) + nl) - - -def warn(msg, new_line=True): - if not silent: - nl = "\n" if new_line else '' - sys.stderr.write(yellow("Warning: %s" % msg) + nl) - - -def success(msg, new_line=True): - if not silent: - nl = "\n" if new_line else '' - sys.stdout.write(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(message='', bar_type="default"): - - MESSAGE_LENGTH = 30 - - suffix = { - 'default': '%(index)d/%(max)d', - 'percent': '%(percent)d%%', - 'b': '%(index)d/%(max)d B', - 'kb': '%(index)d/%(max)d KB', - 'mb': '%(index)d/%(max)d MB' - } - - bar = Bar() - bar.message = message.ljust(MESSAGE_LENGTH) - bar.fill = '#' - bar.suffix = suffix[bar_type] - bar.bar_prefix = ' [' - bar.bar_suffix = '] ' - - return bar - +class MD5: + def __init__(self, output): + self.out = output -def md5(filename, size): + def compute(self, filename, size): - BLOCKSIZE = 2 ** 22 # 4MB + BLOCKSIZE = 2 ** 22 # 4MB - progressbar = progress("Calculating md5sum:", 'mb') - progressbar.max = ((size + 2 ** 20 - 1) // (2 ** 20)) - md5 = hashlib.md5() - with open(filename, "r") as src: - left = size - while left > 0: - length = min(left, BLOCKSIZE) - data = src.read(length) - md5.update(data) - left -= length - progressbar.goto((size - left) // (2 ** 20)) + progressbar = self.out.Progress("Calculating md5sum:", 'mb') + progressbar.max = ((size + 2 ** 20 - 1) // (2 ** 20)) + md5 = hashlib.md5() + with open(filename, "r") as src: + left = size + while left > 0: + length = min(left, BLOCKSIZE) + data = src.read(length) + md5.update(data) + left -= length + progressbar.goto((size - left) // (2 ** 20)) - checksum = md5.hexdigest() - output("\rCalculating md5sum...\033[K", False) - success(checksum) + checksum = md5.hexdigest() + progressbar.success(checksum) - return checksum + return checksum # vim: set sta sts=4 shiftwidth=4 sw=4 et ai :