eggs/mercurial-1.7.3-py2.6-linux-x86_64.egg/hgext/progress.py
changeset 69 c6bca38c1cbf
equal deleted inserted replaced
68:5ff1fc726848 69:c6bca38c1cbf
       
     1 # progress.py show progress bars for some actions
       
     2 #
       
     3 # Copyright (C) 2010 Augie Fackler <durin42@gmail.com>
       
     4 #
       
     5 # This program is free software; you can redistribute it and/or modify it
       
     6 # under the terms of the GNU General Public License as published by the
       
     7 # Free Software Foundation; either version 2 of the License, or (at your
       
     8 # option) any later version.
       
     9 #
       
    10 # This program is distributed in the hope that it will be useful, but
       
    11 # WITHOUT ANY WARRANTY; without even the implied warranty of
       
    12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
       
    13 # Public License for more details.
       
    14 #
       
    15 # You should have received a copy of the GNU General Public License along
       
    16 # with this program; if not, write to the Free Software Foundation, Inc.,
       
    17 # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
       
    18 
       
    19 """show progress bars for some actions
       
    20 
       
    21 This extension uses the progress information logged by hg commands
       
    22 to draw progress bars that are as informative as possible. Some progress
       
    23 bars only offer indeterminate information, while others have a definite
       
    24 end point.
       
    25 
       
    26 The following settings are available::
       
    27 
       
    28   [progress]
       
    29   delay = 3 # number of seconds (float) before showing the progress bar
       
    30   refresh = 0.1 # time in seconds between refreshes of the progress bar
       
    31   format = topic bar number # format of the progress bar
       
    32   width = <none> # if set, the maximum width of the progress information
       
    33                  # (that is, min(width, term width) will be used)
       
    34   clear-complete = True # clear the progress bar after it's done
       
    35   disable = False # if true, don't show a progress bar
       
    36   assume-tty = False # if true, ALWAYS show a progress bar, unless
       
    37                      # disable is given
       
    38 
       
    39 Valid entries for the format field are topic, bar, number, unit, and
       
    40 item. item defaults to the last 20 characters of the item, but this
       
    41 can be changed by adding either ``-<num>`` which would take the last
       
    42 num characters, or ``+<num>`` for the first num characters.
       
    43 """
       
    44 
       
    45 import sys
       
    46 import time
       
    47 
       
    48 from mercurial import util
       
    49 
       
    50 def spacejoin(*args):
       
    51     return ' '.join(s for s in args if s)
       
    52 
       
    53 def shouldprint(ui):
       
    54     return (getattr(sys.stderr, 'isatty', None) and
       
    55             (sys.stderr.isatty() or ui.configbool('progress', 'assume-tty')))
       
    56 
       
    57 class progbar(object):
       
    58     def __init__(self, ui):
       
    59         self.ui = ui
       
    60         self.resetstate()
       
    61 
       
    62     def resetstate(self):
       
    63         self.topics = []
       
    64         self.printed = False
       
    65         self.lastprint = time.time() + float(self.ui.config(
       
    66             'progress', 'delay', default=3))
       
    67         self.indetcount = 0
       
    68         self.refresh = float(self.ui.config(
       
    69             'progress', 'refresh', default=0.1))
       
    70         self.order = self.ui.configlist(
       
    71             'progress', 'format',
       
    72             default=['topic', 'bar', 'number'])
       
    73 
       
    74     def show(self, topic, pos, item, unit, total):
       
    75         if not shouldprint(self.ui):
       
    76             return
       
    77         termwidth = self.width()
       
    78         self.printed = True
       
    79         head = ''
       
    80         needprogress = False
       
    81         tail = ''
       
    82         for indicator in self.order:
       
    83             add = ''
       
    84             if indicator == 'topic':
       
    85                 add = topic
       
    86             elif indicator == 'number':
       
    87                 if total:
       
    88                     add = ('% ' + str(len(str(total))) +
       
    89                            's/%s') % (pos, total)
       
    90                 else:
       
    91                     add = str(pos)
       
    92             elif indicator.startswith('item') and item:
       
    93                 slice = 'end'
       
    94                 if '-' in indicator:
       
    95                     wid = int(indicator.split('-')[1])
       
    96                 elif '+' in indicator:
       
    97                     slice = 'beginning'
       
    98                     wid = int(indicator.split('+')[1])
       
    99                 else:
       
   100                     wid = 20
       
   101                 if slice == 'end':
       
   102                     add = item[-wid:]
       
   103                 else:
       
   104                     add = item[:wid]
       
   105                 add += (wid - len(add)) * ' '
       
   106             elif indicator == 'bar':
       
   107                 add = ''
       
   108                 needprogress = True
       
   109             elif indicator == 'unit' and unit:
       
   110                 add = unit
       
   111             if not needprogress:
       
   112                 head = spacejoin(head, add)
       
   113             else:
       
   114                 tail = spacejoin(add, tail)
       
   115         if needprogress:
       
   116             used = 0
       
   117             if head:
       
   118                 used += len(head) + 1
       
   119             if tail:
       
   120                 used += len(tail) + 1
       
   121             progwidth = termwidth - used - 3
       
   122             if total and pos <= total:
       
   123                 amt = pos * progwidth // total
       
   124                 bar = '=' * (amt - 1)
       
   125                 if amt > 0:
       
   126                     bar += '>'
       
   127                 bar += ' ' * (progwidth - amt)
       
   128             else:
       
   129                 progwidth -= 3
       
   130                 self.indetcount += 1
       
   131                 # mod the count by twice the width so we can make the
       
   132                 # cursor bounce between the right and left sides
       
   133                 amt = self.indetcount % (2 * progwidth)
       
   134                 amt -= progwidth
       
   135                 bar = (' ' * int(progwidth - abs(amt)) + '<=>' +
       
   136                        ' ' * int(abs(amt)))
       
   137             prog = ''.join(('[', bar , ']'))
       
   138             out = spacejoin(head, prog, tail)
       
   139         else:
       
   140             out = spacejoin(head, tail)
       
   141         sys.stderr.write('\r' + out[:termwidth])
       
   142         sys.stderr.flush()
       
   143 
       
   144     def clear(self):
       
   145         if not shouldprint(self.ui):
       
   146             return
       
   147         sys.stderr.write('\r%s\r' % (' ' * self.width()))
       
   148 
       
   149     def complete(self):
       
   150         if not shouldprint(self.ui):
       
   151             return
       
   152         if self.ui.configbool('progress', 'clear-complete', default=True):
       
   153             self.clear()
       
   154         else:
       
   155             sys.stderr.write('\n')
       
   156         sys.stderr.flush()
       
   157 
       
   158     def width(self):
       
   159         tw = self.ui.termwidth()
       
   160         return min(int(self.ui.config('progress', 'width', default=tw)), tw)
       
   161 
       
   162     def progress(self, topic, pos, item='', unit='', total=None):
       
   163         if pos is None:
       
   164             if self.topics and self.topics[-1] == topic and self.printed:
       
   165                 self.complete()
       
   166                 self.resetstate()
       
   167         else:
       
   168             if topic not in self.topics:
       
   169                 self.topics.append(topic)
       
   170             now = time.time()
       
   171             if (now - self.lastprint >= self.refresh
       
   172                 and topic == self.topics[-1]):
       
   173                 self.lastprint = now
       
   174                 self.show(topic, pos, item, unit, total)
       
   175 
       
   176 def uisetup(ui):
       
   177     class progressui(ui.__class__):
       
   178         _progbar = None
       
   179 
       
   180         def progress(self, *args, **opts):
       
   181             self._progbar.progress(*args, **opts)
       
   182             return super(progressui, self).progress(*args, **opts)
       
   183 
       
   184         def write(self, *args, **opts):
       
   185             if self._progbar.printed:
       
   186                 self._progbar.clear()
       
   187             return super(progressui, self).write(*args, **opts)
       
   188 
       
   189         def write_err(self, *args, **opts):
       
   190             if self._progbar.printed:
       
   191                 self._progbar.clear()
       
   192             return super(progressui, self).write_err(*args, **opts)
       
   193 
       
   194     # Apps that derive a class from ui.ui() can use
       
   195     # setconfig('progress', 'disable', 'True') to disable this extension
       
   196     if ui.configbool('progress', 'disable'):
       
   197         return
       
   198     if shouldprint(ui) and not ui.debugflag and not ui.quiet:
       
   199         ui.__class__ = progressui
       
   200         # we instantiate one globally shared progress bar to avoid
       
   201         # competing progress bars when multiple UI objects get created
       
   202         if not progressui._progbar:
       
   203             progressui._progbar = progbar(ui)
       
   204 
       
   205 def reposetup(ui, repo):
       
   206     uisetup(repo.ui)