changeset 5873:ecb4eb0cbff2

convert: make svn revision iterator interruptible
author Patrick Mezard <pmezard@gmail.com>
date Thu, 17 Jan 2008 23:46:56 +0100
parents 7d4149cccc5d
children 866aa7ae2612
files hgext/convert/subversion.py
diffstat 1 files changed, 56 insertions(+), 45 deletions(-) [+]
line wrap: on
line diff
--- a/hgext/convert/subversion.py	Thu Jan 17 23:46:56 2008 +0100
+++ b/hgext/convert/subversion.py	Thu Jan 17 23:46:56 2008 +0100
@@ -89,6 +89,9 @@
                        receiver)
     except SubversionException, (inst, num):
         pickle.dump(num, fp, protocol)
+    except IOError:
+        # Caller may interrupt the iteration
+        pickle.dump(None, fp, protocol)
     else:
         pickle.dump(None, fp, protocol)
     fp.close()
@@ -102,6 +105,39 @@
     args = decodeargs(sys.stdin.read())
     get_log_child(sys.stdout, *args)
 
+class logstream:
+    """Interruptible revision log iterator."""
+    def __init__(self, stdout):
+        self._stdout = stdout
+
+    def __iter__(self):
+        while True:
+            entry = pickle.load(self._stdout)
+            try:
+                orig_paths, revnum, author, date, message = entry
+            except:
+                if entry is None:
+                    break
+                raise SubversionException("child raised exception", entry)
+            yield entry
+
+    def close(self):
+        if self._stdout:
+            self._stdout.close()
+            self._stdout = None
+
+def get_log(url, paths, start, end, limit=0, discover_changed_paths=True,
+                strict_node_history=False):
+    args = [url, paths, start, end, limit, discover_changed_paths,
+            strict_node_history]
+    arg = encodeargs(args)
+    hgexe = util.hgexecutable()
+    cmd = '%s debugsvnlog' % util.shellquote(hgexe)
+    stdin, stdout = os.popen2(cmd, 'b')
+    stdin.write(arg)
+    stdin.close()
+    return logstream(stdout)
+
 # SVN conversion code stolen from bzr-svn and tailor
 class svn_source(converter_source):
     def __init__(self, ui, url, rev=None):
@@ -263,38 +299,11 @@
         del self.commits[rev]
         return commit
 
-    def get_log(self, paths, start, end, limit=0, discover_changed_paths=True,
-                strict_node_history=False):
-
-        def parent(fp):
-            while True:
-                entry = pickle.load(fp)
-                try:
-                    orig_paths, revnum, author, date, message = entry
-                except:
-                    if entry is None:
-                        break
-                    raise SubversionException("child raised exception", entry)
-                yield entry
-
-        args = [self.url, paths, start, end, limit, discover_changed_paths,
-                strict_node_history]
-        arg = encodeargs(args)
-        hgexe = util.hgexecutable()
-        cmd = '%s debugsvnlog' % util.shellquote(hgexe)
-        stdin, stdout = os.popen2(cmd, 'b')
-
-        stdin.write(arg)
-        stdin.close()
-
-        for p in parent(stdout):
-            yield p
-
     def gettags(self):
         tags = {}
         start = self.revnum(self.head)
         try:
-            for entry in self.get_log([self.tags], 0, start):
+            for entry in get_log(self.url, [self.tags], 0, start):
                 orig_paths, revnum, author, date, message = entry
                 for path in orig_paths:
                     if not path.startswith(self.tags+'/'):
@@ -641,23 +650,25 @@
 
         try:
             firstcset = None
-            branched = False
-            for entry in self.get_log([self.module], from_revnum, to_revnum):
-                if branched:
-                    # The iterator must be exhausted for the child process
-                    # to terminate cleanly.
-                    continue
-                paths, revnum, author, date, message = entry
-                if self.is_blacklisted(revnum):
-                    self.ui.note('skipping blacklisted revision %d\n' % revnum)
-                    continue
-                if paths is None:
-                    self.ui.debug('revision %d has no entries\n' % revnum)
-                    continue
-                cset, branched = parselogentry(paths, revnum, author, 
-                                               date, message)
-                if cset:
-                    firstcset = cset
+            stream = get_log(self.url, [self.module], from_revnum, to_revnum)
+            try:
+                for entry in stream:
+                    paths, revnum, author, date, message = entry
+                    if self.is_blacklisted(revnum):
+                        self.ui.note('skipping blacklisted revision %d\n' 
+                                     % revnum)
+                        continue
+                    if paths is None:
+                        self.ui.debug('revision %d has no entries\n' % revnum)
+                        continue
+                    cset, branched = parselogentry(paths, revnum, author, 
+                                                   date, message)
+                    if cset:
+                        firstcset = cset
+                    if branched:
+                        break
+            finally:
+                stream.close()
 
             if firstcset and not firstcset.parents:
                 # The first revision of the sequence (the last fetched one)