From e83d9044924bd85085dc71063e1c3661c5c01b18 Mon Sep 17 00:00:00 2001 From: Avery Pennarun Date: Sat, 13 Feb 2010 18:21:09 -0500 Subject: [PATCH] Make CatPipe objects more resilient when interrupted. If we stopped iterating halfway through a particular object, the iterator wouldn't finishing reading all the data, which would mess up the state of the git-cat-file pipe. Now we read all the data even if we're going to just throw it away. --- git.py | 29 ++++++++++++++++++----------- helpers.py | 18 ++++++++++++++++++ 2 files changed, 36 insertions(+), 11 deletions(-) diff --git a/git.py b/git.py index 89b4c11..dbd61c1 100644 --- a/git.py +++ b/git.py @@ -617,11 +617,14 @@ class CatPipe: stdout=subprocess.PIPE, preexec_fn = _gitenv) self.get = self._fast_get + self.inprogress = 0 def _fast_get(self, id): + assert(not self.inprogress) assert(id.find('\n') < 0) assert(id.find('\r') < 0) assert(id[0] != '-') + self.inprogress += 1 self.p.stdin.write('%s\n' % id) hdr = self.p.stdout.readline() if hdr.endswith(' missing\n'): @@ -630,15 +633,16 @@ class CatPipe: if len(spl) != 3 or len(spl[0]) != 40: raise GitError('expected blob, got %r' % spl) (hex, type, size) = spl - it = iter(chunkyreader(self.p.stdout, int(spl[2]))) - try: - yield type - for blob in it: - yield blob - except StopIteration: - while 1: - it.next() - assert(self.p.stdout.readline() == '\n') + + def ondone(): + assert(self.p.stdout.readline() == '\n') + self.inprogress -= 1 + + it = AutoFlushIter(chunkyreader(self.p.stdout, int(spl[2])), + ondone = ondone) + yield type + for blob in it: + yield blob def _slow_get(self, id): assert(id.find('\n') < 0) @@ -674,8 +678,11 @@ class CatPipe: % type) def join(self, id): - for d in self._join(self.get(id)): - yield d + try: + for d in self._join(self.get(id)): + yield d + except StopIteration: + log('booger!\n') def cat(id): diff --git a/helpers.py b/helpers.py index 2bfdd53..2036ff4 100644 --- a/helpers.py +++ b/helpers.py @@ -182,6 +182,24 @@ def chunkyreader(f, count = None): yield b +class AutoFlushIter: + def __init__(self, it, ondone = None): + self.it = it + self.ondone = ondone + + def __iter__(self): + return self + + def next(self): + return self.it.next() + + def __del__(self): + for i in self.it: + pass + if self.ondone: + self.ondone() + + def slashappend(s): if s and not s.endswith('/'): return s + '/' -- 2.39.5