contrib/hgclient.py
branchstable
changeset 40404 956ec6f1320d
parent 40317 6958eb9bdcd6
child 40589 054d0fcba2c4
equal deleted inserted replaced
40131:535fc8a22365 40404:956ec6f1320d
     1 # A minimal client for Mercurial's command server
     1 # A minimal client for Mercurial's command server
     2 
     2 
     3 from __future__ import absolute_import, print_function
     3 from __future__ import absolute_import, print_function
       
     4 
       
     5 import io
     4 import os
     6 import os
       
     7 import re
     5 import signal
     8 import signal
     6 import socket
     9 import socket
     7 import struct
    10 import struct
     8 import subprocess
    11 import subprocess
     9 import sys
    12 import sys
    10 import time
    13 import time
    11 
    14 
    12 try:
    15 if sys.version_info[0] >= 3:
    13     import cStringIO as io
    16     stdout = sys.stdout.buffer
    14     stringio = io.StringIO
    17     stderr = sys.stderr.buffer
    15 except ImportError:
    18     stringio = io.BytesIO
    16     import io
    19     def bprint(*args):
    17     stringio = io.StringIO
    20         # remove b'' as well for ease of test migration
       
    21         pargs = [re.sub(br'''\bb(['"])''', br'\1', b'%s' % a) for a in args]
       
    22         stdout.write(b' '.join(pargs) + b'\n')
       
    23 else:
       
    24     import cStringIO
       
    25     stdout = sys.stdout
       
    26     stderr = sys.stderr
       
    27     stringio = cStringIO.StringIO
       
    28     bprint = print
    18 
    29 
    19 def connectpipe(path=None):
    30 def connectpipe(path=None):
    20     cmdline = ['hg', 'serve', '--cmdserver', 'pipe']
    31     cmdline = [b'hg', b'serve', b'--cmdserver', b'pipe']
    21     if path:
    32     if path:
    22         cmdline += ['-R', path]
    33         cmdline += [b'-R', path]
    23 
    34 
    24     server = subprocess.Popen(cmdline, stdin=subprocess.PIPE,
    35     server = subprocess.Popen(cmdline, stdin=subprocess.PIPE,
    25                               stdout=subprocess.PIPE)
    36                               stdout=subprocess.PIPE)
    26 
    37 
    27     return server
    38     return server
    39         self.sock.close()
    50         self.sock.close()
    40 
    51 
    41 class unixserver(object):
    52 class unixserver(object):
    42     def __init__(self, sockpath, logpath=None, repopath=None):
    53     def __init__(self, sockpath, logpath=None, repopath=None):
    43         self.sockpath = sockpath
    54         self.sockpath = sockpath
    44         cmdline = ['hg', 'serve', '--cmdserver', 'unix', '-a', sockpath]
    55         cmdline = [b'hg', b'serve', b'--cmdserver', b'unix', b'-a', sockpath]
    45         if repopath:
    56         if repopath:
    46             cmdline += ['-R', repopath]
    57             cmdline += [b'-R', repopath]
    47         if logpath:
    58         if logpath:
    48             stdout = open(logpath, 'a')
    59             stdout = open(logpath, 'a')
    49             stderr = subprocess.STDOUT
    60             stderr = subprocess.STDOUT
    50         else:
    61         else:
    51             stdout = stderr = None
    62             stdout = stderr = None
    62     def shutdown(self):
    73     def shutdown(self):
    63         os.kill(self.server.pid, signal.SIGTERM)
    74         os.kill(self.server.pid, signal.SIGTERM)
    64         self.server.wait()
    75         self.server.wait()
    65 
    76 
    66 def writeblock(server, data):
    77 def writeblock(server, data):
    67     server.stdin.write(struct.pack('>I', len(data)))
    78     server.stdin.write(struct.pack(b'>I', len(data)))
    68     server.stdin.write(data)
    79     server.stdin.write(data)
    69     server.stdin.flush()
    80     server.stdin.flush()
    70 
    81 
    71 def readchannel(server):
    82 def readchannel(server):
    72     data = server.stdout.read(5)
    83     data = server.stdout.read(5)
    73     if not data:
    84     if not data:
    74         raise EOFError
    85         raise EOFError
    75     channel, length = struct.unpack('>cI', data)
    86     channel, length = struct.unpack('>cI', data)
    76     if channel in 'IL':
    87     if channel in b'IL':
    77         return channel, length
    88         return channel, length
    78     else:
    89     else:
    79         return channel, server.stdout.read(length)
    90         return channel, server.stdout.read(length)
    80 
    91 
    81 def sep(text):
    92 def sep(text):
    82     return text.replace('\\', '/')
    93     return text.replace(b'\\', b'/')
    83 
    94 
    84 def runcommand(server, args, output=sys.stdout, error=sys.stderr, input=None,
    95 def runcommand(server, args, output=stdout, error=stderr, input=None,
    85                outfilter=lambda x: x):
    96                outfilter=lambda x: x):
    86     print('*** runcommand', ' '.join(args))
    97     bprint(b'*** runcommand', b' '.join(args))
    87     sys.stdout.flush()
    98     stdout.flush()
    88     server.stdin.write('runcommand\n')
    99     server.stdin.write(b'runcommand\n')
    89     writeblock(server, '\0'.join(args))
   100     writeblock(server, b'\0'.join(args))
    90 
   101 
    91     if not input:
   102     if not input:
    92         input = stringio()
   103         input = stringio()
    93 
   104 
    94     while True:
   105     while True:
    95         ch, data = readchannel(server)
   106         ch, data = readchannel(server)
    96         if ch == 'o':
   107         if ch == b'o':
    97             output.write(outfilter(data))
   108             output.write(outfilter(data))
    98             output.flush()
   109             output.flush()
    99         elif ch == 'e':
   110         elif ch == b'e':
   100             error.write(data)
   111             error.write(data)
   101             error.flush()
   112             error.flush()
   102         elif ch == 'I':
   113         elif ch == b'I':
   103             writeblock(server, input.read(data))
   114             writeblock(server, input.read(data))
   104         elif ch == 'L':
   115         elif ch == b'L':
   105             writeblock(server, input.readline(data))
   116             writeblock(server, input.readline(data))
   106         elif ch == 'r':
   117         elif ch == b'r':
   107             ret, = struct.unpack('>i', data)
   118             ret, = struct.unpack('>i', data)
   108             if ret != 0:
   119             if ret != 0:
   109                 print(' [%d]' % ret)
   120                 bprint(b' [%d]' % ret)
   110             return ret
   121             return ret
   111         else:
   122         else:
   112             print("unexpected channel %c: %r" % (ch, data))
   123             bprint(b"unexpected channel %c: %r" % (ch, data))
   113             if ch.isupper():
   124             if ch.isupper():
   114                 return
   125                 return
   115 
   126 
   116 def check(func, connect=connectpipe):
   127 def check(func, connect=connectpipe):
   117     sys.stdout.flush()
   128     stdout.flush()
   118     server = connect()
   129     server = connect()
   119     try:
   130     try:
   120         return func(server)
   131         return func(server)
   121     finally:
   132     finally:
   122         server.stdin.close()
   133         server.stdin.close()