##// END OF EJS Templates
cmdserver: use given streams as pipe channels like other commands...
Yuya Nishihara -
r23322:000cfc8b default
parent child Browse files
Show More
@@ -1,321 +1,321 b''
1 # commandserver.py - communicate with Mercurial's API over a pipe
1 # commandserver.py - communicate with Mercurial's API over a pipe
2 #
2 #
3 # Copyright Matt Mackall <mpm@selenic.com>
3 # Copyright Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 from i18n import _
8 from i18n import _
9 import struct
9 import struct
10 import sys, os, errno, traceback, SocketServer
10 import os, errno, traceback, SocketServer
11 import dispatch, encoding, util
11 import dispatch, encoding, util
12
12
13 logfile = None
13 logfile = None
14
14
15 def log(*args):
15 def log(*args):
16 if not logfile:
16 if not logfile:
17 return
17 return
18
18
19 for a in args:
19 for a in args:
20 logfile.write(str(a))
20 logfile.write(str(a))
21
21
22 logfile.flush()
22 logfile.flush()
23
23
24 class channeledoutput(object):
24 class channeledoutput(object):
25 """
25 """
26 Write data to out in the following format:
26 Write data to out in the following format:
27
27
28 data length (unsigned int),
28 data length (unsigned int),
29 data
29 data
30 """
30 """
31 def __init__(self, out, channel):
31 def __init__(self, out, channel):
32 self.out = out
32 self.out = out
33 self.channel = channel
33 self.channel = channel
34
34
35 def write(self, data):
35 def write(self, data):
36 if not data:
36 if not data:
37 return
37 return
38 self.out.write(struct.pack('>cI', self.channel, len(data)))
38 self.out.write(struct.pack('>cI', self.channel, len(data)))
39 self.out.write(data)
39 self.out.write(data)
40 self.out.flush()
40 self.out.flush()
41
41
42 def __getattr__(self, attr):
42 def __getattr__(self, attr):
43 if attr in ('isatty', 'fileno'):
43 if attr in ('isatty', 'fileno'):
44 raise AttributeError(attr)
44 raise AttributeError(attr)
45 return getattr(self.out, attr)
45 return getattr(self.out, attr)
46
46
47 class channeledinput(object):
47 class channeledinput(object):
48 """
48 """
49 Read data from in_.
49 Read data from in_.
50
50
51 Requests for input are written to out in the following format:
51 Requests for input are written to out in the following format:
52 channel identifier - 'I' for plain input, 'L' line based (1 byte)
52 channel identifier - 'I' for plain input, 'L' line based (1 byte)
53 how many bytes to send at most (unsigned int),
53 how many bytes to send at most (unsigned int),
54
54
55 The client replies with:
55 The client replies with:
56 data length (unsigned int), 0 meaning EOF
56 data length (unsigned int), 0 meaning EOF
57 data
57 data
58 """
58 """
59
59
60 maxchunksize = 4 * 1024
60 maxchunksize = 4 * 1024
61
61
62 def __init__(self, in_, out, channel):
62 def __init__(self, in_, out, channel):
63 self.in_ = in_
63 self.in_ = in_
64 self.out = out
64 self.out = out
65 self.channel = channel
65 self.channel = channel
66
66
67 def read(self, size=-1):
67 def read(self, size=-1):
68 if size < 0:
68 if size < 0:
69 # if we need to consume all the clients input, ask for 4k chunks
69 # if we need to consume all the clients input, ask for 4k chunks
70 # so the pipe doesn't fill up risking a deadlock
70 # so the pipe doesn't fill up risking a deadlock
71 size = self.maxchunksize
71 size = self.maxchunksize
72 s = self._read(size, self.channel)
72 s = self._read(size, self.channel)
73 buf = s
73 buf = s
74 while s:
74 while s:
75 s = self._read(size, self.channel)
75 s = self._read(size, self.channel)
76 buf += s
76 buf += s
77
77
78 return buf
78 return buf
79 else:
79 else:
80 return self._read(size, self.channel)
80 return self._read(size, self.channel)
81
81
82 def _read(self, size, channel):
82 def _read(self, size, channel):
83 if not size:
83 if not size:
84 return ''
84 return ''
85 assert size > 0
85 assert size > 0
86
86
87 # tell the client we need at most size bytes
87 # tell the client we need at most size bytes
88 self.out.write(struct.pack('>cI', channel, size))
88 self.out.write(struct.pack('>cI', channel, size))
89 self.out.flush()
89 self.out.flush()
90
90
91 length = self.in_.read(4)
91 length = self.in_.read(4)
92 length = struct.unpack('>I', length)[0]
92 length = struct.unpack('>I', length)[0]
93 if not length:
93 if not length:
94 return ''
94 return ''
95 else:
95 else:
96 return self.in_.read(length)
96 return self.in_.read(length)
97
97
98 def readline(self, size=-1):
98 def readline(self, size=-1):
99 if size < 0:
99 if size < 0:
100 size = self.maxchunksize
100 size = self.maxchunksize
101 s = self._read(size, 'L')
101 s = self._read(size, 'L')
102 buf = s
102 buf = s
103 # keep asking for more until there's either no more or
103 # keep asking for more until there's either no more or
104 # we got a full line
104 # we got a full line
105 while s and s[-1] != '\n':
105 while s and s[-1] != '\n':
106 s = self._read(size, 'L')
106 s = self._read(size, 'L')
107 buf += s
107 buf += s
108
108
109 return buf
109 return buf
110 else:
110 else:
111 return self._read(size, 'L')
111 return self._read(size, 'L')
112
112
113 def __iter__(self):
113 def __iter__(self):
114 return self
114 return self
115
115
116 def next(self):
116 def next(self):
117 l = self.readline()
117 l = self.readline()
118 if not l:
118 if not l:
119 raise StopIteration
119 raise StopIteration
120 return l
120 return l
121
121
122 def __getattr__(self, attr):
122 def __getattr__(self, attr):
123 if attr in ('isatty', 'fileno'):
123 if attr in ('isatty', 'fileno'):
124 raise AttributeError(attr)
124 raise AttributeError(attr)
125 return getattr(self.in_, attr)
125 return getattr(self.in_, attr)
126
126
127 class server(object):
127 class server(object):
128 """
128 """
129 Listens for commands on fin, runs them and writes the output on a channel
129 Listens for commands on fin, runs them and writes the output on a channel
130 based stream to fout.
130 based stream to fout.
131 """
131 """
132 def __init__(self, ui, repo, fin, fout):
132 def __init__(self, ui, repo, fin, fout):
133 self.cwd = os.getcwd()
133 self.cwd = os.getcwd()
134
134
135 logpath = ui.config("cmdserver", "log", None)
135 logpath = ui.config("cmdserver", "log", None)
136 if logpath:
136 if logpath:
137 global logfile
137 global logfile
138 if logpath == '-':
138 if logpath == '-':
139 # write log on a special 'd' (debug) channel
139 # write log on a special 'd' (debug) channel
140 logfile = channeledoutput(fout, 'd')
140 logfile = channeledoutput(fout, 'd')
141 else:
141 else:
142 logfile = open(logpath, 'a')
142 logfile = open(logpath, 'a')
143
143
144 if repo:
144 if repo:
145 # the ui here is really the repo ui so take its baseui so we don't
145 # the ui here is really the repo ui so take its baseui so we don't
146 # end up with its local configuration
146 # end up with its local configuration
147 self.ui = repo.baseui
147 self.ui = repo.baseui
148 self.repo = repo
148 self.repo = repo
149 self.repoui = repo.ui
149 self.repoui = repo.ui
150 else:
150 else:
151 self.ui = ui
151 self.ui = ui
152 self.repo = self.repoui = None
152 self.repo = self.repoui = None
153
153
154 self.cerr = channeledoutput(fout, 'e')
154 self.cerr = channeledoutput(fout, 'e')
155 self.cout = channeledoutput(fout, 'o')
155 self.cout = channeledoutput(fout, 'o')
156 self.cin = channeledinput(fin, fout, 'I')
156 self.cin = channeledinput(fin, fout, 'I')
157 self.cresult = channeledoutput(fout, 'r')
157 self.cresult = channeledoutput(fout, 'r')
158
158
159 self.client = fin
159 self.client = fin
160
160
161 def _read(self, size):
161 def _read(self, size):
162 if not size:
162 if not size:
163 return ''
163 return ''
164
164
165 data = self.client.read(size)
165 data = self.client.read(size)
166
166
167 # is the other end closed?
167 # is the other end closed?
168 if not data:
168 if not data:
169 raise EOFError
169 raise EOFError
170
170
171 return data
171 return data
172
172
173 def runcommand(self):
173 def runcommand(self):
174 """ reads a list of \0 terminated arguments, executes
174 """ reads a list of \0 terminated arguments, executes
175 and writes the return code to the result channel """
175 and writes the return code to the result channel """
176
176
177 length = struct.unpack('>I', self._read(4))[0]
177 length = struct.unpack('>I', self._read(4))[0]
178 if not length:
178 if not length:
179 args = []
179 args = []
180 else:
180 else:
181 args = self._read(length).split('\0')
181 args = self._read(length).split('\0')
182
182
183 # copy the uis so changes (e.g. --config or --verbose) don't
183 # copy the uis so changes (e.g. --config or --verbose) don't
184 # persist between requests
184 # persist between requests
185 copiedui = self.ui.copy()
185 copiedui = self.ui.copy()
186 uis = [copiedui]
186 uis = [copiedui]
187 if self.repo:
187 if self.repo:
188 self.repo.baseui = copiedui
188 self.repo.baseui = copiedui
189 # clone ui without using ui.copy because this is protected
189 # clone ui without using ui.copy because this is protected
190 repoui = self.repoui.__class__(self.repoui)
190 repoui = self.repoui.__class__(self.repoui)
191 repoui.copy = copiedui.copy # redo copy protection
191 repoui.copy = copiedui.copy # redo copy protection
192 uis.append(repoui)
192 uis.append(repoui)
193 self.repo.ui = self.repo.dirstate._ui = repoui
193 self.repo.ui = self.repo.dirstate._ui = repoui
194 self.repo.invalidateall()
194 self.repo.invalidateall()
195
195
196 for ui in uis:
196 for ui in uis:
197 # any kind of interaction must use server channels
197 # any kind of interaction must use server channels
198 ui.setconfig('ui', 'nontty', 'true', 'commandserver')
198 ui.setconfig('ui', 'nontty', 'true', 'commandserver')
199
199
200 req = dispatch.request(args[:], copiedui, self.repo, self.cin,
200 req = dispatch.request(args[:], copiedui, self.repo, self.cin,
201 self.cout, self.cerr)
201 self.cout, self.cerr)
202
202
203 ret = (dispatch.dispatch(req) or 0) & 255 # might return None
203 ret = (dispatch.dispatch(req) or 0) & 255 # might return None
204
204
205 # restore old cwd
205 # restore old cwd
206 if '--cwd' in args:
206 if '--cwd' in args:
207 os.chdir(self.cwd)
207 os.chdir(self.cwd)
208
208
209 self.cresult.write(struct.pack('>i', int(ret)))
209 self.cresult.write(struct.pack('>i', int(ret)))
210
210
211 def getencoding(self):
211 def getencoding(self):
212 """ writes the current encoding to the result channel """
212 """ writes the current encoding to the result channel """
213 self.cresult.write(encoding.encoding)
213 self.cresult.write(encoding.encoding)
214
214
215 def serveone(self):
215 def serveone(self):
216 cmd = self.client.readline()[:-1]
216 cmd = self.client.readline()[:-1]
217 if cmd:
217 if cmd:
218 handler = self.capabilities.get(cmd)
218 handler = self.capabilities.get(cmd)
219 if handler:
219 if handler:
220 handler(self)
220 handler(self)
221 else:
221 else:
222 # clients are expected to check what commands are supported by
222 # clients are expected to check what commands are supported by
223 # looking at the servers capabilities
223 # looking at the servers capabilities
224 raise util.Abort(_('unknown command %s') % cmd)
224 raise util.Abort(_('unknown command %s') % cmd)
225
225
226 return cmd != ''
226 return cmd != ''
227
227
228 capabilities = {'runcommand' : runcommand,
228 capabilities = {'runcommand' : runcommand,
229 'getencoding' : getencoding}
229 'getencoding' : getencoding}
230
230
231 def serve(self):
231 def serve(self):
232 hellomsg = 'capabilities: ' + ' '.join(sorted(self.capabilities))
232 hellomsg = 'capabilities: ' + ' '.join(sorted(self.capabilities))
233 hellomsg += '\n'
233 hellomsg += '\n'
234 hellomsg += 'encoding: ' + encoding.encoding
234 hellomsg += 'encoding: ' + encoding.encoding
235 hellomsg += '\n'
235 hellomsg += '\n'
236 hellomsg += 'pid: %d' % os.getpid()
236 hellomsg += 'pid: %d' % os.getpid()
237
237
238 # write the hello msg in -one- chunk
238 # write the hello msg in -one- chunk
239 self.cout.write(hellomsg)
239 self.cout.write(hellomsg)
240
240
241 try:
241 try:
242 while self.serveone():
242 while self.serveone():
243 pass
243 pass
244 except EOFError:
244 except EOFError:
245 # we'll get here if the client disconnected while we were reading
245 # we'll get here if the client disconnected while we were reading
246 # its request
246 # its request
247 return 1
247 return 1
248
248
249 return 0
249 return 0
250
250
251 class pipeservice(object):
251 class pipeservice(object):
252 def __init__(self, ui, repo, opts):
252 def __init__(self, ui, repo, opts):
253 self.server = server(ui, repo, sys.stdin, sys.stdout)
253 self.server = server(ui, repo, ui.fin, ui.fout)
254
254
255 def init(self):
255 def init(self):
256 pass
256 pass
257
257
258 def run(self):
258 def run(self):
259 return self.server.serve()
259 return self.server.serve()
260
260
261 class _requesthandler(SocketServer.StreamRequestHandler):
261 class _requesthandler(SocketServer.StreamRequestHandler):
262 def handle(self):
262 def handle(self):
263 ui = self.server.ui
263 ui = self.server.ui
264 repo = self.server.repo
264 repo = self.server.repo
265 sv = server(ui, repo, self.rfile, self.wfile)
265 sv = server(ui, repo, self.rfile, self.wfile)
266 try:
266 try:
267 try:
267 try:
268 sv.serve()
268 sv.serve()
269 # handle exceptions that may be raised by command server. most of
269 # handle exceptions that may be raised by command server. most of
270 # known exceptions are caught by dispatch.
270 # known exceptions are caught by dispatch.
271 except util.Abort, inst:
271 except util.Abort, inst:
272 ui.warn(_('abort: %s\n') % inst)
272 ui.warn(_('abort: %s\n') % inst)
273 except IOError, inst:
273 except IOError, inst:
274 if inst.errno != errno.EPIPE:
274 if inst.errno != errno.EPIPE:
275 raise
275 raise
276 except KeyboardInterrupt:
276 except KeyboardInterrupt:
277 pass
277 pass
278 except: # re-raises
278 except: # re-raises
279 # also write traceback to error channel. otherwise client cannot
279 # also write traceback to error channel. otherwise client cannot
280 # see it because it is written to server's stderr by default.
280 # see it because it is written to server's stderr by default.
281 traceback.print_exc(file=sv.cerr)
281 traceback.print_exc(file=sv.cerr)
282 raise
282 raise
283
283
284 class unixservice(object):
284 class unixservice(object):
285 """
285 """
286 Listens on unix domain socket and forks server per connection
286 Listens on unix domain socket and forks server per connection
287 """
287 """
288 def __init__(self, ui, repo, opts):
288 def __init__(self, ui, repo, opts):
289 self.ui = ui
289 self.ui = ui
290 self.repo = repo
290 self.repo = repo
291 self.address = opts['address']
291 self.address = opts['address']
292 if not util.safehasattr(SocketServer, 'UnixStreamServer'):
292 if not util.safehasattr(SocketServer, 'UnixStreamServer'):
293 raise util.Abort(_('unsupported platform'))
293 raise util.Abort(_('unsupported platform'))
294 if not self.address:
294 if not self.address:
295 raise util.Abort(_('no socket path specified with --address'))
295 raise util.Abort(_('no socket path specified with --address'))
296
296
297 def init(self):
297 def init(self):
298 class cls(SocketServer.ForkingMixIn, SocketServer.UnixStreamServer):
298 class cls(SocketServer.ForkingMixIn, SocketServer.UnixStreamServer):
299 ui = self.ui
299 ui = self.ui
300 repo = self.repo
300 repo = self.repo
301 self.server = cls(self.address, _requesthandler)
301 self.server = cls(self.address, _requesthandler)
302 self.ui.status(_('listening at %s\n') % self.address)
302 self.ui.status(_('listening at %s\n') % self.address)
303 self.ui.flush() # avoid buffering of status message
303 self.ui.flush() # avoid buffering of status message
304
304
305 def run(self):
305 def run(self):
306 try:
306 try:
307 self.server.serve_forever()
307 self.server.serve_forever()
308 finally:
308 finally:
309 os.unlink(self.address)
309 os.unlink(self.address)
310
310
311 _servicemap = {
311 _servicemap = {
312 'pipe': pipeservice,
312 'pipe': pipeservice,
313 'unix': unixservice,
313 'unix': unixservice,
314 }
314 }
315
315
316 def createservice(ui, repo, opts):
316 def createservice(ui, repo, opts):
317 mode = opts['cmdserver']
317 mode = opts['cmdserver']
318 try:
318 try:
319 return _servicemap[mode](ui, repo, opts)
319 return _servicemap[mode](ui, repo, opts)
320 except KeyError:
320 except KeyError:
321 raise util.Abort(_('unknown mode %s') % mode)
321 raise util.Abort(_('unknown mode %s') % mode)
@@ -1,612 +1,633 b''
1 #if windows
1 #if windows
2 $ PYTHONPATH="$TESTDIR/../contrib;$PYTHONPATH"
2 $ PYTHONPATH="$TESTDIR/../contrib;$PYTHONPATH"
3 #else
3 #else
4 $ PYTHONPATH="$TESTDIR/../contrib:$PYTHONPATH"
4 $ PYTHONPATH="$TESTDIR/../contrib:$PYTHONPATH"
5 #endif
5 #endif
6 $ export PYTHONPATH
6 $ export PYTHONPATH
7
7
8 typical client does not want echo-back messages, so test without it:
8 typical client does not want echo-back messages, so test without it:
9
9
10 $ grep -v '^promptecho ' < $HGRCPATH >> $HGRCPATH.new
10 $ grep -v '^promptecho ' < $HGRCPATH >> $HGRCPATH.new
11 $ mv $HGRCPATH.new $HGRCPATH
11 $ mv $HGRCPATH.new $HGRCPATH
12
12
13 $ hg init repo
13 $ hg init repo
14 $ cd repo
14 $ cd repo
15
15
16 >>> from hgclient import readchannel, runcommand, check
16 >>> from hgclient import readchannel, runcommand, check
17 >>> @check
17 >>> @check
18 ... def hellomessage(server):
18 ... def hellomessage(server):
19 ... ch, data = readchannel(server)
19 ... ch, data = readchannel(server)
20 ... print '%c, %r' % (ch, data)
20 ... print '%c, %r' % (ch, data)
21 ... # run an arbitrary command to make sure the next thing the server
21 ... # run an arbitrary command to make sure the next thing the server
22 ... # sends isn't part of the hello message
22 ... # sends isn't part of the hello message
23 ... runcommand(server, ['id'])
23 ... runcommand(server, ['id'])
24 o, 'capabilities: getencoding runcommand\nencoding: *\npid: *' (glob)
24 o, 'capabilities: getencoding runcommand\nencoding: *\npid: *' (glob)
25 *** runcommand id
25 *** runcommand id
26 000000000000 tip
26 000000000000 tip
27
27
28 >>> from hgclient import check
28 >>> from hgclient import check
29 >>> @check
29 >>> @check
30 ... def unknowncommand(server):
30 ... def unknowncommand(server):
31 ... server.stdin.write('unknowncommand\n')
31 ... server.stdin.write('unknowncommand\n')
32 abort: unknown command unknowncommand
32 abort: unknown command unknowncommand
33
33
34 >>> from hgclient import readchannel, runcommand, check
34 >>> from hgclient import readchannel, runcommand, check
35 >>> @check
35 >>> @check
36 ... def checkruncommand(server):
36 ... def checkruncommand(server):
37 ... # hello block
37 ... # hello block
38 ... readchannel(server)
38 ... readchannel(server)
39 ...
39 ...
40 ... # no args
40 ... # no args
41 ... runcommand(server, [])
41 ... runcommand(server, [])
42 ...
42 ...
43 ... # global options
43 ... # global options
44 ... runcommand(server, ['id', '--quiet'])
44 ... runcommand(server, ['id', '--quiet'])
45 ...
45 ...
46 ... # make sure global options don't stick through requests
46 ... # make sure global options don't stick through requests
47 ... runcommand(server, ['id'])
47 ... runcommand(server, ['id'])
48 ...
48 ...
49 ... # --config
49 ... # --config
50 ... runcommand(server, ['id', '--config', 'ui.quiet=True'])
50 ... runcommand(server, ['id', '--config', 'ui.quiet=True'])
51 ...
51 ...
52 ... # make sure --config doesn't stick
52 ... # make sure --config doesn't stick
53 ... runcommand(server, ['id'])
53 ... runcommand(server, ['id'])
54 ...
54 ...
55 ... # negative return code should be masked
55 ... # negative return code should be masked
56 ... runcommand(server, ['id', '-runknown'])
56 ... runcommand(server, ['id', '-runknown'])
57 *** runcommand
57 *** runcommand
58 Mercurial Distributed SCM
58 Mercurial Distributed SCM
59
59
60 basic commands:
60 basic commands:
61
61
62 add add the specified files on the next commit
62 add add the specified files on the next commit
63 annotate show changeset information by line for each file
63 annotate show changeset information by line for each file
64 clone make a copy of an existing repository
64 clone make a copy of an existing repository
65 commit commit the specified files or all outstanding changes
65 commit commit the specified files or all outstanding changes
66 diff diff repository (or selected files)
66 diff diff repository (or selected files)
67 export dump the header and diffs for one or more changesets
67 export dump the header and diffs for one or more changesets
68 forget forget the specified files on the next commit
68 forget forget the specified files on the next commit
69 init create a new repository in the given directory
69 init create a new repository in the given directory
70 log show revision history of entire repository or files
70 log show revision history of entire repository or files
71 merge merge working directory with another revision
71 merge merge working directory with another revision
72 pull pull changes from the specified source
72 pull pull changes from the specified source
73 push push changes to the specified destination
73 push push changes to the specified destination
74 remove remove the specified files on the next commit
74 remove remove the specified files on the next commit
75 serve start stand-alone webserver
75 serve start stand-alone webserver
76 status show changed files in the working directory
76 status show changed files in the working directory
77 summary summarize working directory state
77 summary summarize working directory state
78 update update working directory (or switch revisions)
78 update update working directory (or switch revisions)
79
79
80 (use "hg help" for the full list of commands or "hg -v" for details)
80 (use "hg help" for the full list of commands or "hg -v" for details)
81 *** runcommand id --quiet
81 *** runcommand id --quiet
82 000000000000
82 000000000000
83 *** runcommand id
83 *** runcommand id
84 000000000000 tip
84 000000000000 tip
85 *** runcommand id --config ui.quiet=True
85 *** runcommand id --config ui.quiet=True
86 000000000000
86 000000000000
87 *** runcommand id
87 *** runcommand id
88 000000000000 tip
88 000000000000 tip
89 *** runcommand id -runknown
89 *** runcommand id -runknown
90 abort: unknown revision 'unknown'!
90 abort: unknown revision 'unknown'!
91 [255]
91 [255]
92
92
93 >>> from hgclient import readchannel, check
93 >>> from hgclient import readchannel, check
94 >>> @check
94 >>> @check
95 ... def inputeof(server):
95 ... def inputeof(server):
96 ... readchannel(server)
96 ... readchannel(server)
97 ... server.stdin.write('runcommand\n')
97 ... server.stdin.write('runcommand\n')
98 ... # close stdin while server is waiting for input
98 ... # close stdin while server is waiting for input
99 ... server.stdin.close()
99 ... server.stdin.close()
100 ...
100 ...
101 ... # server exits with 1 if the pipe closed while reading the command
101 ... # server exits with 1 if the pipe closed while reading the command
102 ... print 'server exit code =', server.wait()
102 ... print 'server exit code =', server.wait()
103 server exit code = 1
103 server exit code = 1
104
104
105 >>> import cStringIO
105 >>> import cStringIO
106 >>> from hgclient import readchannel, runcommand, check
106 >>> from hgclient import readchannel, runcommand, check
107 >>> @check
107 >>> @check
108 ... def serverinput(server):
108 ... def serverinput(server):
109 ... readchannel(server)
109 ... readchannel(server)
110 ...
110 ...
111 ... patch = """
111 ... patch = """
112 ... # HG changeset patch
112 ... # HG changeset patch
113 ... # User test
113 ... # User test
114 ... # Date 0 0
114 ... # Date 0 0
115 ... # Node ID c103a3dec114d882c98382d684d8af798d09d857
115 ... # Node ID c103a3dec114d882c98382d684d8af798d09d857
116 ... # Parent 0000000000000000000000000000000000000000
116 ... # Parent 0000000000000000000000000000000000000000
117 ... 1
117 ... 1
118 ...
118 ...
119 ... diff -r 000000000000 -r c103a3dec114 a
119 ... diff -r 000000000000 -r c103a3dec114 a
120 ... --- /dev/null Thu Jan 01 00:00:00 1970 +0000
120 ... --- /dev/null Thu Jan 01 00:00:00 1970 +0000
121 ... +++ b/a Thu Jan 01 00:00:00 1970 +0000
121 ... +++ b/a Thu Jan 01 00:00:00 1970 +0000
122 ... @@ -0,0 +1,1 @@
122 ... @@ -0,0 +1,1 @@
123 ... +1
123 ... +1
124 ... """
124 ... """
125 ...
125 ...
126 ... runcommand(server, ['import', '-'], input=cStringIO.StringIO(patch))
126 ... runcommand(server, ['import', '-'], input=cStringIO.StringIO(patch))
127 ... runcommand(server, ['log'])
127 ... runcommand(server, ['log'])
128 *** runcommand import -
128 *** runcommand import -
129 applying patch from stdin
129 applying patch from stdin
130 *** runcommand log
130 *** runcommand log
131 changeset: 0:eff892de26ec
131 changeset: 0:eff892de26ec
132 tag: tip
132 tag: tip
133 user: test
133 user: test
134 date: Thu Jan 01 00:00:00 1970 +0000
134 date: Thu Jan 01 00:00:00 1970 +0000
135 summary: 1
135 summary: 1
136
136
137
137
138 check that --cwd doesn't persist between requests:
138 check that --cwd doesn't persist between requests:
139
139
140 $ mkdir foo
140 $ mkdir foo
141 $ touch foo/bar
141 $ touch foo/bar
142 >>> from hgclient import readchannel, runcommand, check
142 >>> from hgclient import readchannel, runcommand, check
143 >>> @check
143 >>> @check
144 ... def cwd(server):
144 ... def cwd(server):
145 ... readchannel(server)
145 ... readchannel(server)
146 ... runcommand(server, ['--cwd', 'foo', 'st', 'bar'])
146 ... runcommand(server, ['--cwd', 'foo', 'st', 'bar'])
147 ... runcommand(server, ['st', 'foo/bar'])
147 ... runcommand(server, ['st', 'foo/bar'])
148 *** runcommand --cwd foo st bar
148 *** runcommand --cwd foo st bar
149 ? bar
149 ? bar
150 *** runcommand st foo/bar
150 *** runcommand st foo/bar
151 ? foo/bar
151 ? foo/bar
152
152
153 $ rm foo/bar
153 $ rm foo/bar
154
154
155
155
156 check that local configs for the cached repo aren't inherited when -R is used:
156 check that local configs for the cached repo aren't inherited when -R is used:
157
157
158 $ cat <<EOF >> .hg/hgrc
158 $ cat <<EOF >> .hg/hgrc
159 > [ui]
159 > [ui]
160 > foo = bar
160 > foo = bar
161 > EOF
161 > EOF
162
162
163 >>> from hgclient import readchannel, sep, runcommand, check
163 >>> from hgclient import readchannel, sep, runcommand, check
164 >>> @check
164 >>> @check
165 ... def localhgrc(server):
165 ... def localhgrc(server):
166 ... readchannel(server)
166 ... readchannel(server)
167 ...
167 ...
168 ... # the cached repo local hgrc contains ui.foo=bar, so showconfig should
168 ... # the cached repo local hgrc contains ui.foo=bar, so showconfig should
169 ... # show it
169 ... # show it
170 ... runcommand(server, ['showconfig'], outfilter=sep)
170 ... runcommand(server, ['showconfig'], outfilter=sep)
171 ...
171 ...
172 ... # but not for this repo
172 ... # but not for this repo
173 ... runcommand(server, ['init', 'foo'])
173 ... runcommand(server, ['init', 'foo'])
174 ... runcommand(server, ['-R', 'foo', 'showconfig', 'ui', 'defaults'])
174 ... runcommand(server, ['-R', 'foo', 'showconfig', 'ui', 'defaults'])
175 *** runcommand showconfig
175 *** runcommand showconfig
176 bundle.mainreporoot=$TESTTMP/repo
176 bundle.mainreporoot=$TESTTMP/repo
177 defaults.backout=-d "0 0"
177 defaults.backout=-d "0 0"
178 defaults.commit=-d "0 0"
178 defaults.commit=-d "0 0"
179 defaults.shelve=--date "0 0"
179 defaults.shelve=--date "0 0"
180 defaults.tag=-d "0 0"
180 defaults.tag=-d "0 0"
181 ui.slash=True
181 ui.slash=True
182 ui.interactive=False
182 ui.interactive=False
183 ui.mergemarkers=detailed
183 ui.mergemarkers=detailed
184 ui.foo=bar
184 ui.foo=bar
185 ui.nontty=true
185 ui.nontty=true
186 *** runcommand init foo
186 *** runcommand init foo
187 *** runcommand -R foo showconfig ui defaults
187 *** runcommand -R foo showconfig ui defaults
188 defaults.backout=-d "0 0"
188 defaults.backout=-d "0 0"
189 defaults.commit=-d "0 0"
189 defaults.commit=-d "0 0"
190 defaults.shelve=--date "0 0"
190 defaults.shelve=--date "0 0"
191 defaults.tag=-d "0 0"
191 defaults.tag=-d "0 0"
192 ui.slash=True
192 ui.slash=True
193 ui.interactive=False
193 ui.interactive=False
194 ui.mergemarkers=detailed
194 ui.mergemarkers=detailed
195 ui.nontty=true
195 ui.nontty=true
196
196
197 $ rm -R foo
197 $ rm -R foo
198
198
199 #if windows
199 #if windows
200 $ PYTHONPATH="$TESTTMP/repo;$PYTHONPATH"
200 $ PYTHONPATH="$TESTTMP/repo;$PYTHONPATH"
201 #else
201 #else
202 $ PYTHONPATH="$TESTTMP/repo:$PYTHONPATH"
202 $ PYTHONPATH="$TESTTMP/repo:$PYTHONPATH"
203 #endif
203 #endif
204
204
205 $ cat <<EOF > hook.py
205 $ cat <<EOF > hook.py
206 > import sys
206 > import sys
207 > def hook(**args):
207 > def hook(**args):
208 > print 'hook talking'
208 > print 'hook talking'
209 > print 'now try to read something: %r' % sys.stdin.read()
209 > print 'now try to read something: %r' % sys.stdin.read()
210 > EOF
210 > EOF
211
211
212 >>> import cStringIO
212 >>> import cStringIO
213 >>> from hgclient import readchannel, runcommand, check
213 >>> from hgclient import readchannel, runcommand, check
214 >>> @check
214 >>> @check
215 ... def hookoutput(server):
215 ... def hookoutput(server):
216 ... readchannel(server)
216 ... readchannel(server)
217 ... runcommand(server, ['--config',
217 ... runcommand(server, ['--config',
218 ... 'hooks.pre-identify=python:hook.hook',
218 ... 'hooks.pre-identify=python:hook.hook',
219 ... 'id'],
219 ... 'id'],
220 ... input=cStringIO.StringIO('some input'))
220 ... input=cStringIO.StringIO('some input'))
221 *** runcommand --config hooks.pre-identify=python:hook.hook id
221 *** runcommand --config hooks.pre-identify=python:hook.hook id
222 hook talking
222 hook talking
223 now try to read something: 'some input'
223 now try to read something: 'some input'
224 eff892de26ec tip
224 eff892de26ec tip
225
225
226 $ rm hook.py*
226 $ rm hook.py*
227
227
228 $ echo a >> a
228 $ echo a >> a
229 >>> import os
229 >>> import os
230 >>> from hgclient import readchannel, runcommand, check
230 >>> from hgclient import readchannel, runcommand, check
231 >>> @check
231 >>> @check
232 ... def outsidechanges(server):
232 ... def outsidechanges(server):
233 ... readchannel(server)
233 ... readchannel(server)
234 ... runcommand(server, ['status'])
234 ... runcommand(server, ['status'])
235 ... os.system('hg ci -Am2')
235 ... os.system('hg ci -Am2')
236 ... runcommand(server, ['tip'])
236 ... runcommand(server, ['tip'])
237 ... runcommand(server, ['status'])
237 ... runcommand(server, ['status'])
238 *** runcommand status
238 *** runcommand status
239 M a
239 M a
240 *** runcommand tip
240 *** runcommand tip
241 changeset: 1:d3a0a68be6de
241 changeset: 1:d3a0a68be6de
242 tag: tip
242 tag: tip
243 user: test
243 user: test
244 date: Thu Jan 01 00:00:00 1970 +0000
244 date: Thu Jan 01 00:00:00 1970 +0000
245 summary: 2
245 summary: 2
246
246
247 *** runcommand status
247 *** runcommand status
248
248
249 >>> import os
249 >>> import os
250 >>> from hgclient import readchannel, runcommand, check
250 >>> from hgclient import readchannel, runcommand, check
251 >>> @check
251 >>> @check
252 ... def bookmarks(server):
252 ... def bookmarks(server):
253 ... readchannel(server)
253 ... readchannel(server)
254 ... runcommand(server, ['bookmarks'])
254 ... runcommand(server, ['bookmarks'])
255 ...
255 ...
256 ... # changes .hg/bookmarks
256 ... # changes .hg/bookmarks
257 ... os.system('hg bookmark -i bm1')
257 ... os.system('hg bookmark -i bm1')
258 ... os.system('hg bookmark -i bm2')
258 ... os.system('hg bookmark -i bm2')
259 ... runcommand(server, ['bookmarks'])
259 ... runcommand(server, ['bookmarks'])
260 ...
260 ...
261 ... # changes .hg/bookmarks.current
261 ... # changes .hg/bookmarks.current
262 ... os.system('hg upd bm1 -q')
262 ... os.system('hg upd bm1 -q')
263 ... runcommand(server, ['bookmarks'])
263 ... runcommand(server, ['bookmarks'])
264 ...
264 ...
265 ... runcommand(server, ['bookmarks', 'bm3'])
265 ... runcommand(server, ['bookmarks', 'bm3'])
266 ... f = open('a', 'ab')
266 ... f = open('a', 'ab')
267 ... f.write('a\n')
267 ... f.write('a\n')
268 ... f.close()
268 ... f.close()
269 ... runcommand(server, ['commit', '-Amm'])
269 ... runcommand(server, ['commit', '-Amm'])
270 ... runcommand(server, ['bookmarks'])
270 ... runcommand(server, ['bookmarks'])
271 *** runcommand bookmarks
271 *** runcommand bookmarks
272 no bookmarks set
272 no bookmarks set
273 *** runcommand bookmarks
273 *** runcommand bookmarks
274 bm1 1:d3a0a68be6de
274 bm1 1:d3a0a68be6de
275 bm2 1:d3a0a68be6de
275 bm2 1:d3a0a68be6de
276 *** runcommand bookmarks
276 *** runcommand bookmarks
277 * bm1 1:d3a0a68be6de
277 * bm1 1:d3a0a68be6de
278 bm2 1:d3a0a68be6de
278 bm2 1:d3a0a68be6de
279 *** runcommand bookmarks bm3
279 *** runcommand bookmarks bm3
280 *** runcommand commit -Amm
280 *** runcommand commit -Amm
281 *** runcommand bookmarks
281 *** runcommand bookmarks
282 bm1 1:d3a0a68be6de
282 bm1 1:d3a0a68be6de
283 bm2 1:d3a0a68be6de
283 bm2 1:d3a0a68be6de
284 * bm3 2:aef17e88f5f0
284 * bm3 2:aef17e88f5f0
285
285
286 >>> import os
286 >>> import os
287 >>> from hgclient import readchannel, runcommand, check
287 >>> from hgclient import readchannel, runcommand, check
288 >>> @check
288 >>> @check
289 ... def tagscache(server):
289 ... def tagscache(server):
290 ... readchannel(server)
290 ... readchannel(server)
291 ... runcommand(server, ['id', '-t', '-r', '0'])
291 ... runcommand(server, ['id', '-t', '-r', '0'])
292 ... os.system('hg tag -r 0 foo')
292 ... os.system('hg tag -r 0 foo')
293 ... runcommand(server, ['id', '-t', '-r', '0'])
293 ... runcommand(server, ['id', '-t', '-r', '0'])
294 *** runcommand id -t -r 0
294 *** runcommand id -t -r 0
295
295
296 *** runcommand id -t -r 0
296 *** runcommand id -t -r 0
297 foo
297 foo
298
298
299 >>> import os
299 >>> import os
300 >>> from hgclient import readchannel, runcommand, check
300 >>> from hgclient import readchannel, runcommand, check
301 >>> @check
301 >>> @check
302 ... def setphase(server):
302 ... def setphase(server):
303 ... readchannel(server)
303 ... readchannel(server)
304 ... runcommand(server, ['phase', '-r', '.'])
304 ... runcommand(server, ['phase', '-r', '.'])
305 ... os.system('hg phase -r . -p')
305 ... os.system('hg phase -r . -p')
306 ... runcommand(server, ['phase', '-r', '.'])
306 ... runcommand(server, ['phase', '-r', '.'])
307 *** runcommand phase -r .
307 *** runcommand phase -r .
308 3: draft
308 3: draft
309 *** runcommand phase -r .
309 *** runcommand phase -r .
310 3: public
310 3: public
311
311
312 $ echo a >> a
312 $ echo a >> a
313 >>> from hgclient import readchannel, runcommand, check
313 >>> from hgclient import readchannel, runcommand, check
314 >>> @check
314 >>> @check
315 ... def rollback(server):
315 ... def rollback(server):
316 ... readchannel(server)
316 ... readchannel(server)
317 ... runcommand(server, ['phase', '-r', '.', '-p'])
317 ... runcommand(server, ['phase', '-r', '.', '-p'])
318 ... runcommand(server, ['commit', '-Am.'])
318 ... runcommand(server, ['commit', '-Am.'])
319 ... runcommand(server, ['rollback'])
319 ... runcommand(server, ['rollback'])
320 ... runcommand(server, ['phase', '-r', '.'])
320 ... runcommand(server, ['phase', '-r', '.'])
321 *** runcommand phase -r . -p
321 *** runcommand phase -r . -p
322 no phases changed
322 no phases changed
323 [1]
323 [1]
324 *** runcommand commit -Am.
324 *** runcommand commit -Am.
325 *** runcommand rollback
325 *** runcommand rollback
326 repository tip rolled back to revision 3 (undo commit)
326 repository tip rolled back to revision 3 (undo commit)
327 working directory now based on revision 3
327 working directory now based on revision 3
328 *** runcommand phase -r .
328 *** runcommand phase -r .
329 3: public
329 3: public
330
330
331 >>> import os
331 >>> import os
332 >>> from hgclient import readchannel, runcommand, check
332 >>> from hgclient import readchannel, runcommand, check
333 >>> @check
333 >>> @check
334 ... def branch(server):
334 ... def branch(server):
335 ... readchannel(server)
335 ... readchannel(server)
336 ... runcommand(server, ['branch'])
336 ... runcommand(server, ['branch'])
337 ... os.system('hg branch foo')
337 ... os.system('hg branch foo')
338 ... runcommand(server, ['branch'])
338 ... runcommand(server, ['branch'])
339 ... os.system('hg branch default')
339 ... os.system('hg branch default')
340 *** runcommand branch
340 *** runcommand branch
341 default
341 default
342 marked working directory as branch foo
342 marked working directory as branch foo
343 (branches are permanent and global, did you want a bookmark?)
343 (branches are permanent and global, did you want a bookmark?)
344 *** runcommand branch
344 *** runcommand branch
345 foo
345 foo
346 marked working directory as branch default
346 marked working directory as branch default
347 (branches are permanent and global, did you want a bookmark?)
347 (branches are permanent and global, did you want a bookmark?)
348
348
349 $ touch .hgignore
349 $ touch .hgignore
350 >>> import os
350 >>> import os
351 >>> from hgclient import readchannel, runcommand, check
351 >>> from hgclient import readchannel, runcommand, check
352 >>> @check
352 >>> @check
353 ... def hgignore(server):
353 ... def hgignore(server):
354 ... readchannel(server)
354 ... readchannel(server)
355 ... runcommand(server, ['commit', '-Am.'])
355 ... runcommand(server, ['commit', '-Am.'])
356 ... f = open('ignored-file', 'ab')
356 ... f = open('ignored-file', 'ab')
357 ... f.write('')
357 ... f.write('')
358 ... f.close()
358 ... f.close()
359 ... f = open('.hgignore', 'ab')
359 ... f = open('.hgignore', 'ab')
360 ... f.write('ignored-file')
360 ... f.write('ignored-file')
361 ... f.close()
361 ... f.close()
362 ... runcommand(server, ['status', '-i', '-u'])
362 ... runcommand(server, ['status', '-i', '-u'])
363 *** runcommand commit -Am.
363 *** runcommand commit -Am.
364 adding .hgignore
364 adding .hgignore
365 *** runcommand status -i -u
365 *** runcommand status -i -u
366 I ignored-file
366 I ignored-file
367
367
368 >>> import os
368 >>> import os
369 >>> from hgclient import readchannel, sep, runcommand, check
369 >>> from hgclient import readchannel, sep, runcommand, check
370 >>> @check
370 >>> @check
371 ... def phasecacheafterstrip(server):
371 ... def phasecacheafterstrip(server):
372 ... readchannel(server)
372 ... readchannel(server)
373 ...
373 ...
374 ... # create new head, 5:731265503d86
374 ... # create new head, 5:731265503d86
375 ... runcommand(server, ['update', '-C', '0'])
375 ... runcommand(server, ['update', '-C', '0'])
376 ... f = open('a', 'ab')
376 ... f = open('a', 'ab')
377 ... f.write('a\n')
377 ... f.write('a\n')
378 ... f.close()
378 ... f.close()
379 ... runcommand(server, ['commit', '-Am.', 'a'])
379 ... runcommand(server, ['commit', '-Am.', 'a'])
380 ... runcommand(server, ['log', '-Gq'])
380 ... runcommand(server, ['log', '-Gq'])
381 ...
381 ...
382 ... # make it public; draft marker moves to 4:7966c8e3734d
382 ... # make it public; draft marker moves to 4:7966c8e3734d
383 ... runcommand(server, ['phase', '-p', '.'])
383 ... runcommand(server, ['phase', '-p', '.'])
384 ... # load _phasecache.phaseroots
384 ... # load _phasecache.phaseroots
385 ... runcommand(server, ['phase', '.'], outfilter=sep)
385 ... runcommand(server, ['phase', '.'], outfilter=sep)
386 ...
386 ...
387 ... # strip 1::4 outside server
387 ... # strip 1::4 outside server
388 ... os.system('hg -q --config extensions.mq= strip 1')
388 ... os.system('hg -q --config extensions.mq= strip 1')
389 ...
389 ...
390 ... # shouldn't raise "7966c8e3734d: no node!"
390 ... # shouldn't raise "7966c8e3734d: no node!"
391 ... runcommand(server, ['branches'])
391 ... runcommand(server, ['branches'])
392 *** runcommand update -C 0
392 *** runcommand update -C 0
393 1 files updated, 0 files merged, 2 files removed, 0 files unresolved
393 1 files updated, 0 files merged, 2 files removed, 0 files unresolved
394 (leaving bookmark bm3)
394 (leaving bookmark bm3)
395 *** runcommand commit -Am. a
395 *** runcommand commit -Am. a
396 created new head
396 created new head
397 *** runcommand log -Gq
397 *** runcommand log -Gq
398 @ 5:731265503d86
398 @ 5:731265503d86
399 |
399 |
400 | o 4:7966c8e3734d
400 | o 4:7966c8e3734d
401 | |
401 | |
402 | o 3:b9b85890c400
402 | o 3:b9b85890c400
403 | |
403 | |
404 | o 2:aef17e88f5f0
404 | o 2:aef17e88f5f0
405 | |
405 | |
406 | o 1:d3a0a68be6de
406 | o 1:d3a0a68be6de
407 |/
407 |/
408 o 0:eff892de26ec
408 o 0:eff892de26ec
409
409
410 *** runcommand phase -p .
410 *** runcommand phase -p .
411 *** runcommand phase .
411 *** runcommand phase .
412 5: public
412 5: public
413 *** runcommand branches
413 *** runcommand branches
414 default 1:731265503d86
414 default 1:731265503d86
415
415
416 $ cat >> .hg/hgrc << EOF
416 $ cat >> .hg/hgrc << EOF
417 > [experimental]
417 > [experimental]
418 > evolution=createmarkers
418 > evolution=createmarkers
419 > EOF
419 > EOF
420
420
421 >>> import os
421 >>> import os
422 >>> from hgclient import readchannel, runcommand, check
422 >>> from hgclient import readchannel, runcommand, check
423 >>> @check
423 >>> @check
424 ... def obsolete(server):
424 ... def obsolete(server):
425 ... readchannel(server)
425 ... readchannel(server)
426 ...
426 ...
427 ... runcommand(server, ['up', 'null'])
427 ... runcommand(server, ['up', 'null'])
428 ... runcommand(server, ['phase', '-df', 'tip'])
428 ... runcommand(server, ['phase', '-df', 'tip'])
429 ... cmd = 'hg debugobsolete `hg log -r tip --template {node}`'
429 ... cmd = 'hg debugobsolete `hg log -r tip --template {node}`'
430 ... if os.name == 'nt':
430 ... if os.name == 'nt':
431 ... cmd = 'sh -c "%s"' % cmd # run in sh, not cmd.exe
431 ... cmd = 'sh -c "%s"' % cmd # run in sh, not cmd.exe
432 ... os.system(cmd)
432 ... os.system(cmd)
433 ... runcommand(server, ['log', '--hidden'])
433 ... runcommand(server, ['log', '--hidden'])
434 ... runcommand(server, ['log'])
434 ... runcommand(server, ['log'])
435 *** runcommand up null
435 *** runcommand up null
436 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
436 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
437 *** runcommand phase -df tip
437 *** runcommand phase -df tip
438 *** runcommand log --hidden
438 *** runcommand log --hidden
439 changeset: 1:731265503d86
439 changeset: 1:731265503d86
440 tag: tip
440 tag: tip
441 user: test
441 user: test
442 date: Thu Jan 01 00:00:00 1970 +0000
442 date: Thu Jan 01 00:00:00 1970 +0000
443 summary: .
443 summary: .
444
444
445 changeset: 0:eff892de26ec
445 changeset: 0:eff892de26ec
446 bookmark: bm1
446 bookmark: bm1
447 bookmark: bm2
447 bookmark: bm2
448 bookmark: bm3
448 bookmark: bm3
449 user: test
449 user: test
450 date: Thu Jan 01 00:00:00 1970 +0000
450 date: Thu Jan 01 00:00:00 1970 +0000
451 summary: 1
451 summary: 1
452
452
453 *** runcommand log
453 *** runcommand log
454 changeset: 0:eff892de26ec
454 changeset: 0:eff892de26ec
455 bookmark: bm1
455 bookmark: bm1
456 bookmark: bm2
456 bookmark: bm2
457 bookmark: bm3
457 bookmark: bm3
458 tag: tip
458 tag: tip
459 user: test
459 user: test
460 date: Thu Jan 01 00:00:00 1970 +0000
460 date: Thu Jan 01 00:00:00 1970 +0000
461 summary: 1
461 summary: 1
462
462
463
463
464 $ cat <<EOF >> .hg/hgrc
464 $ cat <<EOF >> .hg/hgrc
465 > [extensions]
465 > [extensions]
466 > mq =
466 > mq =
467 > EOF
467 > EOF
468
468
469 >>> import os
469 >>> import os
470 >>> from hgclient import readchannel, runcommand, check
470 >>> from hgclient import readchannel, runcommand, check
471 >>> @check
471 >>> @check
472 ... def mqoutsidechanges(server):
472 ... def mqoutsidechanges(server):
473 ... readchannel(server)
473 ... readchannel(server)
474 ...
474 ...
475 ... # load repo.mq
475 ... # load repo.mq
476 ... runcommand(server, ['qapplied'])
476 ... runcommand(server, ['qapplied'])
477 ... os.system('hg qnew 0.diff')
477 ... os.system('hg qnew 0.diff')
478 ... # repo.mq should be invalidated
478 ... # repo.mq should be invalidated
479 ... runcommand(server, ['qapplied'])
479 ... runcommand(server, ['qapplied'])
480 ...
480 ...
481 ... runcommand(server, ['qpop', '--all'])
481 ... runcommand(server, ['qpop', '--all'])
482 ... os.system('hg qqueue --create foo')
482 ... os.system('hg qqueue --create foo')
483 ... # repo.mq should be recreated to point to new queue
483 ... # repo.mq should be recreated to point to new queue
484 ... runcommand(server, ['qqueue', '--active'])
484 ... runcommand(server, ['qqueue', '--active'])
485 *** runcommand qapplied
485 *** runcommand qapplied
486 *** runcommand qapplied
486 *** runcommand qapplied
487 0.diff
487 0.diff
488 *** runcommand qpop --all
488 *** runcommand qpop --all
489 popping 0.diff
489 popping 0.diff
490 patch queue now empty
490 patch queue now empty
491 *** runcommand qqueue --active
491 *** runcommand qqueue --active
492 foo
492 foo
493
493
494 $ cat <<EOF > dbgui.py
494 $ cat <<EOF > dbgui.py
495 > from mercurial import cmdutil, commands
495 > from mercurial import cmdutil, commands
496 > cmdtable = {}
496 > cmdtable = {}
497 > command = cmdutil.command(cmdtable)
497 > command = cmdutil.command(cmdtable)
498 > @command("debuggetpass", norepo=True)
498 > @command("debuggetpass", norepo=True)
499 > def debuggetpass(ui):
499 > def debuggetpass(ui):
500 > ui.write("%s\\n" % ui.getpass())
500 > ui.write("%s\\n" % ui.getpass())
501 > @command("debugprompt", norepo=True)
501 > @command("debugprompt", norepo=True)
502 > def debugprompt(ui):
502 > def debugprompt(ui):
503 > ui.write("%s\\n" % ui.prompt("prompt:"))
503 > ui.write("%s\\n" % ui.prompt("prompt:"))
504 > EOF
504 > EOF
505 $ cat <<EOF >> .hg/hgrc
505 $ cat <<EOF >> .hg/hgrc
506 > [extensions]
506 > [extensions]
507 > dbgui = dbgui.py
507 > dbgui = dbgui.py
508 > EOF
508 > EOF
509
509
510 >>> import cStringIO
510 >>> import cStringIO
511 >>> from hgclient import readchannel, runcommand, check
511 >>> from hgclient import readchannel, runcommand, check
512 >>> @check
512 >>> @check
513 ... def getpass(server):
513 ... def getpass(server):
514 ... readchannel(server)
514 ... readchannel(server)
515 ... runcommand(server, ['debuggetpass', '--config',
515 ... runcommand(server, ['debuggetpass', '--config',
516 ... 'ui.interactive=True'],
516 ... 'ui.interactive=True'],
517 ... input=cStringIO.StringIO('1234\n'))
517 ... input=cStringIO.StringIO('1234\n'))
518 ... runcommand(server, ['debugprompt', '--config',
518 ... runcommand(server, ['debugprompt', '--config',
519 ... 'ui.interactive=True'],
519 ... 'ui.interactive=True'],
520 ... input=cStringIO.StringIO('5678\n'))
520 ... input=cStringIO.StringIO('5678\n'))
521 *** runcommand debuggetpass --config ui.interactive=True
521 *** runcommand debuggetpass --config ui.interactive=True
522 password: 1234
522 password: 1234
523 *** runcommand debugprompt --config ui.interactive=True
523 *** runcommand debugprompt --config ui.interactive=True
524 prompt: 5678
524 prompt: 5678
525
525
526
526
527 run commandserver in commandserver, which is silly but should work:
528
529 >>> import cStringIO
530 >>> from hgclient import readchannel, runcommand, check
531 >>> @check
532 ... def nested(server):
533 ... print '%c, %r' % readchannel(server)
534 ... class nestedserver(object):
535 ... stdin = cStringIO.StringIO('getencoding\n')
536 ... stdout = cStringIO.StringIO()
537 ... runcommand(server, ['serve', '--cmdserver', 'pipe'],
538 ... output=nestedserver.stdout, input=nestedserver.stdin)
539 ... nestedserver.stdout.seek(0)
540 ... print '%c, %r' % readchannel(nestedserver) # hello
541 ... print '%c, %r' % readchannel(nestedserver) # getencoding
542 o, 'capabilities: getencoding runcommand\nencoding: *\npid: *' (glob)
543 *** runcommand serve --cmdserver pipe
544 o, 'capabilities: getencoding runcommand\nencoding: *\npid: *' (glob)
545 r, '*' (glob)
546
547
527 start without repository:
548 start without repository:
528
549
529 $ cd ..
550 $ cd ..
530
551
531 >>> from hgclient import readchannel, runcommand, check
552 >>> from hgclient import readchannel, runcommand, check
532 >>> @check
553 >>> @check
533 ... def hellomessage(server):
554 ... def hellomessage(server):
534 ... ch, data = readchannel(server)
555 ... ch, data = readchannel(server)
535 ... print '%c, %r' % (ch, data)
556 ... print '%c, %r' % (ch, data)
536 ... # run an arbitrary command to make sure the next thing the server
557 ... # run an arbitrary command to make sure the next thing the server
537 ... # sends isn't part of the hello message
558 ... # sends isn't part of the hello message
538 ... runcommand(server, ['id'])
559 ... runcommand(server, ['id'])
539 o, 'capabilities: getencoding runcommand\nencoding: *\npid: *' (glob)
560 o, 'capabilities: getencoding runcommand\nencoding: *\npid: *' (glob)
540 *** runcommand id
561 *** runcommand id
541 abort: there is no Mercurial repository here (.hg not found)
562 abort: there is no Mercurial repository here (.hg not found)
542 [255]
563 [255]
543
564
544 >>> from hgclient import readchannel, runcommand, check
565 >>> from hgclient import readchannel, runcommand, check
545 >>> @check
566 >>> @check
546 ... def startwithoutrepo(server):
567 ... def startwithoutrepo(server):
547 ... readchannel(server)
568 ... readchannel(server)
548 ... runcommand(server, ['init', 'repo2'])
569 ... runcommand(server, ['init', 'repo2'])
549 ... runcommand(server, ['id', '-R', 'repo2'])
570 ... runcommand(server, ['id', '-R', 'repo2'])
550 *** runcommand init repo2
571 *** runcommand init repo2
551 *** runcommand id -R repo2
572 *** runcommand id -R repo2
552 000000000000 tip
573 000000000000 tip
553
574
554
575
555 unix domain socket:
576 unix domain socket:
556
577
557 $ cd repo
578 $ cd repo
558 $ hg update -q
579 $ hg update -q
559
580
560 #if unix-socket unix-permissions
581 #if unix-socket unix-permissions
561
582
562 >>> import cStringIO
583 >>> import cStringIO
563 >>> from hgclient import unixserver, readchannel, runcommand, check
584 >>> from hgclient import unixserver, readchannel, runcommand, check
564 >>> server = unixserver('.hg/server.sock', '.hg/server.log')
585 >>> server = unixserver('.hg/server.sock', '.hg/server.log')
565 >>> def hellomessage(conn):
586 >>> def hellomessage(conn):
566 ... ch, data = readchannel(conn)
587 ... ch, data = readchannel(conn)
567 ... print '%c, %r' % (ch, data)
588 ... print '%c, %r' % (ch, data)
568 ... runcommand(conn, ['id'])
589 ... runcommand(conn, ['id'])
569 >>> check(hellomessage, server.connect)
590 >>> check(hellomessage, server.connect)
570 o, 'capabilities: getencoding runcommand\nencoding: *\npid: *' (glob)
591 o, 'capabilities: getencoding runcommand\nencoding: *\npid: *' (glob)
571 *** runcommand id
592 *** runcommand id
572 eff892de26ec tip bm1/bm2/bm3
593 eff892de26ec tip bm1/bm2/bm3
573 >>> def unknowncommand(conn):
594 >>> def unknowncommand(conn):
574 ... readchannel(conn)
595 ... readchannel(conn)
575 ... conn.stdin.write('unknowncommand\n')
596 ... conn.stdin.write('unknowncommand\n')
576 >>> check(unknowncommand, server.connect) # error sent to server.log
597 >>> check(unknowncommand, server.connect) # error sent to server.log
577 >>> def serverinput(conn):
598 >>> def serverinput(conn):
578 ... readchannel(conn)
599 ... readchannel(conn)
579 ... patch = """
600 ... patch = """
580 ... # HG changeset patch
601 ... # HG changeset patch
581 ... # User test
602 ... # User test
582 ... # Date 0 0
603 ... # Date 0 0
583 ... 2
604 ... 2
584 ...
605 ...
585 ... diff -r eff892de26ec -r 1ed24be7e7a0 a
606 ... diff -r eff892de26ec -r 1ed24be7e7a0 a
586 ... --- a/a
607 ... --- a/a
587 ... +++ b/a
608 ... +++ b/a
588 ... @@ -1,1 +1,2 @@
609 ... @@ -1,1 +1,2 @@
589 ... 1
610 ... 1
590 ... +2
611 ... +2
591 ... """
612 ... """
592 ... runcommand(conn, ['import', '-'], input=cStringIO.StringIO(patch))
613 ... runcommand(conn, ['import', '-'], input=cStringIO.StringIO(patch))
593 ... runcommand(conn, ['log', '-rtip', '-q'])
614 ... runcommand(conn, ['log', '-rtip', '-q'])
594 >>> check(serverinput, server.connect)
615 >>> check(serverinput, server.connect)
595 *** runcommand import -
616 *** runcommand import -
596 applying patch from stdin
617 applying patch from stdin
597 *** runcommand log -rtip -q
618 *** runcommand log -rtip -q
598 2:1ed24be7e7a0
619 2:1ed24be7e7a0
599 >>> server.shutdown()
620 >>> server.shutdown()
600
621
601 $ cat .hg/server.log
622 $ cat .hg/server.log
602 listening at .hg/server.sock
623 listening at .hg/server.sock
603 abort: unknown command unknowncommand
624 abort: unknown command unknowncommand
604 killed!
625 killed!
605 #endif
626 #endif
606 #if no-unix-socket
627 #if no-unix-socket
607
628
608 $ hg serve --cmdserver unix -a .hg/server.sock
629 $ hg serve --cmdserver unix -a .hg/server.sock
609 abort: unsupported platform
630 abort: unsupported platform
610 [255]
631 [255]
611
632
612 #endif
633 #endif
General Comments 0
You need to be logged in to leave comments. Login now