[PATCH 2 of 3] convert/mtn: use mtn "automate stdio" when available
daniel.atallah at gmail.com
daniel.atallah at gmail.com
Wed Mar 23 14:24:49 CDT 2011
# HG changeset patch
# User Daniel Atallah <daniel.atallah at gmail.com>
# Date 1300904816 14400
# Branch stable
# Node ID d2ef3495b1a62785683fc2a57212e8f2d2500fc6
# Parent 0fb617760b931cd25537e3362af52b2cfbd1a329
convert/mtn: use mtn "automate stdio" when available
This causes a single long-running mtn process to be used instead of spawning a
new process per operation.
diff --git a/hgext/convert/monotone.py b/hgext/convert/monotone.py
--- a/hgext/convert/monotone.py
+++ b/hgext/convert/monotone.py
@@ -19,6 +19,7 @@
self.ui = ui
self.path = path
+ self.automatestdio = False
norepo = NoRepo(_("%s does not look like a monotone repository")
% path)
@@ -73,9 +74,105 @@
self.rev = rev
def mtnrun(self, *args, **kwargs):
+ if self.automatestdio:
+ return self.mtnrunstdio(*args, **kwargs)
+ else:
+ return self.mtnrunsingle(*args, **kwargs)
+
+ def mtnrunsingle(self, *args, **kwargs):
kwargs['d'] = self.path
return self.run0('automate', *args, **kwargs)
+ def mtnrunstdio(self, *args, **kwargs):
+ #Prepare the command in automate stdio format
+ command = []
+ for k, v in kwargs.iteritems():
+ command.append("%s:%s" % (len(k), k))
+ try:
+ command.append("%s:%s" % (len(v), v))
+ except TypeError:
+ pass
+ if len(command) > 0:
+ command.insert(0, 'o')
+ command.append('e')
+
+ command.append('l')
+ for arg in args:
+ command += "%s:%s" % (len(arg), arg)
+ command.append('e')
+ commandstr = ''.join(command)
+
+ self.ui.debug("mtn: Sending '%s'\n" % commandstr)
+ self.mtnwritefp.write(commandstr)
+ self.mtnwritefp.flush()
+
+ return self.mtnstdioreadcommandoutput(commandstr)
+
+ def mtnstdioreadpacket(self):
+ read = None
+ commandnbr = ''
+ while not read == ':':
+ read = self.mtnreadfp.read(1)
+ if read == '':
+ raise util.Abort('bad mtn packet - no end of commandnbr')
+ commandnbr += read
+ commandnbr = commandnbr[:-1]
+
+ stream = self.mtnreadfp.read(1)
+ if not stream in ['m', 'e', 'w', 'p', 't', 'l']:
+ raise util.Abort('bad mtn packet - bad stream type %s' % stream)
+
+ read = self.mtnreadfp.read(1)
+ if not read == ':':
+ raise util.Abort('bad mtn packet - no divider before size')
+
+ read = None
+ lengthstr = ''
+ while not read == ':':
+ read = self.mtnreadfp.read(1)
+ if read == '':
+ raise util.Abort('bad mtn packet - no end of packet size')
+ lengthstr += read
+ try:
+ length = long(lengthstr[:-1])
+ except TypeError:
+ raise util.Abort('bad mtn packet - bad packet size %s' % lengthstr)
+
+ read = self.mtnreadfp.read(length)
+ if not len(read) == length:
+ raise util.Abort('bad mtn packet - unable to read full packet " \
+ " read %s of %s' % (len(read), length))
+
+ return (commandnbr, stream, length, read)
+
+ def mtnstdioreadcommandoutput(self, command):
+ retval = ''
+ done = False
+ while not done:
+ commandnbr, stream, length, output = self.mtnstdioreadpacket()
+ self.ui.debug('mtn: read packet %s:%s:%s\n' %
+ (commandnbr, stream, length))
+
+ if stream == 'l':
+ #End of command
+ if not output == '0':
+ raise util.Abort('mtn command \'%s\' returned %s' %
+ (command, output))
+ done = True
+ elif stream in ['e', 'w']:
+ #Error, warning output
+ self.ui.warn(_('%s error:\n') % self.command)
+ self.ui.warn(output)
+ elif stream == 'p':
+ #Progress messages
+ self.ui.debug('mtn: ' + output)
+ elif stream == 'm':
+ #Main stream - command output
+ retval = output
+
+ return retval
+
+
def mtnloadmanifest(self, rev):
if self.manifest_rev == rev:
return
@@ -225,3 +322,43 @@
# This function is only needed to support --filemap
# ... and we don't support that
raise NotImplementedError()
+
+ def before(self):
+ #Check if we have a new enough version to use automate stdio
+ version = 0.0
+ try:
+ versionstr = self.mtnrunsingle("interface_version")
+ version = float(versionstr)
+ except:
+ raise util.Abort("unable to determine mtn automate interface "
+ "version")
+
+ if version >= 12.0:
+ self.automatestdio = True
+ self.ui.debug("mtn automate version %s - using automate stdio\n" %
+ (version))
+
+ #Mark commandline not to redirect stdin
+ self.redirectstdin = False
+ #launch the long-running automate stdio process
+ self.mtnwritefp, self.mtnreadfp = self._run2('automate', 'stdio',
+ '-d', self.path)
+ #read the headers
+ read = self.mtnreadfp.readline()
+ if not read == 'format-version: 2\n':
+ raise util.Abort('mtn automate stdio header unexpected: %s' %
+ (read))
+ while not read == '\n':
+ read = self.mtnreadfp.readline()
+ if read == '':
+ raise util.Abort("failed to reach end of mtn automate stdio"
+ " headers")
+ else:
+ self.ui.debug("mtn automate version %s - not using automate stdio "
+ "(automate >= 12.0 - mtn >= 0.46 is needed)\n" %(version))
+
+ def after(self):
+ if self.automatestdio:
+ self.mtnwritefp.close()
+ self.mtnreadfp.close()
+
More information about the Mercurial-devel
mailing list