##// END OF EJS Templates
localrepo: move extension loading to a separate method...
localrepo: move extension loading to a separate method The stateful chg plan [1] requires a special repo object, where ideally all side effects caused by loading the repo object could be reverted by just dropping (gabbage collect) the loaded repo object. Currently, that is impossible because repo.__init__ calls "extensions.loadall", which may have unpredictable side-effects that cannot be reverted by dropping the repo object. This patch moves "extensions.loadall" to a separate method, so chg could subclass localrepository and make extensions loading a no-op. [1]: mercurial-scm.org/pipermail/mercurial-devel/2017-February/092547.html

File last commit:

r28836:3f45488d default
r30989:74af89c6 default
Show More
hgclient.py
123 lines | 3.3 KiB | text/x-python | PythonLexer
# A minimal client for Mercurial's command server
from __future__ import absolute_import, print_function
import os
import signal
import socket
import struct
import subprocess
import sys
import time
try:
import cStringIO as io
stringio = io.StringIO
except ImportError:
import io
stringio = io.StringIO
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 = 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()