mercurial/sshpeer.py
changeset 46662 db8037e38085
parent 46660 0738bc25d6ac
child 46663 a4c19a162615
equal deleted inserted replaced
46661:0509cee38757 46662:db8037e38085
   146 
   146 
   147     def flush(self):
   147     def flush(self):
   148         return self._main.flush()
   148         return self._main.flush()
   149 
   149 
   150 
   150 
   151 def _cleanuppipes(ui, pipei, pipeo, pipee):
   151 def _cleanuppipes(ui, pipei, pipeo, pipee, warn):
   152     """Clean up pipes used by an SSH connection."""
   152     """Clean up pipes used by an SSH connection."""
   153     if pipeo:
   153     didsomething = False
       
   154     if pipeo and not pipeo.closed:
       
   155         didsomething = True
   154         pipeo.close()
   156         pipeo.close()
   155     if pipei:
   157     if pipei and not pipei.closed:
       
   158         didsomething = True
   156         pipei.close()
   159         pipei.close()
   157 
   160 
   158     if pipee:
   161     if pipee and not pipee.closed:
       
   162         didsomething = True
   159         # Try to read from the err descriptor until EOF.
   163         # Try to read from the err descriptor until EOF.
   160         try:
   164         try:
   161             for l in pipee:
   165             for l in pipee:
   162                 ui.status(_(b'remote: '), l)
   166                 ui.status(_(b'remote: '), l)
   163         except (IOError, ValueError):
   167         except (IOError, ValueError):
   164             pass
   168             pass
   165 
   169 
   166         pipee.close()
   170         pipee.close()
       
   171 
       
   172     if didsomething and warn is not None:
       
   173         # Encourage explicit close of sshpeers. Closing via __del__ is
       
   174         # not very predictable when exceptions are thrown, which has led
       
   175         # to deadlocks due to a peer get gc'ed in a fork
       
   176         # We add our own stack trace, because the stacktrace when called
       
   177         # from __del__ is useless.
       
   178         if False:  # enabled in next commit
       
   179             ui.develwarn(
       
   180                 b'missing close on SSH connection created at:\n%s' % warn
       
   181             )
   167 
   182 
   168 
   183 
   169 def _makeconnection(ui, sshcmd, args, remotecmd, path, sshenv=None):
   184 def _makeconnection(ui, sshcmd, args, remotecmd, path, sshenv=None):
   170     """Create an SSH connection to a server.
   185     """Create an SSH connection to a server.
   171 
   186 
   414         self._pipeo = stdin
   429         self._pipeo = stdin
   415         self._pipei = stdout
   430         self._pipei = stdout
   416         self._pipee = stderr
   431         self._pipee = stderr
   417         self._caps = caps
   432         self._caps = caps
   418         self._autoreadstderr = autoreadstderr
   433         self._autoreadstderr = autoreadstderr
       
   434         self._initstack = b''.join(util.getstackframes(1))
   419 
   435 
   420     # Commands that have a "framed" response where the first line of the
   436     # Commands that have a "framed" response where the first line of the
   421     # response contains the length of that response.
   437     # response contains the length of that response.
   422     _FRAMED_COMMANDS = {
   438     _FRAMED_COMMANDS = {
   423         b'batch',
   439         b'batch',
   454 
   470 
   455     def _abort(self, exception):
   471     def _abort(self, exception):
   456         self._cleanup()
   472         self._cleanup()
   457         raise exception
   473         raise exception
   458 
   474 
   459     def _cleanup(self):
   475     def _cleanup(self, warn=None):
   460         _cleanuppipes(self.ui, self._pipei, self._pipeo, self._pipee)
   476         _cleanuppipes(self.ui, self._pipei, self._pipeo, self._pipee, warn=warn)
   461 
   477 
   462     __del__ = _cleanup
   478     def __del__(self):
       
   479         self._cleanup(warn=self._initstack)
   463 
   480 
   464     def _sendrequest(self, cmd, args, framed=False):
   481     def _sendrequest(self, cmd, args, framed=False):
   465         if self.ui.debugflag and self.ui.configbool(
   482         if self.ui.debugflag and self.ui.configbool(
   466             b'devel', b'debug.peer-request'
   483             b'devel', b'debug.peer-request'
   467         ):
   484         ):
   609     testing.
   626     testing.
   610     """
   627     """
   611     try:
   628     try:
   612         protoname, caps = _performhandshake(ui, stdin, stdout, stderr)
   629         protoname, caps = _performhandshake(ui, stdin, stdout, stderr)
   613     except Exception:
   630     except Exception:
   614         _cleanuppipes(ui, stdout, stdin, stderr)
   631         _cleanuppipes(ui, stdout, stdin, stderr, warn=None)
   615         raise
   632         raise
   616 
   633 
   617     if protoname == wireprototypes.SSHV1:
   634     if protoname == wireprototypes.SSHV1:
   618         return sshv1peer(
   635         return sshv1peer(
   619             ui,
   636             ui,
   635             stderr,
   652             stderr,
   636             caps,
   653             caps,
   637             autoreadstderr=autoreadstderr,
   654             autoreadstderr=autoreadstderr,
   638         )
   655         )
   639     else:
   656     else:
   640         _cleanuppipes(ui, stdout, stdin, stderr)
   657         _cleanuppipes(ui, stdout, stdin, stderr, warn=None)
   641         raise error.RepoError(
   658         raise error.RepoError(
   642             _(b'unknown version of SSH protocol: %s') % protoname
   659             _(b'unknown version of SSH protocol: %s') % protoname
   643         )
   660         )
   644 
   661 
   645 
   662