##// END OF EJS Templates
chg: forward job control signals to worker process (issue5051)...
chg: forward job control signals to worker process (issue5051) This is necessary to suspend/resume long pulls, interactive curses session, etc. The implementation is based on emacsclient, but our version doesn't test if chg process is foreground or not before propagating SIGCONT. This is because chg isn't always an interactive session. If we copy the SIGTTIN/SIGTTOU emulation from emacsclient, non-interactive session can't be moved to a background job. $ chg pull ^Z suspended $ bg %1 [1] continued [1] suspended (tty input) # wrong https://github.com/emacs-mirror/emacs/blob/0e96320/lib-src/emacsclient.c#L1094

File last commit:

r22993:24c5fd28 default
r28086:65d24ca3 default
Show More
hgclient.py
109 lines | 3.1 KiB | text/x-python | PythonLexer
# A minimal client for Mercurial's command server
import os, sys, signal, struct, socket, subprocess, time, cStringIO
def connectpipe(path=None):
cmdline = ['hg', 'serve', '--cmdserver', 'pipe']
if path:
cmdline += ['-R', path]
server = subprocess.Popen(cmdline, stdin=subprocess.PIPE,
stdout=subprocess.PIPE)
return server
class unixconnection(object):
def __init__(self, sockpath):
self.sock = sock = socket.socket(socket.AF_UNIX)
sock.connect(sockpath)
self.stdin = sock.makefile('wb')
self.stdout = sock.makefile('rb')
def wait(self):
self.stdin.close()
self.stdout.close()
self.sock.close()
class unixserver(object):
def __init__(self, sockpath, logpath=None, repopath=None):
self.sockpath = sockpath
cmdline = ['hg', 'serve', '--cmdserver', 'unix', '-a', sockpath]
if repopath:
cmdline += ['-R', repopath]
if logpath:
stdout = open(logpath, 'a')
stderr = subprocess.STDOUT
else:
stdout = stderr = None
self.server = subprocess.Popen(cmdline, stdout=stdout, stderr=stderr)
# wait for listen()
while self.server.poll() is None:
if os.path.exists(sockpath):
break
time.sleep(0.1)
def connect(self):
return unixconnection(self.sockpath)
def shutdown(self):
os.kill(self.server.pid, signal.SIGTERM)
self.server.wait()
def writeblock(server, data):
server.stdin.write(struct.pack('>I', len(data)))
server.stdin.write(data)
server.stdin.flush()
def readchannel(server):
data = server.stdout.read(5)
if not data:
raise EOFError
channel, length = struct.unpack('>cI', data)
if channel in 'IL':
return channel, length
else:
return channel, server.stdout.read(length)
def sep(text):
return text.replace('\\', '/')
def runcommand(server, args, output=sys.stdout, error=sys.stderr, input=None,
outfilter=lambda x: x):
print '*** runcommand', ' '.join(args)
sys.stdout.flush()
server.stdin.write('runcommand\n')
writeblock(server, '\0'.join(args))
if not input:
input = cStringIO.StringIO()
while True:
ch, data = readchannel(server)
if ch == 'o':
output.write(outfilter(data))
output.flush()
elif ch == 'e':
error.write(data)
error.flush()
elif ch == 'I':
writeblock(server, input.read(data))
elif ch == 'L':
writeblock(server, input.readline(data))
elif ch == 'r':
ret, = struct.unpack('>i', data)
if ret != 0:
print ' [%d]' % ret
return ret
else:
print "unexpected channel %c: %r" % (ch, data)
if ch.isupper():
return
def check(func, connect=connectpipe):
sys.stdout.flush()
server = connect()
try:
return func(server)
finally:
server.stdin.close()
server.wait()