Revision 339be5a8

b/lib/utils.py
45 45
import signal
46 46
import datetime
47 47
import calendar
48
import collections
48 49

  
49 50
from cStringIO import StringIO
50 51

  
......
2761 2762
                "Failed to unlock %s" % self.filename)
2762 2763

  
2763 2764

  
2765
class LineSplitter:
2766
  """Splits data chunks into lines separated by newline.
2767

  
2768
  Instances provide a file-like interface.
2769

  
2770
  """
2771
  def __init__(self, line_fn, *args):
2772
    """Initializes this class.
2773

  
2774
    @type line_fn: callable
2775
    @param line_fn: Function called for each line, first parameter is line
2776
    @param args: Extra arguments for L{line_fn}
2777

  
2778
    """
2779
    assert callable(line_fn)
2780

  
2781
    if args:
2782
      # Python 2.4 doesn't have functools.partial yet
2783
      self._line_fn = \
2784
        lambda line: line_fn(line, *args) # pylint: disable-msg=W0142
2785
    else:
2786
      self._line_fn = line_fn
2787

  
2788
    self._lines = collections.deque()
2789
    self._buffer = ""
2790

  
2791
  def write(self, data):
2792
    parts = (self._buffer + data).split("\n")
2793
    self._buffer = parts.pop()
2794
    self._lines.extend(parts)
2795

  
2796
  def flush(self):
2797
    while self._lines:
2798
      self._line_fn(self._lines.popleft().rstrip("\r\n"))
2799

  
2800
  def close(self):
2801
    self.flush()
2802
    if self._buffer:
2803
      self._line_fn(self._buffer)
2804

  
2805

  
2764 2806
def SignalHandled(signums):
2765 2807
  """Signal Handled decoration.
2766 2808

  
b/test/ganeti.utils_unittest.py
1558 1558
      self.fail("Didn't detect inner loop's exception")
1559 1559

  
1560 1560

  
1561
class TestLineSplitter(unittest.TestCase):
1562
  def test(self):
1563
    lines = []
1564
    ls = utils.LineSplitter(lines.append)
1565
    ls.write("Hello World\n")
1566
    self.assertEqual(lines, [])
1567
    ls.write("Foo\n Bar\r\n ")
1568
    ls.write("Baz")
1569
    ls.write("Moo")
1570
    self.assertEqual(lines, [])
1571
    ls.flush()
1572
    self.assertEqual(lines, ["Hello World", "Foo", " Bar"])
1573
    ls.close()
1574
    self.assertEqual(lines, ["Hello World", "Foo", " Bar", " BazMoo"])
1575

  
1576
  def _testExtra(self, line, all_lines, p1, p2):
1577
    self.assertEqual(p1, 999)
1578
    self.assertEqual(p2, "extra")
1579
    all_lines.append(line)
1580

  
1581
  def testExtraArgsNoFlush(self):
1582
    lines = []
1583
    ls = utils.LineSplitter(self._testExtra, lines, 999, "extra")
1584
    ls.write("\n\nHello World\n")
1585
    ls.write("Foo\n Bar\r\n ")
1586
    ls.write("")
1587
    ls.write("Baz")
1588
    ls.write("Moo\n\nx\n")
1589
    self.assertEqual(lines, [])
1590
    ls.close()
1591
    self.assertEqual(lines, ["", "", "Hello World", "Foo", " Bar", " BazMoo",
1592
                             "", "x"])
1593

  
1594

  
1561 1595
if __name__ == '__main__':
1562 1596
  testutils.GanetiTestProgram()

Also available in: Unified diff