Commits

Lukasz Balcerzak committed cefd3e2

import_media command gets fancy progressbar made by Nadia Alramli

Comments (0)

Files changed (4)

richtemplates/extras/progressbar.py

+# -*- coding: utf-8 -*-
+# Copyright: 2009 Nadia Alramli
+# License: BSD
+"""Draws an animated terminal progress bar
+Usage:
+    p = ProgressBar("blue")
+    p.render(percentage, message)
+"""
+
+import terminal
+import sys
+
+class ProgressBar(object):
+    """Terminal progress bar class"""
+    TEMPLATE = (
+     '%(percent)-2s%% %(color)s%(progress)s%(normal)s%(empty)s %(message)s\n'
+    )
+    PADDING = 7
+
+    def __init__(self, color=None, width=None, block='█', empty=' '):
+        """
+        color -- color name (BLUE GREEN CYAN RED MAGENTA YELLOW WHITE BLACK)
+        width -- bar width (optinal)
+        block -- progress display character (default '█')
+        empty -- bar display character (default ' ')
+        """
+        if color:
+            self.color = getattr(terminal, color.upper())
+        else:
+            self.color = ''
+        if width and width < terminal.COLUMNS - self.PADDING:
+            self.width = width
+        else:
+            # Adjust to the width of the terminal
+            self.width = terminal.COLUMNS - self.PADDING
+        self.block = block
+        self.empty = empty
+        self.progress = None
+        self.lines = 0
+
+    def render(self, percent, message = ''):
+        """Print the progress bar
+        percent -- the progress percentage %
+        message -- message string (optional)
+        """
+        inline_msg_len = 0
+        if message:
+            # The length of the first line in the message
+            inline_msg_len = len(message.splitlines()[0])
+        if inline_msg_len + self.width + self.PADDING > terminal.COLUMNS:
+            # The message is too long to fit in one line.
+            # Adjust the bar width to fit.
+            bar_width = terminal.COLUMNS - inline_msg_len -self.PADDING
+        else:
+            bar_width = self.width
+
+        # Check if render is called for the first time
+        if self.progress != None:
+            self.clear()
+        self.progress = (bar_width * percent) / 100
+        data = self.TEMPLATE % {
+            'percent': percent,
+            'color': self.color,
+            'progress': self.block * self.progress,
+            'normal': terminal.NORMAL,
+            'empty': self.empty * (bar_width - self.progress),
+            'message': message
+        }
+        sys.stdout.write(data)
+        sys.stdout.flush()
+        # The number of lines printed
+        self.lines = len(data.splitlines())
+
+    def clear(self):
+        """Clear all printed lines"""
+        sys.stdout.write(
+            self.lines * (terminal.UP + terminal.BOL + terminal.CLEAR_EOL)
+        )
+
+
+def main():
+    import time
+    p = ProgressBar(color='GREEN', width=20)
+    for i in xrange(101):
+        p.render(i, 'step %s' % i)
+        time.sleep(0.01)
+        #if i in (20, 60, 65):
+        #    time.sleep(0.2)
+    p.render(5, 'foobar')
+
+if __name__ == '__main__':
+    main()

richtemplates/extras/terminal.py

