~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to patches/annotate4.patch

  • Committer: Martin Pool
  • Date: 2005-06-10 06:34:26 UTC
  • Revision ID: mbp@sourcefrog.net-20050610063426-cfcf5c0f96c271ec
- split out updated progress indicator

Show diffs side-by-side

added added

removed removed

Lines of Context:
500
500
+    test()
501
501
+# arch-tag: d1541a25-eac5-4de9-a476-08a7cecd5683
502
502
 
503
 
*** added file 'bzrlib/progress.py'
504
 
--- /dev/null 
505
 
+++ bzrlib/progress.py 
506
 
@@ -0,0 +1,138 @@
507
 
+# Copyright (C) 2005 Aaron Bentley
508
 
+# <aaron.bentley@utoronto.ca>
509
 
+#
510
 
+#    This program is free software; you can redistribute it and/or modify
511
 
+#    it under the terms of the GNU General Public License as published by
512
 
+#    the Free Software Foundation; either version 2 of the License, or
513
 
+#    (at your option) any later version.
514
 
+#
515
 
+#    This program is distributed in the hope that it will be useful,
516
 
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
517
 
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
518
 
+#    GNU General Public License for more details.
519
 
+#
520
 
+#    You should have received a copy of the GNU General Public License
521
 
+#    along with this program; if not, write to the Free Software
522
 
+#    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
523
 
+
524
 
+import sys
525
 
+import datetime
526
 
+
527
 
+class Progress(object):
528
 
+    def __init__(self, units, current, total=None):
529
 
+        self.units = units
530
 
+        self.current = current
531
 
+        self.total = total
532
 
+
533
 
+    def _get_percent(self):
534
 
+        if self.total is not None and self.current is not None:
535
 
+            return 100.0 * self.current / self.total
536
 
+
537
 
+    percent = property(_get_percent)
538
 
+
539
 
+    def __str__(self):
540
 
+        if self.total is not None:
541
 
+            return "%i of %i %s %.1f%%" % (self.current, self.total, self.units,
542
 
+                                         self.percent)
543
 
+        else:
544
 
+            return "%i %s" (self.current, self.units) 
545
 
+
546
 
+class ProgressBar(object):
547
 
+    def __init__(self):
548
 
+        self.start = None
549
 
+        object.__init__(self)
550
 
+
551
 
+    def __call__(self, progress):
552
 
+        if self.start is None:
553
 
+            self.start = datetime.datetime.now()
554
 
+        progress_bar(progress, start_time=self.start)
555
 
+        
556
 
+def divide_timedelta(delt, divisor):
557
 
+    """Divides a timedelta object"""
558
 
+    return datetime.timedelta(float(delt.days)/divisor, 
559
 
+                              float(delt.seconds)/divisor, 
560
 
+                              float(delt.microseconds)/divisor)
561
 
+
562
 
+def str_tdelta(delt):
563
 
+    if delt is None:
564
 
+        return "-:--:--"
565
 
+    return str(datetime.timedelta(delt.days, delt.seconds))
566
 
+
567
 
+def get_eta(start_time, progress, enough_samples=20):
568
 
+    if start_time is None or progress.current == 0:
569
 
+        return None
570
 
+    elif progress.current < enough_samples:
571
 
+        return None
572
 
+    elapsed = datetime.datetime.now() - start_time
573
 
+    total_duration = divide_timedelta((elapsed) * long(progress.total), 
574
 
+                                      progress.current)
575
 
+    if elapsed < total_duration:
576
 
+        eta = total_duration - elapsed
577
 
+    else:
578
 
+        eta = total_duration - total_duration
579
 
+    return eta
580
 
+
581
 
+def progress_bar(progress, start_time=None):
582
 
+    eta = get_eta(start_time, progress)
583
 
+    if start_time is not None:
584
 
+        eta_str = " "+str_tdelta(eta)
585
 
+    else:
586
 
+        eta_str = ""
587
 
+
588
 
+    fmt = " %i of %i %s (%.1f%%)"
589
 
+    f = fmt % (progress.total, progress.total, progress.units, 100.0)
590
 
+    max = len(f)
591
 
+    cols = 77 - max
592
 
+    if start_time is not None:
593
 
+        cols -= len(eta_str)
594
 
+    markers = int (float(cols) * progress.current / progress.total)
595
 
+    txt = fmt % (progress.current, progress.total, progress.units,
596
 
+                 progress.percent)
597
 
+    sys.stderr.write("\r[%s%s]%s%s" % ('='*markers, ' '*(cols-markers), txt, 
598
 
+                                       eta_str))
599
 
+
600
 
+def clear_progress_bar():
601
 
+    sys.stderr.write('\r%s\r' % (' '*79))
602
 
+
603
 
+def spinner_str(progress, show_text=False):
604
 
+    """
605
 
+    Produces the string for a textual "spinner" progress indicator
606
 
+    :param progress: an object represinting current progress
607
 
+    :param show_text: If true, show progress text as well
608
 
+    :return: The spinner string
609
 
+
610
 
+    >>> spinner_str(Progress("baloons", 0))
611
 
+    '|'
612
 
+    >>> spinner_str(Progress("baloons", 5))
613
 
+    '/'
614
 
+    >>> spinner_str(Progress("baloons", 6), show_text=True)
615
 
+    '- 6 baloons'
616
 
+    """
617
 
+    positions = ('|', '/', '-', '\\')
618
 
+    text = positions[progress.current % 4]
619
 
+    if show_text:
620
 
+        text+=" %i %s" % (progress.current, progress.units)
621
 
+    return text
622
 
+
623
 
+def spinner(progress, show_text=False, output=sys.stderr):
624
 
+    """
625
 
+    Update a spinner progress indicator on an output
626
 
+    :param progress: The progress to display
627
 
+    :param show_text: If true, show text as well as spinner
628
 
+    :param output: The output to write to
629
 
+
630
 
+    >>> spinner(Progress("baloons", 6), show_text=True, output=sys.stdout)
631
 
+    \r- 6 baloons
632
 
+    """
633
 
+    output.write('\r%s' % spinner_str(progress, show_text))
634
 
+
635
 
+def run_tests():
636
 
+    import doctest
637
 
+    result = doctest.testmod()
638
 
+    if result[1] > 0:
639
 
+        if result[0] == 0:
640
 
+            print "All tests passed"
641
 
+    else:
642
 
+        print "No tests to run"
643
 
+if __name__ == "__main__":
644
 
+    run_tests()
645
 
 
646
503
*** added directory 'testdata'
647
504
*** added file 'testdata/diff'
648
505
--- /dev/null