comparison mercurial/chgserver.py @ 39738:a93fe297dfb3

chgserver: add separate flag to remember if stdio fds are replaced I want to make it use a separate saved buffer for "attachio" requests within "runcommand" session. See the next patch for details.
author Yuya Nishihara <yuya@tcha.org>
date Wed, 19 Sep 2018 22:57:47 +0900
parents a8a902d7176e
children 7cdd47d9ccf8
comparison
equal deleted inserted replaced
39737:fd805a44b89d 39738:a93fe297dfb3
309 def __init__(self, ui, repo, fin, fout, sock, hashstate, baseaddress): 309 def __init__(self, ui, repo, fin, fout, sock, hashstate, baseaddress):
310 super(chgcmdserver, self).__init__( 310 super(chgcmdserver, self).__init__(
311 _newchgui(ui, channeledsystem(fin, fout, 'S'), self.attachio), 311 _newchgui(ui, channeledsystem(fin, fout, 'S'), self.attachio),
312 repo, fin, fout) 312 repo, fin, fout)
313 self.clientsock = sock 313 self.clientsock = sock
314 self._ioattached = False
314 self._oldios = [] # original (self.ch, ui.fp, fd) before "attachio" 315 self._oldios = [] # original (self.ch, ui.fp, fd) before "attachio"
315 self.hashstate = hashstate 316 self.hashstate = hashstate
316 self.baseaddress = baseaddress 317 self.baseaddress = baseaddress
317 if hashstate is not None: 318 if hashstate is not None:
318 self.capabilities = self.capabilities.copy() 319 self.capabilities = self.capabilities.copy()
322 super(chgcmdserver, self).cleanup() 323 super(chgcmdserver, self).cleanup()
323 # dispatch._runcatch() does not flush outputs if exception is not 324 # dispatch._runcatch() does not flush outputs if exception is not
324 # handled by dispatch._dispatch() 325 # handled by dispatch._dispatch()
325 self.ui.flush() 326 self.ui.flush()
326 self._restoreio() 327 self._restoreio()
328 self._ioattached = False
327 329
328 def attachio(self): 330 def attachio(self):
329 """Attach to client's stdio passed via unix domain socket; all 331 """Attach to client's stdio passed via unix domain socket; all
330 channels except cresult will no longer be used 332 channels except cresult will no longer be used
331 """ 333 """
335 clientfds = util.recvfds(self.clientsock.fileno()) 337 clientfds = util.recvfds(self.clientsock.fileno())
336 _log('received fds: %r\n' % clientfds) 338 _log('received fds: %r\n' % clientfds)
337 339
338 ui = self.ui 340 ui = self.ui
339 ui.flush() 341 ui.flush()
340 first = self._saveio() 342 self._saveio()
341 for fd, (cn, fn, mode) in zip(clientfds, _iochannels): 343 for fd, (cn, fn, mode) in zip(clientfds, _iochannels):
342 assert fd > 0 344 assert fd > 0
343 fp = getattr(ui, fn) 345 fp = getattr(ui, fn)
344 os.dup2(fd, fp.fileno()) 346 os.dup2(fd, fp.fileno())
345 os.close(fd) 347 os.close(fd)
346 if not first: 348 if self._ioattached:
347 continue 349 continue
348 # reset buffering mode when client is first attached. as we want 350 # reset buffering mode when client is first attached. as we want
349 # to see output immediately on pager, the mode stays unchanged 351 # to see output immediately on pager, the mode stays unchanged
350 # when client re-attached. ferr is unchanged because it should 352 # when client re-attached. ferr is unchanged because it should
351 # be unbuffered no matter if it is a tty or not. 353 # be unbuffered no matter if it is a tty or not.
360 bufsize = -1 # system default 362 bufsize = -1 # system default
361 newfp = os.fdopen(fp.fileno(), mode, bufsize) 363 newfp = os.fdopen(fp.fileno(), mode, bufsize)
362 setattr(ui, fn, newfp) 364 setattr(ui, fn, newfp)
363 setattr(self, cn, newfp) 365 setattr(self, cn, newfp)
364 366
367 self._ioattached = True
365 self.cresult.write(struct.pack('>i', len(clientfds))) 368 self.cresult.write(struct.pack('>i', len(clientfds)))
366 369
367 def _saveio(self): 370 def _saveio(self):
368 if self._oldios: 371 if self._oldios:
369 return False 372 return
370 ui = self.ui 373 ui = self.ui
371 for cn, fn, _mode in _iochannels: 374 for cn, fn, _mode in _iochannels:
372 ch = getattr(self, cn) 375 ch = getattr(self, cn)
373 fp = getattr(ui, fn) 376 fp = getattr(ui, fn)
374 fd = os.dup(fp.fileno()) 377 fd = os.dup(fp.fileno())
375 self._oldios.append((ch, fp, fd)) 378 self._oldios.append((ch, fp, fd))
376 return True
377 379
378 def _restoreio(self): 380 def _restoreio(self):
379 ui = self.ui 381 ui = self.ui
380 for (ch, fp, fd), (cn, fn, _mode) in zip(self._oldios, _iochannels): 382 for (ch, fp, fd), (cn, fn, _mode) in zip(self._oldios, _iochannels):
381 newfp = getattr(ui, fn) 383 newfp = getattr(ui, fn)