+# Copyright: 2009 Nadia Alramli
+# License: BSD
+
+"""Terminal controller module
+Example of usage:
+    print BG_BLUE + 'Text on blue background' + NORMAL
+    print BLUE + UNDERLINE + 'Blue underlined text' + NORMAL
+    print BLUE + BG_YELLOW + BOLD + 'text' + NORMAL
+"""
+
+import sys
+
+# The current module
+MODULE = sys.modules[__name__]
+
+COLORS = "BLUE GREEN CYAN RED MAGENTA YELLOW WHITE BLACK".split()
+# List of terminal controls, you can add more to the list.
+CONTROLS = {
+    'BOL':'cr', 'UP':'cuu1', 'DOWN':'cud1', 'LEFT':'cub1', 'RIGHT':'cuf1',
+    'CLEAR_SCREEN':'clear', 'CLEAR_EOL':'el', 'CLEAR_BOL':'el1',
+    'CLEAR_EOS':'ed', 'BOLD':'bold', 'BLINK':'blink', 'DIM':'dim',
+    'REVERSE':'rev', 'UNDERLINE':'smul', 'NORMAL':'sgr0',
+    'HIDE_CURSOR':'cinvis', 'SHOW_CURSOR':'cnorm'
+}
+
+# List of numeric capabilities
+VALUES = {
+    'COLUMNS':'cols', # Width of the terminal (None for unknown)
+    'LINES':'lines',  # Height of the terminal (None for unknown)
+    'MAX_COLORS': 'colors',
+}
+
+def default():
+    """Set the default attribute values"""
+    for color in COLORS:
+        setattr(MODULE, color, '')
+        setattr(MODULE, 'BG_%s' % color, '')
+    for control in CONTROLS:
+        setattr(MODULE, control, '')
+    for value in VALUES:
+        setattr(MODULE, value, None)
+
+def setup():
+    """Set the terminal control strings"""
+    # Initializing the terminal
+    curses.setupterm()
+    # Get the color escape sequence template or '' if not supported
+    # setab and setaf are for ANSI escape sequences
+    bgColorSeq = curses.tigetstr('setab') or curses.tigetstr('setb') or ''
+    fgColorSeq = curses.tigetstr('setaf') or curses.tigetstr('setf') or ''
+
+    for color in COLORS:
+        # Get the color index from curses
+        colorIndex = getattr(curses, 'COLOR_%s' % color)
+        # Set the color escape sequence after filling the template with index
+        setattr(MODULE, color, curses.tparm(fgColorSeq, colorIndex))
+        # Set background escape sequence
+        setattr(
+            MODULE, 'BG_%s' % color, curses.tparm(bgColorSeq, colorIndex)
+        )
+    for control in CONTROLS:
+        # Set the control escape sequence
+        setattr(MODULE, control, curses.tigetstr(CONTROLS[control]) or '')
+    for value in VALUES:
+        # Set terminal related values
+        setattr(MODULE, value, curses.tigetnum(VALUES[value]))
+
+def render(text):
+    """Helper function to apply controls easily
+    Example:
+    apply("%(GREEN)s%(BOLD)stext%(NORMAL)s") -> a bold green text
+    """
+    return text % MODULE.__dict__
+
+try:
+    import curses
+    setup()
+except Exception, e:
+    # There is a failure; set all attributes to default
+    print 'Warning: %s' % e
+    default()
+

richtemplates/management/helpers.py

 import logging
 
 from django.core.management.base import _make_writeable, CommandError
+from shutil import copy2, copystat, Error, WindowsError
+from richtemplates.extras.progressbar import ProgressBar
 
 def copy_dir_helper(src, dst, force=False):
     """
             shutil.rmtree(dst)
         else:
             raise CommandError("Target %s already exists" % dst)
-    shutil.copytree(src, dst)
+    copytree(src, dst, draw_pbar=True)
     logging.info("Copied %s into %s" % (src, dst))
     make_writeable(dst)
 
     return dict((key, val) for key, val in inspect.getmembers(settings_module)\
         if key == key.upper())
 
+def copytree(src, dst, symlinks=False, ignore=None, draw_pbar=False):
+    """
+    Copies directory from ``src`` into ``dst``.
+
+    Codes taken from shutil module, with some progressbar sugar.
+    """
+    names = os.listdir(src)
+    if ignore is not None:
+        ignored_names = ignore(src, names)
+    else:
+        ignored_names = set()
+
+    os.makedirs(dst)
+    errors = []
+    pbar = ProgressBar(color='GREEN', width=40)
+    total = len(names)
+
+    for i in xrange(total):
+        name, perc = names[i], 100 * i / total
+        draw_pbar and pbar.render(perc)
+        if name in ignored_names:
+            continue
+        srcname = os.path.join(src, name)
+        dstname = os.path.join(dst, name)
+        try:
+            if symlinks and os.path.islink(srcname):
+                linkto = os.readlink(srcname)
+                os.symlink(linkto, dstname)
+            elif os.path.isdir(srcname):
+                copytree(srcname, dstname, symlinks, ignore)
+            else:
+                copy2(srcname, dstname)
+            # XXX What about devices, sockets etc.?
+        except (IOError, os.error), why:
+            errors.append((srcname, dstname, str(why)))
+        # catch the Error from the recursive copytree so that we can
+        # continue with other files
+        except Error, err:
+            errors.extend(err.args[0])
+    try:
+        copystat(src, dst)
+    except OSError, why:
+        if WindowsError is not None and isinstance(why, WindowsError):
+            # Copying file access times may fail on Windows
+            pass
+        else:
+            errors.extend((src, dst, str(why)))
+    if errors:
+        raise Error, errors
+    draw_pbar and pbar.render(100, "Done")
+

richtemplates/templatetags/native.py

 autocomplete_field.function = True
 
 def do_get_code_style(context):
-    user = context['user']
+    user = context.get('user', None)
     if user and user.is_authenticated():
         style = getattr(user.get_profile(),
             richtemplates_settings.PROFILE_CODE_STYLE_FIELD,