[PATCH 2 of 5 RFC] hglib: a wrapper around hg's cmdserver, written in Python
Idan Kamara
idankk86 at gmail.com
Fri Jun 3 15:04:41 CDT 2011
# HG changeset patch
# User Idan Kamara <idankk86 at gmail.com>
# Date 1307111464 -10800
# Node ID 15c24865581d773d00dec51ebd0cbe222feec6e0
# Parent 5b9901ab0f4c60450ecd5c112fd937493a043667
hglib: a wrapper around hg's cmdserver, written in Python
diff -r 5b9901ab0f4c -r 15c24865581d contrib/hglib/hglib.py
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/contrib/hglib/hglib.py Fri Jun 03 17:31:04 2011 +0300
@@ -0,0 +1,100 @@
+# hglib.py
+#
+# Copyright Matt Mackall <mpm at selenic.com>
+#
+# This software may be used and distributed according to the terms of the
+# GNU General Public License version 2 or any later version.
+
+import subprocess
+import struct
+import cStringIO
+
+HGPATH = 'hg'
+
+def connect(path, out, err, extraconfigs=None):
+ return hgclient(path, out, err, extraconfigs)
+
+class CommandFailed(Exception):
+ pass
+
+class hgclient(object):
+ inputfmt = '>I'
+ outputfmt = '>cI'
+ outputfmtsize = struct.calcsize(outputfmt)
+ retfmt = '>i'
+
+ def __init__(self, path, out, err, extraconfigs):
+ self.channels = {'o' : out, 'e' : err}
+ cmdline = [HGPATH, '-R', path, 'serve', '--cmdserver', 'pipe']
+
+ if extraconfigs:
+ cmdline += ['--config'] + extraconfigs
+
+ self.proc = subprocess.Popen(cmdline,
+ stdin=subprocess.PIPE, stdout=subprocess.PIPE)
+
+ def terminated(self):
+ if self.proc.poll() is not None:
+ return self.proc.returncode
+ else:
+ return None
+
+ def rawcommand(self, args):
+ if not self.proc or self.terminated():
+ raise ValueError("server not connected")
+
+ args = '\0'.join(args)
+ self.proc.stdin.write(struct.pack(hgclient.inputfmt, len(args)))
+ self.proc.stdin.write(args)
+
+ while True:
+ data = self.proc.stdout.read(hgclient.outputfmtsize)
+ (channel, length) = struct.unpack(hgclient.outputfmt, data)
+ data = self.proc.stdout.read(length)
+ if data[0] == '\0':
+ # end of output, this is the return code
+ break
+ self.channels[channel].write(data)
+
+ ret = struct.unpack(hgclient.retfmt, data[1:])[0]
+ return ret
+
+ def outputrawcommand(self, args):
+ self.redirect()
+ ret = self.rawcommand(args)
+ out, err = self.restore()
+
+ return (ret, out, err)
+
+ def status(self):
+ ret, out, err = self.outputrawcommand(['status', '-0'])
+
+ if ret:
+ raise CommandFailed(ret, out, err)
+
+ d = dict((c, []) for c in 'MARC!?I ')
+
+ for entry in out.split('\0'):
+ if entry:
+ t, f = entry.split(' ', 1)
+ d[t].append(f)
+
+ return d
+
+ def close(self):
+ self.proc.stdin.close()
+ self.proc.wait()
+ ret = self.proc.returncode
+ self.proc = None
+
+ return ret
+
+ def redirect(self):
+ self.old = self.channels['o'], self.channels['e']
+ self.channels['o'], self.channels['e'] = \
+ cStringIO.StringIO(), cStringIO.StringIO()
+
+ def restore(self):
+ out, err = self.channels['o'].getvalue(), self.channels['e'].getvalue()
+ self.channels['o'], self.channels['e'] = self.old
+ return out, err
More information about the Mercurial-devel
mailing list