##// END OF EJS Templates
chgserver: add setumask method...
Jun Wu -
r28159:d2d04d1d default
parent child Browse files
Show More
@@ -1,392 +1,399 b''
1 # chgserver.py - command server extension for cHg
1 # chgserver.py - command server extension for cHg
2 #
2 #
3 # Copyright 2011 Yuya Nishihara <yuya@tcha.org>
3 # Copyright 2011 Yuya Nishihara <yuya@tcha.org>
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 """command server extension for cHg (EXPERIMENTAL)
8 """command server extension for cHg (EXPERIMENTAL)
9
9
10 'S' channel (read/write)
10 'S' channel (read/write)
11 propagate ui.system() request to client
11 propagate ui.system() request to client
12
12
13 'attachio' command
13 'attachio' command
14 attach client's stdio passed by sendmsg()
14 attach client's stdio passed by sendmsg()
15
15
16 'chdir' command
16 'chdir' command
17 change current directory
17 change current directory
18
18
19 'getpager' command
19 'getpager' command
20 checks if pager is enabled and which pager should be executed
20 checks if pager is enabled and which pager should be executed
21
21
22 'setenv' command
22 'setenv' command
23 replace os.environ completely
23 replace os.environ completely
24
24
25 'SIGHUP' signal
25 'SIGHUP' signal
26 reload configuration files
26 reload configuration files
27 """
27 """
28
28
29 from __future__ import absolute_import
29 from __future__ import absolute_import
30
30
31 import SocketServer
31 import SocketServer
32 import errno
32 import errno
33 import os
33 import os
34 import re
34 import re
35 import signal
35 import signal
36 import struct
36 import struct
37 import traceback
37 import traceback
38
38
39 from mercurial.i18n import _
39 from mercurial.i18n import _
40
40
41 from mercurial import (
41 from mercurial import (
42 cmdutil,
42 cmdutil,
43 commands,
43 commands,
44 commandserver,
44 commandserver,
45 dispatch,
45 dispatch,
46 error,
46 error,
47 osutil,
47 osutil,
48 util,
48 util,
49 )
49 )
50
50
51 # Note for extension authors: ONLY specify testedwith = 'internal' for
51 # Note for extension authors: ONLY specify testedwith = 'internal' for
52 # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
52 # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
53 # be specifying the version(s) of Mercurial they are tested with, or
53 # be specifying the version(s) of Mercurial they are tested with, or
54 # leave the attribute unspecified.
54 # leave the attribute unspecified.
55 testedwith = 'internal'
55 testedwith = 'internal'
56
56
57 _log = commandserver.log
57 _log = commandserver.log
58
58
59 # copied from hgext/pager.py:uisetup()
59 # copied from hgext/pager.py:uisetup()
60 def _setuppagercmd(ui, options, cmd):
60 def _setuppagercmd(ui, options, cmd):
61 if not ui.formatted():
61 if not ui.formatted():
62 return
62 return
63
63
64 p = ui.config("pager", "pager", os.environ.get("PAGER"))
64 p = ui.config("pager", "pager", os.environ.get("PAGER"))
65 usepager = False
65 usepager = False
66 always = util.parsebool(options['pager'])
66 always = util.parsebool(options['pager'])
67 auto = options['pager'] == 'auto'
67 auto = options['pager'] == 'auto'
68
68
69 if not p:
69 if not p:
70 pass
70 pass
71 elif always:
71 elif always:
72 usepager = True
72 usepager = True
73 elif not auto:
73 elif not auto:
74 usepager = False
74 usepager = False
75 else:
75 else:
76 attended = ['annotate', 'cat', 'diff', 'export', 'glog', 'log', 'qdiff']
76 attended = ['annotate', 'cat', 'diff', 'export', 'glog', 'log', 'qdiff']
77 attend = ui.configlist('pager', 'attend', attended)
77 attend = ui.configlist('pager', 'attend', attended)
78 ignore = ui.configlist('pager', 'ignore')
78 ignore = ui.configlist('pager', 'ignore')
79 cmds, _ = cmdutil.findcmd(cmd, commands.table)
79 cmds, _ = cmdutil.findcmd(cmd, commands.table)
80
80
81 for cmd in cmds:
81 for cmd in cmds:
82 var = 'attend-%s' % cmd
82 var = 'attend-%s' % cmd
83 if ui.config('pager', var):
83 if ui.config('pager', var):
84 usepager = ui.configbool('pager', var)
84 usepager = ui.configbool('pager', var)
85 break
85 break
86 if (cmd in attend or
86 if (cmd in attend or
87 (cmd not in ignore and not attend)):
87 (cmd not in ignore and not attend)):
88 usepager = True
88 usepager = True
89 break
89 break
90
90
91 if usepager:
91 if usepager:
92 ui.setconfig('ui', 'formatted', ui.formatted(), 'pager')
92 ui.setconfig('ui', 'formatted', ui.formatted(), 'pager')
93 ui.setconfig('ui', 'interactive', False, 'pager')
93 ui.setconfig('ui', 'interactive', False, 'pager')
94 return p
94 return p
95
95
96 _envvarre = re.compile(r'\$[a-zA-Z_]+')
96 _envvarre = re.compile(r'\$[a-zA-Z_]+')
97
97
98 def _clearenvaliases(cmdtable):
98 def _clearenvaliases(cmdtable):
99 """Remove stale command aliases referencing env vars; variable expansion
99 """Remove stale command aliases referencing env vars; variable expansion
100 is done at dispatch.addaliases()"""
100 is done at dispatch.addaliases()"""
101 for name, tab in cmdtable.items():
101 for name, tab in cmdtable.items():
102 cmddef = tab[0]
102 cmddef = tab[0]
103 if (isinstance(cmddef, dispatch.cmdalias) and
103 if (isinstance(cmddef, dispatch.cmdalias) and
104 not cmddef.definition.startswith('!') and # shell alias
104 not cmddef.definition.startswith('!') and # shell alias
105 _envvarre.search(cmddef.definition)):
105 _envvarre.search(cmddef.definition)):
106 del cmdtable[name]
106 del cmdtable[name]
107
107
108 def _newchgui(srcui, csystem):
108 def _newchgui(srcui, csystem):
109 class chgui(srcui.__class__):
109 class chgui(srcui.__class__):
110 def __init__(self, src=None):
110 def __init__(self, src=None):
111 super(chgui, self).__init__(src)
111 super(chgui, self).__init__(src)
112 if src:
112 if src:
113 self._csystem = getattr(src, '_csystem', csystem)
113 self._csystem = getattr(src, '_csystem', csystem)
114 else:
114 else:
115 self._csystem = csystem
115 self._csystem = csystem
116
116
117 def system(self, cmd, environ=None, cwd=None, onerr=None,
117 def system(self, cmd, environ=None, cwd=None, onerr=None,
118 errprefix=None):
118 errprefix=None):
119 # copied from mercurial/util.py:system()
119 # copied from mercurial/util.py:system()
120 self.flush()
120 self.flush()
121 def py2shell(val):
121 def py2shell(val):
122 if val is None or val is False:
122 if val is None or val is False:
123 return '0'
123 return '0'
124 if val is True:
124 if val is True:
125 return '1'
125 return '1'
126 return str(val)
126 return str(val)
127 env = os.environ.copy()
127 env = os.environ.copy()
128 if environ:
128 if environ:
129 env.update((k, py2shell(v)) for k, v in environ.iteritems())
129 env.update((k, py2shell(v)) for k, v in environ.iteritems())
130 env['HG'] = util.hgexecutable()
130 env['HG'] = util.hgexecutable()
131 rc = self._csystem(cmd, env, cwd)
131 rc = self._csystem(cmd, env, cwd)
132 if rc and onerr:
132 if rc and onerr:
133 errmsg = '%s %s' % (os.path.basename(cmd.split(None, 1)[0]),
133 errmsg = '%s %s' % (os.path.basename(cmd.split(None, 1)[0]),
134 util.explainexit(rc)[0])
134 util.explainexit(rc)[0])
135 if errprefix:
135 if errprefix:
136 errmsg = '%s: %s' % (errprefix, errmsg)
136 errmsg = '%s: %s' % (errprefix, errmsg)
137 raise onerr(errmsg)
137 raise onerr(errmsg)
138 return rc
138 return rc
139
139
140 return chgui(srcui)
140 return chgui(srcui)
141
141
142 def _renewui(srcui):
142 def _renewui(srcui):
143 newui = srcui.__class__()
143 newui = srcui.__class__()
144 for a in ['fin', 'fout', 'ferr', 'environ']:
144 for a in ['fin', 'fout', 'ferr', 'environ']:
145 setattr(newui, a, getattr(srcui, a))
145 setattr(newui, a, getattr(srcui, a))
146 if util.safehasattr(srcui, '_csystem'):
146 if util.safehasattr(srcui, '_csystem'):
147 newui._csystem = srcui._csystem
147 newui._csystem = srcui._csystem
148 # stolen from tortoisehg.util.copydynamicconfig()
148 # stolen from tortoisehg.util.copydynamicconfig()
149 for section, name, value in srcui.walkconfig():
149 for section, name, value in srcui.walkconfig():
150 source = srcui.configsource(section, name)
150 source = srcui.configsource(section, name)
151 if ':' in source:
151 if ':' in source:
152 # path:line
152 # path:line
153 continue
153 continue
154 if source == 'none':
154 if source == 'none':
155 # ui.configsource returns 'none' by default
155 # ui.configsource returns 'none' by default
156 source = ''
156 source = ''
157 newui.setconfig(section, name, value, source)
157 newui.setconfig(section, name, value, source)
158 return newui
158 return newui
159
159
160 class channeledsystem(object):
160 class channeledsystem(object):
161 """Propagate ui.system() request in the following format:
161 """Propagate ui.system() request in the following format:
162
162
163 payload length (unsigned int),
163 payload length (unsigned int),
164 cmd, '\0',
164 cmd, '\0',
165 cwd, '\0',
165 cwd, '\0',
166 envkey, '=', val, '\0',
166 envkey, '=', val, '\0',
167 ...
167 ...
168 envkey, '=', val
168 envkey, '=', val
169
169
170 and waits:
170 and waits:
171
171
172 exitcode length (unsigned int),
172 exitcode length (unsigned int),
173 exitcode (int)
173 exitcode (int)
174 """
174 """
175 def __init__(self, in_, out, channel):
175 def __init__(self, in_, out, channel):
176 self.in_ = in_
176 self.in_ = in_
177 self.out = out
177 self.out = out
178 self.channel = channel
178 self.channel = channel
179
179
180 def __call__(self, cmd, environ, cwd):
180 def __call__(self, cmd, environ, cwd):
181 args = [util.quotecommand(cmd), cwd or '.']
181 args = [util.quotecommand(cmd), cwd or '.']
182 args.extend('%s=%s' % (k, v) for k, v in environ.iteritems())
182 args.extend('%s=%s' % (k, v) for k, v in environ.iteritems())
183 data = '\0'.join(args)
183 data = '\0'.join(args)
184 self.out.write(struct.pack('>cI', self.channel, len(data)))
184 self.out.write(struct.pack('>cI', self.channel, len(data)))
185 self.out.write(data)
185 self.out.write(data)
186 self.out.flush()
186 self.out.flush()
187
187
188 length = self.in_.read(4)
188 length = self.in_.read(4)
189 length, = struct.unpack('>I', length)
189 length, = struct.unpack('>I', length)
190 if length != 4:
190 if length != 4:
191 raise error.Abort(_('invalid response'))
191 raise error.Abort(_('invalid response'))
192 rc, = struct.unpack('>i', self.in_.read(4))
192 rc, = struct.unpack('>i', self.in_.read(4))
193 return rc
193 return rc
194
194
195 _iochannels = [
195 _iochannels = [
196 # server.ch, ui.fp, mode
196 # server.ch, ui.fp, mode
197 ('cin', 'fin', 'rb'),
197 ('cin', 'fin', 'rb'),
198 ('cout', 'fout', 'wb'),
198 ('cout', 'fout', 'wb'),
199 ('cerr', 'ferr', 'wb'),
199 ('cerr', 'ferr', 'wb'),
200 ]
200 ]
201
201
202 class chgcmdserver(commandserver.server):
202 class chgcmdserver(commandserver.server):
203 def __init__(self, ui, repo, fin, fout, sock):
203 def __init__(self, ui, repo, fin, fout, sock):
204 super(chgcmdserver, self).__init__(
204 super(chgcmdserver, self).__init__(
205 _newchgui(ui, channeledsystem(fin, fout, 'S')), repo, fin, fout)
205 _newchgui(ui, channeledsystem(fin, fout, 'S')), repo, fin, fout)
206 self.clientsock = sock
206 self.clientsock = sock
207 self._oldios = [] # original (self.ch, ui.fp, fd) before "attachio"
207 self._oldios = [] # original (self.ch, ui.fp, fd) before "attachio"
208
208
209 def cleanup(self):
209 def cleanup(self):
210 # dispatch._runcatch() does not flush outputs if exception is not
210 # dispatch._runcatch() does not flush outputs if exception is not
211 # handled by dispatch._dispatch()
211 # handled by dispatch._dispatch()
212 self.ui.flush()
212 self.ui.flush()
213 self._restoreio()
213 self._restoreio()
214
214
215 def attachio(self):
215 def attachio(self):
216 """Attach to client's stdio passed via unix domain socket; all
216 """Attach to client's stdio passed via unix domain socket; all
217 channels except cresult will no longer be used
217 channels except cresult will no longer be used
218 """
218 """
219 # tell client to sendmsg() with 1-byte payload, which makes it
219 # tell client to sendmsg() with 1-byte payload, which makes it
220 # distinctive from "attachio\n" command consumed by client.read()
220 # distinctive from "attachio\n" command consumed by client.read()
221 self.clientsock.sendall(struct.pack('>cI', 'I', 1))
221 self.clientsock.sendall(struct.pack('>cI', 'I', 1))
222 clientfds = osutil.recvfds(self.clientsock.fileno())
222 clientfds = osutil.recvfds(self.clientsock.fileno())
223 _log('received fds: %r\n' % clientfds)
223 _log('received fds: %r\n' % clientfds)
224
224
225 ui = self.ui
225 ui = self.ui
226 ui.flush()
226 ui.flush()
227 first = self._saveio()
227 first = self._saveio()
228 for fd, (cn, fn, mode) in zip(clientfds, _iochannels):
228 for fd, (cn, fn, mode) in zip(clientfds, _iochannels):
229 assert fd > 0
229 assert fd > 0
230 fp = getattr(ui, fn)
230 fp = getattr(ui, fn)
231 os.dup2(fd, fp.fileno())
231 os.dup2(fd, fp.fileno())
232 os.close(fd)
232 os.close(fd)
233 if not first:
233 if not first:
234 continue
234 continue
235 # reset buffering mode when client is first attached. as we want
235 # reset buffering mode when client is first attached. as we want
236 # to see output immediately on pager, the mode stays unchanged
236 # to see output immediately on pager, the mode stays unchanged
237 # when client re-attached. ferr is unchanged because it should
237 # when client re-attached. ferr is unchanged because it should
238 # be unbuffered no matter if it is a tty or not.
238 # be unbuffered no matter if it is a tty or not.
239 if fn == 'ferr':
239 if fn == 'ferr':
240 newfp = fp
240 newfp = fp
241 else:
241 else:
242 # make it line buffered explicitly because the default is
242 # make it line buffered explicitly because the default is
243 # decided on first write(), where fout could be a pager.
243 # decided on first write(), where fout could be a pager.
244 if fp.isatty():
244 if fp.isatty():
245 bufsize = 1 # line buffered
245 bufsize = 1 # line buffered
246 else:
246 else:
247 bufsize = -1 # system default
247 bufsize = -1 # system default
248 newfp = os.fdopen(fp.fileno(), mode, bufsize)
248 newfp = os.fdopen(fp.fileno(), mode, bufsize)
249 setattr(ui, fn, newfp)
249 setattr(ui, fn, newfp)
250 setattr(self, cn, newfp)
250 setattr(self, cn, newfp)
251
251
252 self.cresult.write(struct.pack('>i', len(clientfds)))
252 self.cresult.write(struct.pack('>i', len(clientfds)))
253
253
254 def _saveio(self):
254 def _saveio(self):
255 if self._oldios:
255 if self._oldios:
256 return False
256 return False
257 ui = self.ui
257 ui = self.ui
258 for cn, fn, _mode in _iochannels:
258 for cn, fn, _mode in _iochannels:
259 ch = getattr(self, cn)
259 ch = getattr(self, cn)
260 fp = getattr(ui, fn)
260 fp = getattr(ui, fn)
261 fd = os.dup(fp.fileno())
261 fd = os.dup(fp.fileno())
262 self._oldios.append((ch, fp, fd))
262 self._oldios.append((ch, fp, fd))
263 return True
263 return True
264
264
265 def _restoreio(self):
265 def _restoreio(self):
266 ui = self.ui
266 ui = self.ui
267 for (ch, fp, fd), (cn, fn, _mode) in zip(self._oldios, _iochannels):
267 for (ch, fp, fd), (cn, fn, _mode) in zip(self._oldios, _iochannels):
268 newfp = getattr(ui, fn)
268 newfp = getattr(ui, fn)
269 # close newfp while it's associated with client; otherwise it
269 # close newfp while it's associated with client; otherwise it
270 # would be closed when newfp is deleted
270 # would be closed when newfp is deleted
271 if newfp is not fp:
271 if newfp is not fp:
272 newfp.close()
272 newfp.close()
273 # restore original fd: fp is open again
273 # restore original fd: fp is open again
274 os.dup2(fd, fp.fileno())
274 os.dup2(fd, fp.fileno())
275 os.close(fd)
275 os.close(fd)
276 setattr(self, cn, ch)
276 setattr(self, cn, ch)
277 setattr(ui, fn, fp)
277 setattr(ui, fn, fp)
278 del self._oldios[:]
278 del self._oldios[:]
279
279
280 def chdir(self):
280 def chdir(self):
281 """Change current directory
281 """Change current directory
282
282
283 Note that the behavior of --cwd option is bit different from this.
283 Note that the behavior of --cwd option is bit different from this.
284 It does not affect --config parameter.
284 It does not affect --config parameter.
285 """
285 """
286 path = self._readstr()
286 path = self._readstr()
287 if not path:
287 if not path:
288 return
288 return
289 _log('chdir to %r\n' % path)
289 _log('chdir to %r\n' % path)
290 os.chdir(path)
290 os.chdir(path)
291
291
292 def setumask(self):
293 """Change umask"""
294 mask = struct.unpack('>I', self._read(4))[0]
295 _log('setumask %r\n' % mask)
296 os.umask(mask)
297
292 def getpager(self):
298 def getpager(self):
293 """Read cmdargs and write pager command to r-channel if enabled
299 """Read cmdargs and write pager command to r-channel if enabled
294
300
295 If pager isn't enabled, this writes '\0' because channeledoutput
301 If pager isn't enabled, this writes '\0' because channeledoutput
296 does not allow to write empty data.
302 does not allow to write empty data.
297 """
303 """
298 args = self._readlist()
304 args = self._readlist()
299 try:
305 try:
300 cmd, _func, args, options, _cmdoptions = dispatch._parse(self.ui,
306 cmd, _func, args, options, _cmdoptions = dispatch._parse(self.ui,
301 args)
307 args)
302 except (error.Abort, error.AmbiguousCommand, error.CommandError,
308 except (error.Abort, error.AmbiguousCommand, error.CommandError,
303 error.UnknownCommand):
309 error.UnknownCommand):
304 cmd = None
310 cmd = None
305 options = {}
311 options = {}
306 if not cmd or 'pager' not in options:
312 if not cmd or 'pager' not in options:
307 self.cresult.write('\0')
313 self.cresult.write('\0')
308 return
314 return
309
315
310 pagercmd = _setuppagercmd(self.ui, options, cmd)
316 pagercmd = _setuppagercmd(self.ui, options, cmd)
311 if pagercmd:
317 if pagercmd:
312 self.cresult.write(pagercmd)
318 self.cresult.write(pagercmd)
313 else:
319 else:
314 self.cresult.write('\0')
320 self.cresult.write('\0')
315
321
316 def setenv(self):
322 def setenv(self):
317 """Clear and update os.environ
323 """Clear and update os.environ
318
324
319 Note that not all variables can make an effect on the running process.
325 Note that not all variables can make an effect on the running process.
320 """
326 """
321 l = self._readlist()
327 l = self._readlist()
322 try:
328 try:
323 newenv = dict(s.split('=', 1) for s in l)
329 newenv = dict(s.split('=', 1) for s in l)
324 except ValueError:
330 except ValueError:
325 raise ValueError('unexpected value in setenv request')
331 raise ValueError('unexpected value in setenv request')
326
332
327 diffkeys = set(k for k in set(os.environ.keys() + newenv.keys())
333 diffkeys = set(k for k in set(os.environ.keys() + newenv.keys())
328 if os.environ.get(k) != newenv.get(k))
334 if os.environ.get(k) != newenv.get(k))
329 _log('change env: %r\n' % sorted(diffkeys))
335 _log('change env: %r\n' % sorted(diffkeys))
330
336
331 os.environ.clear()
337 os.environ.clear()
332 os.environ.update(newenv)
338 os.environ.update(newenv)
333
339
334 if set(['HGPLAIN', 'HGPLAINEXCEPT']) & diffkeys:
340 if set(['HGPLAIN', 'HGPLAINEXCEPT']) & diffkeys:
335 # reload config so that ui.plain() takes effect
341 # reload config so that ui.plain() takes effect
336 self.ui = _renewui(self.ui)
342 self.ui = _renewui(self.ui)
337
343
338 _clearenvaliases(commands.table)
344 _clearenvaliases(commands.table)
339
345
340 capabilities = commandserver.server.capabilities.copy()
346 capabilities = commandserver.server.capabilities.copy()
341 capabilities.update({'attachio': attachio,
347 capabilities.update({'attachio': attachio,
342 'chdir': chdir,
348 'chdir': chdir,
343 'getpager': getpager,
349 'getpager': getpager,
344 'setenv': setenv})
350 'setenv': setenv,
351 'setumask': setumask})
345
352
346 # copied from mercurial/commandserver.py
353 # copied from mercurial/commandserver.py
347 class _requesthandler(SocketServer.StreamRequestHandler):
354 class _requesthandler(SocketServer.StreamRequestHandler):
348 def handle(self):
355 def handle(self):
349 # use a different process group from the master process, making this
356 # use a different process group from the master process, making this
350 # process pass kernel "is_current_pgrp_orphaned" check so signals like
357 # process pass kernel "is_current_pgrp_orphaned" check so signals like
351 # SIGTSTP, SIGTTIN, SIGTTOU are not ignored.
358 # SIGTSTP, SIGTTIN, SIGTTOU are not ignored.
352 os.setpgid(0, 0)
359 os.setpgid(0, 0)
353 ui = self.server.ui
360 ui = self.server.ui
354 repo = self.server.repo
361 repo = self.server.repo
355 sv = chgcmdserver(ui, repo, self.rfile, self.wfile, self.connection)
362 sv = chgcmdserver(ui, repo, self.rfile, self.wfile, self.connection)
356 try:
363 try:
357 try:
364 try:
358 sv.serve()
365 sv.serve()
359 # handle exceptions that may be raised by command server. most of
366 # handle exceptions that may be raised by command server. most of
360 # known exceptions are caught by dispatch.
367 # known exceptions are caught by dispatch.
361 except error.Abort as inst:
368 except error.Abort as inst:
362 ui.warn(_('abort: %s\n') % inst)
369 ui.warn(_('abort: %s\n') % inst)
363 except IOError as inst:
370 except IOError as inst:
364 if inst.errno != errno.EPIPE:
371 if inst.errno != errno.EPIPE:
365 raise
372 raise
366 except KeyboardInterrupt:
373 except KeyboardInterrupt:
367 pass
374 pass
368 finally:
375 finally:
369 sv.cleanup()
376 sv.cleanup()
370 except: # re-raises
377 except: # re-raises
371 # also write traceback to error channel. otherwise client cannot
378 # also write traceback to error channel. otherwise client cannot
372 # see it because it is written to server's stderr by default.
379 # see it because it is written to server's stderr by default.
373 traceback.print_exc(file=sv.cerr)
380 traceback.print_exc(file=sv.cerr)
374 raise
381 raise
375
382
376 class chgunixservice(commandserver.unixservice):
383 class chgunixservice(commandserver.unixservice):
377 def init(self):
384 def init(self):
378 # drop options set for "hg serve --cmdserver" command
385 # drop options set for "hg serve --cmdserver" command
379 self.ui.setconfig('progress', 'assume-tty', None)
386 self.ui.setconfig('progress', 'assume-tty', None)
380 signal.signal(signal.SIGHUP, self._reloadconfig)
387 signal.signal(signal.SIGHUP, self._reloadconfig)
381 class cls(SocketServer.ForkingMixIn, SocketServer.UnixStreamServer):
388 class cls(SocketServer.ForkingMixIn, SocketServer.UnixStreamServer):
382 ui = self.ui
389 ui = self.ui
383 repo = self.repo
390 repo = self.repo
384 self.server = cls(self.address, _requesthandler)
391 self.server = cls(self.address, _requesthandler)
385 # avoid writing "listening at" message to stdout before attachio
392 # avoid writing "listening at" message to stdout before attachio
386 # request, which calls setvbuf()
393 # request, which calls setvbuf()
387
394
388 def _reloadconfig(self, signum, frame):
395 def _reloadconfig(self, signum, frame):
389 self.ui = self.server.ui = _renewui(self.ui)
396 self.ui = self.server.ui = _renewui(self.ui)
390
397
391 def uisetup(ui):
398 def uisetup(ui):
392 commandserver._servicemap['chgunix'] = chgunixservice
399 commandserver._servicemap['chgunix'] = chgunixservice
General Comments 0
You need to be logged in to leave comments. Login now