Mercurial > public > mercurial-scm > hg-stable
comparison mercurial/sshpeer.py @ 35975:00b9e26d727b
sshpeer: establish SSH connection before class instantiation
We want to move the handshake to before peers are created so
we can instantiate a different peer class depending on the
results of the handshake. This necessitates moving the SSH
process invocation to outside the peer class.
As part of the code move, some variables were renamed for
clarity. util.popen4() returns stdin, stdout, and stderr in
their typical file descriptor order. However, stdin and stdout
were being mapped to "pipeo" and "pipei" respectively. "o"
for "stdin" and "i" for "stdout" is a bit confusing. Although
it does make sense for "output" and "input" from the perspective
of the client. But in the context of the new function, it makes
sense to refer to these as their file descriptor names.
In addition, the last use of self._path disappeared, so we stop
setting that attribute and we can delete the redundant URL
parsing necessary to set it.
Differential Revision: https://phab.mercurial-scm.org/D2031
author | Gregory Szorc <gregory.szorc@gmail.com> |
---|---|
date | Mon, 05 Feb 2018 14:05:59 -0800 |
parents | 94ba29934f00 |
children | f8f034344b39 |
comparison
equal
deleted
inserted
replaced
35974:94ba29934f00 | 35975:00b9e26d727b |
---|---|
129 except (IOError, ValueError): | 129 except (IOError, ValueError): |
130 pass | 130 pass |
131 | 131 |
132 pipee.close() | 132 pipee.close() |
133 | 133 |
134 def _makeconnection(ui, sshcmd, args, remotecmd, path, sshenv=None): | |
135 """Create an SSH connection to a server. | |
136 | |
137 Returns a tuple of (process, stdin, stdout, stderr) for the | |
138 spawned process. | |
139 """ | |
140 cmd = '%s %s %s' % ( | |
141 sshcmd, | |
142 args, | |
143 util.shellquote('%s -R %s serve --stdio' % ( | |
144 _serverquote(remotecmd), _serverquote(path)))) | |
145 | |
146 ui.debug('running %s\n' % cmd) | |
147 cmd = util.quotecommand(cmd) | |
148 | |
149 # no buffer allow the use of 'select' | |
150 # feel free to remove buffering and select usage when we ultimately | |
151 # move to threading. | |
152 stdin, stdout, stderr, proc = util.popen4(cmd, bufsize=0, env=sshenv) | |
153 | |
154 stdout = doublepipe(ui, util.bufferedinputpipe(stdout), stderr) | |
155 stdin = doublepipe(ui, stdin, stderr) | |
156 | |
157 return proc, stdin, stdout, stderr | |
158 | |
134 class sshpeer(wireproto.wirepeer): | 159 class sshpeer(wireproto.wirepeer): |
135 def __init__(self, ui, path, create=False, sshstate=None): | 160 def __init__(self, ui, path, create=False, sshstate=None): |
136 self._url = path | 161 self._url = path |
137 self._ui = ui | 162 self._ui = ui |
138 self._pipeo = self._pipei = self._pipee = None | 163 # self._subprocess is unused. Keeping a handle on the process |
139 | 164 # holds a reference and prevents it from being garbage collected. |
140 u = util.url(path, parsequery=False, parsefragment=False) | 165 self._subprocess, self._pipei, self._pipeo, self._pipee = sshstate |
141 self._path = u.path or '.' | 166 |
142 | 167 self._validaterepo() |
143 self._validaterepo(*sshstate) | |
144 | 168 |
145 # Begin of _basepeer interface. | 169 # Begin of _basepeer interface. |
146 | 170 |
147 @util.propertycache | 171 @util.propertycache |
148 def ui(self): | 172 def ui(self): |
170 def capabilities(self): | 194 def capabilities(self): |
171 return self._caps | 195 return self._caps |
172 | 196 |
173 # End of _basewirecommands interface. | 197 # End of _basewirecommands interface. |
174 | 198 |
175 def _validaterepo(self, sshcmd, args, remotecmd, sshenv=None): | 199 def _validaterepo(self): |
176 assert self._pipei is None | |
177 | |
178 cmd = '%s %s %s' % (sshcmd, args, | |
179 util.shellquote("%s -R %s serve --stdio" % | |
180 (_serverquote(remotecmd), _serverquote(self._path)))) | |
181 self.ui.debug('running %s\n' % cmd) | |
182 cmd = util.quotecommand(cmd) | |
183 | |
184 # while self._subprocess isn't used, having it allows the subprocess to | |
185 # to clean up correctly later | |
186 # | |
187 # no buffer allow the use of 'select' | |
188 # feel free to remove buffering and select usage when we ultimately | |
189 # move to threading. | |
190 sub = util.popen4(cmd, bufsize=0, env=sshenv) | |
191 self._pipeo, self._pipei, self._pipee, self._subprocess = sub | |
192 | |
193 self._pipei = util.bufferedinputpipe(self._pipei) | |
194 self._pipei = doublepipe(self.ui, self._pipei, self._pipee) | |
195 self._pipeo = doublepipe(self.ui, self._pipeo, self._pipee) | |
196 | |
197 def badresponse(): | 200 def badresponse(): |
198 msg = _("no suitable response from remote hg") | 201 msg = _("no suitable response from remote hg") |
199 hint = self.ui.config("ui", "ssherrorhint") | 202 hint = self.ui.config("ui", "ssherrorhint") |
200 self._abort(error.RepoError(msg, hint=hint)) | 203 self._abort(error.RepoError(msg, hint=hint)) |
201 | 204 |
378 ui.debug('running %s\n' % cmd) | 381 ui.debug('running %s\n' % cmd) |
379 res = ui.system(cmd, blockedtag='sshpeer', environ=sshenv) | 382 res = ui.system(cmd, blockedtag='sshpeer', environ=sshenv) |
380 if res != 0: | 383 if res != 0: |
381 raise error.RepoError(_('could not create remote repo')) | 384 raise error.RepoError(_('could not create remote repo')) |
382 | 385 |
383 sshstate = (sshcmd, args, remotecmd, sshenv) | 386 proc, stdin, stdout, stderr = _makeconnection(ui, sshcmd, args, remotecmd, |
387 remotepath, sshenv) | |
388 | |
389 sshstate = (proc, stdout, stdin, stderr) | |
384 | 390 |
385 return sshpeer(ui, path, create=create, sshstate=sshstate) | 391 return sshpeer(ui, path, create=create, sshstate=sshstate) |