mercurial/sshpeer.py
changeset 35938 80a2b8ae42a1
parent 35937 a9cffd14aa04
child 35939 a622a927fe03
equal deleted inserted replaced
35937:a9cffd14aa04 35938:80a2b8ae42a1
   154     stdout = doublepipe(ui, util.bufferedinputpipe(stdout), stderr)
   154     stdout = doublepipe(ui, util.bufferedinputpipe(stdout), stderr)
   155     stdin = doublepipe(ui, stdin, stderr)
   155     stdin = doublepipe(ui, stdin, stderr)
   156 
   156 
   157     return proc, stdin, stdout, stderr
   157     return proc, stdin, stdout, stderr
   158 
   158 
       
   159 def _performhandshake(ui, stdin, stdout, stderr):
       
   160     def badresponse():
       
   161         msg = _('no suitable response from remote hg')
       
   162         hint = ui.config('ui', 'ssherrorhint')
       
   163         raise error.RepoError(msg, hint=hint)
       
   164 
       
   165     requestlog = ui.configbool('devel', 'debug.peer-request')
       
   166 
       
   167     try:
       
   168         pairsarg = '%s-%s' % ('0' * 40, '0' * 40)
       
   169         handshake = [
       
   170             'hello\n',
       
   171             'between\n',
       
   172             'pairs %d\n' % len(pairsarg),
       
   173             pairsarg,
       
   174         ]
       
   175 
       
   176         if requestlog:
       
   177             ui.debug('devel-peer-request: hello\n')
       
   178         ui.debug('sending hello command\n')
       
   179         if requestlog:
       
   180             ui.debug('devel-peer-request: between\n')
       
   181             ui.debug('devel-peer-request:   pairs: %d bytes\n' % len(pairsarg))
       
   182         ui.debug('sending between command\n')
       
   183 
       
   184         stdin.write(''.join(handshake))
       
   185         stdin.flush()
       
   186     except IOError:
       
   187         badresponse()
       
   188 
       
   189     lines = ['', 'dummy']
       
   190     max_noise = 500
       
   191     while lines[-1] and max_noise:
       
   192         try:
       
   193             l = stdout.readline()
       
   194             _forwardoutput(ui, stderr)
       
   195             if lines[-1] == '1\n' and l == '\n':
       
   196                 break
       
   197             if l:
       
   198                 ui.debug('remote: ', l)
       
   199             lines.append(l)
       
   200             max_noise -= 1
       
   201         except IOError:
       
   202             badresponse()
       
   203     else:
       
   204         badresponse()
       
   205 
       
   206     caps = set()
       
   207     for l in reversed(lines):
       
   208         if l.startswith('capabilities:'):
       
   209             caps.update(l[:-1].split(':')[1].split())
       
   210             break
       
   211 
       
   212     return caps
       
   213 
   159 class sshpeer(wireproto.wirepeer):
   214 class sshpeer(wireproto.wirepeer):
   160     def __init__(self, ui, url, proc, stdin, stdout, stderr):
   215     def __init__(self, ui, url, proc, stdin, stdout, stderr, caps):
   161         """Create a peer from an existing SSH connection.
   216         """Create a peer from an existing SSH connection.
   162 
   217 
   163         ``proc`` is a handle on the underlying SSH process.
   218         ``proc`` is a handle on the underlying SSH process.
   164         ``stdin``, ``stdout``, and ``stderr`` are handles on the stdio
   219         ``stdin``, ``stdout``, and ``stderr`` are handles on the stdio
   165         pipes for that process.
   220         pipes for that process.
       
   221         ``caps`` is a set of capabilities supported by the remote.
   166         """
   222         """
   167         self._url = url
   223         self._url = url
   168         self._ui = ui
   224         self._ui = ui
   169         # self._subprocess is unused. Keeping a handle on the process
   225         # self._subprocess is unused. Keeping a handle on the process
   170         # holds a reference and prevents it from being garbage collected.
   226         # holds a reference and prevents it from being garbage collected.
   171         self._subprocess = proc
   227         self._subprocess = proc
   172         self._pipeo = stdin
   228         self._pipeo = stdin
   173         self._pipei = stdout
   229         self._pipei = stdout
   174         self._pipee = stderr
   230         self._pipee = stderr
   175 
   231         self._caps = caps
   176         self._validaterepo()
       
   177 
   232 
   178     # Begin of _basepeer interface.
   233     # Begin of _basepeer interface.
   179 
   234 
   180     @util.propertycache
   235     @util.propertycache
   181     def ui(self):
   236     def ui(self):
   202 
   257 
   203     def capabilities(self):
   258     def capabilities(self):
   204         return self._caps
   259         return self._caps
   205 
   260 
   206     # End of _basewirecommands interface.
   261     # End of _basewirecommands interface.
   207 
       
   208     def _validaterepo(self):
       
   209         def badresponse():
       
   210             msg = _("no suitable response from remote hg")
       
   211             hint = self.ui.config("ui", "ssherrorhint")
       
   212             self._abort(error.RepoError(msg, hint=hint))
       
   213 
       
   214         try:
       
   215             pairsarg = '%s-%s' % ('0' * 40, '0' * 40)
       
   216 
       
   217             handshake = [
       
   218                 'hello\n',
       
   219                 'between\n',
       
   220                 'pairs %d\n' % len(pairsarg),
       
   221                 pairsarg,
       
   222             ]
       
   223 
       
   224             requestlog = self.ui.configbool('devel', 'debug.peer-request')
       
   225 
       
   226             if requestlog:
       
   227                 self.ui.debug('devel-peer-request: hello\n')
       
   228             self.ui.debug('sending hello command\n')
       
   229             if requestlog:
       
   230                 self.ui.debug('devel-peer-request: between\n')
       
   231                 self.ui.debug('devel-peer-request:   pairs: %d bytes\n' %
       
   232                               len(pairsarg))
       
   233             self.ui.debug('sending between command\n')
       
   234 
       
   235             self._pipeo.write(''.join(handshake))
       
   236             self._pipeo.flush()
       
   237         except IOError:
       
   238             badresponse()
       
   239 
       
   240         lines = ["", "dummy"]
       
   241         max_noise = 500
       
   242         while lines[-1] and max_noise:
       
   243             try:
       
   244                 l = self._pipei.readline()
       
   245                 _forwardoutput(self.ui, self._pipee)
       
   246                 if lines[-1] == "1\n" and l == "\n":
       
   247                     break
       
   248                 if l:
       
   249                     self.ui.debug("remote: ", l)
       
   250                 lines.append(l)
       
   251                 max_noise -= 1
       
   252             except IOError:
       
   253                 badresponse()
       
   254         else:
       
   255             badresponse()
       
   256 
       
   257         self._caps = set()
       
   258         for l in reversed(lines):
       
   259             if l.startswith("capabilities:"):
       
   260                 self._caps.update(l[:-1].split(":")[1].split())
       
   261                 break
       
   262 
   262 
   263     def _readerr(self):
   263     def _readerr(self):
   264         _forwardoutput(self.ui, self._pipee)
   264         _forwardoutput(self.ui, self._pipee)
   265 
   265 
   266     def _abort(self, exception):
   266     def _abort(self, exception):
   412             raise error.RepoError(_('could not create remote repo'))
   412             raise error.RepoError(_('could not create remote repo'))
   413 
   413 
   414     proc, stdin, stdout, stderr = _makeconnection(ui, sshcmd, args, remotecmd,
   414     proc, stdin, stdout, stderr = _makeconnection(ui, sshcmd, args, remotecmd,
   415                                                   remotepath, sshenv)
   415                                                   remotepath, sshenv)
   416 
   416 
   417     return sshpeer(ui, path, proc, stdin, stdout, stderr)
   417     try:
       
   418         caps = _performhandshake(ui, stdin, stdout, stderr)
       
   419     except Exception:
       
   420         _cleanuppipes(ui, stdout, stdin, stderr)
       
   421         raise
       
   422 
       
   423     return sshpeer(ui, path, proc, stdin, stdout, stderr, caps)