mercurial/sshpeer.py
changeset 43077 687b865b95ad
parent 43076 2372284d9457
child 43089 c59eb1560c44
--- a/mercurial/sshpeer.py	Sun Oct 06 09:45:02 2019 -0400
+++ b/mercurial/sshpeer.py	Sun Oct 06 09:48:39 2019 -0400
@@ -30,9 +30,9 @@
     """quote a string for the remote shell ... which we assume is sh"""
     if not s:
         return s
-    if re.match('[a-zA-Z0-9@%_+=:,./-]*$', s):
+    if re.match(b'[a-zA-Z0-9@%_+=:,./-]*$', s):
         return s
-    return "'%s'" % s.replace("'", "'\\''")
+    return b"'%s'" % s.replace(b"'", b"'\\''")
 
 
 def _forwardoutput(ui, pipe):
@@ -43,7 +43,7 @@
         s = procutil.readpipe(pipe)
         if s:
             for l in s.splitlines():
-                ui.status(_("remote: "), l, '\n')
+                ui.status(_(b"remote: "), l, b'\n')
 
 
 class doublepipe(object):
@@ -91,10 +91,10 @@
         return (self._main.fileno() in act, self._side.fileno() in act)
 
     def write(self, data):
-        return self._call('write', data)
+        return self._call(b'write', data)
 
     def read(self, size):
-        r = self._call('read', size)
+        r = self._call(b'read', size)
         if size != 0 and not r:
             # We've observed a condition that indicates the
             # stdout closed unexpectedly. Check stderr one
@@ -105,7 +105,7 @@
         return r
 
     def unbufferedread(self, size):
-        r = self._call('unbufferedread', size)
+        r = self._call(b'unbufferedread', size)
         if size != 0 and not r:
             # We've observed a condition that indicates the
             # stdout closed unexpectedly. Check stderr one
@@ -116,7 +116,7 @@
         return r
 
     def readline(self):
-        return self._call('readline')
+        return self._call(b'readline')
 
     def _call(self, methname, data=None):
         """call <methname> on "main", forward output of "side" while blocking
@@ -124,7 +124,7 @@
         # data can be '' or 0
         if (data is not None and not data) or self._main.closed:
             _forwardoutput(self._ui, self._side)
-            return ''
+            return b''
         while True:
             mainready, sideready = self._wait()
             if sideready:
@@ -154,7 +154,7 @@
         # Try to read from the err descriptor until EOF.
         try:
             for l in pipee:
-                ui.status(_('remote: '), l)
+                ui.status(_(b'remote: '), l)
         except (IOError, ValueError):
             pass
 
@@ -167,16 +167,16 @@
     Returns a tuple of (process, stdin, stdout, stderr) for the
     spawned process.
     """
-    cmd = '%s %s %s' % (
+    cmd = b'%s %s %s' % (
         sshcmd,
         args,
         procutil.shellquote(
-            '%s -R %s serve --stdio'
+            b'%s -R %s serve --stdio'
             % (_serverquote(remotecmd), _serverquote(path))
         ),
     )
 
-    ui.debug('running %s\n' % cmd)
+    ui.debug(b'running %s\n' % cmd)
     cmd = procutil.quotecommand(cmd)
 
     # no buffer allow the use of 'select'
@@ -192,12 +192,12 @@
 
     Returns a list of capabilities that are supported by this client.
     """
-    protoparams = {'partial-pull'}
+    protoparams = {b'partial-pull'}
     comps = [
         e.wireprotosupport().name
         for e in util.compengines.supportedwireengines(util.CLIENTROLE)
     ]
-    protoparams.add('comp=%s' % ','.join(comps))
+    protoparams.add(b'comp=%s' % b','.join(comps))
     return protoparams
 
 
@@ -206,8 +206,8 @@
         # Flush any output on stderr.
         _forwardoutput(ui, stderr)
 
-        msg = _('no suitable response from remote hg')
-        hint = ui.config('ui', 'ssherrorhint')
+        msg = _(b'no suitable response from remote hg')
+        hint = ui.config(b'ui', b'ssherrorhint')
         raise error.RepoError(msg, hint=hint)
 
     # The handshake consists of sending wire protocol commands in reverse
@@ -262,37 +262,37 @@
     # for output to our well-known ``between`` command. Of course, if
     # the banner contains ``1\n\n``, this will throw off our detection.
 
-    requestlog = ui.configbool('devel', 'debug.peer-request')
+    requestlog = ui.configbool(b'devel', b'debug.peer-request')
 
     # Generate a random token to help identify responses to version 2
     # upgrade request.
     token = pycompat.sysbytes(str(uuid.uuid4()))
     upgradecaps = [
-        ('proto', wireprotoserver.SSHV2),
+        (b'proto', wireprotoserver.SSHV2),
     ]
     upgradecaps = util.urlreq.urlencode(upgradecaps)
 
     try:
-        pairsarg = '%s-%s' % ('0' * 40, '0' * 40)
+        pairsarg = b'%s-%s' % (b'0' * 40, b'0' * 40)
         handshake = [
-            'hello\n',
-            'between\n',
-            'pairs %d\n' % len(pairsarg),
+            b'hello\n',
+            b'between\n',
+            b'pairs %d\n' % len(pairsarg),
             pairsarg,
         ]
 
         # Request upgrade to version 2 if configured.
-        if ui.configbool('experimental', 'sshpeer.advertise-v2'):
-            ui.debug('sending upgrade request: %s %s\n' % (token, upgradecaps))
-            handshake.insert(0, 'upgrade %s %s\n' % (token, upgradecaps))
+        if ui.configbool(b'experimental', b'sshpeer.advertise-v2'):
+            ui.debug(b'sending upgrade request: %s %s\n' % (token, upgradecaps))
+            handshake.insert(0, b'upgrade %s %s\n' % (token, upgradecaps))
 
         if requestlog:
-            ui.debug('devel-peer-request: hello+between\n')
-            ui.debug('devel-peer-request:   pairs: %d bytes\n' % len(pairsarg))
-        ui.debug('sending hello command\n')
-        ui.debug('sending between command\n')
+            ui.debug(b'devel-peer-request: hello+between\n')
+            ui.debug(b'devel-peer-request:   pairs: %d bytes\n' % len(pairsarg))
+        ui.debug(b'sending hello command\n')
+        ui.debug(b'sending between command\n')
 
-        stdin.write(''.join(handshake))
+        stdin.write(b''.join(handshake))
         stdin.flush()
     except IOError:
         badresponse()
@@ -301,7 +301,7 @@
     protoname = wireprototypes.SSHV1
     reupgraded = re.compile(b'^upgraded %s (.*)$' % stringutil.reescape(token))
 
-    lines = ['', 'dummy']
+    lines = [b'', b'dummy']
     max_noise = 500
     while lines[-1] and max_noise:
         try:
@@ -313,7 +313,7 @@
             m = reupgraded.match(l)
             if m:
                 protoname = m.group(1)
-                ui.debug('protocol upgraded to %s\n' % protoname)
+                ui.debug(b'protocol upgraded to %s\n' % protoname)
                 # If an upgrade was handled, the ``hello`` and ``between``
                 # requests are ignored. The next output belongs to the
                 # protocol, so stop scanning lines.
@@ -322,10 +322,10 @@
             # Otherwise it could be a banner, ``0\n`` response if server
             # doesn't support upgrade.
 
-            if lines[-1] == '1\n' and l == '\n':
+            if lines[-1] == b'1\n' and l == b'\n':
                 break
             if l:
-                ui.debug('remote: ', l)
+                ui.debug(b'remote: ', l)
             lines.append(l)
             max_noise -= 1
         except IOError:
@@ -341,8 +341,8 @@
         for l in reversed(lines):
             # Look for response to ``hello`` command. Scan from the back so
             # we don't misinterpret banner output as the command reply.
-            if l.startswith('capabilities:'):
-                caps.update(l[:-1].split(':')[1].split())
+            if l.startswith(b'capabilities:'):
+                caps.update(l[:-1].split(b':')[1].split())
                 break
     elif protoname == wireprotoserver.SSHV2:
         # We see a line with number of bytes to follow and then a value
@@ -354,12 +354,12 @@
             badresponse()
 
         capsline = stdout.read(valuelen)
-        if not capsline.startswith('capabilities: '):
+        if not capsline.startswith(b'capabilities: '):
             badresponse()
 
-        ui.debug('remote: %s\n' % capsline)
+        ui.debug(b'remote: %s\n' % capsline)
 
-        caps.update(capsline.split(':')[1].split())
+        caps.update(capsline.split(b':')[1].split())
         # Trailing newline.
         stdout.read(1)
 
@@ -412,7 +412,7 @@
     # Commands that have a "framed" response where the first line of the
     # response contains the length of that response.
     _FRAMED_COMMANDS = {
-        'batch',
+        b'batch',
     }
 
     # Begin of ipeerconnection interface.
@@ -455,34 +455,34 @@
 
     def _sendrequest(self, cmd, args, framed=False):
         if self.ui.debugflag and self.ui.configbool(
-            'devel', 'debug.peer-request'
+            b'devel', b'debug.peer-request'
         ):
             dbg = self.ui.debug
-            line = 'devel-peer-request: %s\n'
+            line = b'devel-peer-request: %s\n'
             dbg(line % cmd)
             for key, value in sorted(args.items()):
                 if not isinstance(value, dict):
-                    dbg(line % '  %s: %d bytes' % (key, len(value)))
+                    dbg(line % b'  %s: %d bytes' % (key, len(value)))
                 else:
                     for dk, dv in sorted(value.items()):
-                        dbg(line % '  %s-%s: %d' % (key, dk, len(dv)))
-        self.ui.debug("sending %s command\n" % cmd)
-        self._pipeo.write("%s\n" % cmd)
+                        dbg(line % b'  %s-%s: %d' % (key, dk, len(dv)))
+        self.ui.debug(b"sending %s command\n" % cmd)
+        self._pipeo.write(b"%s\n" % cmd)
         _func, names = wireprotov1server.commands[cmd]
         keys = names.split()
         wireargs = {}
         for k in keys:
-            if k == '*':
-                wireargs['*'] = args
+            if k == b'*':
+                wireargs[b'*'] = args
                 break
             else:
                 wireargs[k] = args[k]
                 del args[k]
         for k, v in sorted(wireargs.iteritems()):
-            self._pipeo.write("%s %d\n" % (k, len(v)))
+            self._pipeo.write(b"%s %d\n" % (k, len(v)))
             if isinstance(v, dict):
                 for dk, dv in v.iteritems():
-                    self._pipeo.write("%s %d\n" % (dk, len(dv)))
+                    self._pipeo.write(b"%s %d\n" % (dk, len(dv)))
                     self._pipeo.write(dv)
             else:
                 self._pipeo.write(v)
@@ -515,21 +515,21 @@
         # continue submitting the payload.
         r = self._call(cmd, **args)
         if r:
-            return '', r
+            return b'', r
 
         # The payload consists of frames with content followed by an empty
         # frame.
-        for d in iter(lambda: fp.read(4096), ''):
+        for d in iter(lambda: fp.read(4096), b''):
             self._writeframed(d)
-        self._writeframed("", flush=True)
+        self._writeframed(b"", flush=True)
 
         # In case of success, there is an empty frame and a frame containing
         # the integer result (as a string).
         # In case of error, there is a non-empty frame containing the error.
         r = self._readframed()
         if r:
-            return '', r
-        return self._readframed(), ''
+            return b'', r
+        return self._readframed(), b''
 
     def _calltwowaystream(self, cmd, fp, **args):
         # The server responds with an empty frame if the client should
@@ -537,29 +537,29 @@
         r = self._call(cmd, **args)
         if r:
             # XXX needs to be made better
-            raise error.Abort(_('unexpected remote reply: %s') % r)
+            raise error.Abort(_(b'unexpected remote reply: %s') % r)
 
         # The payload consists of frames with content followed by an empty
         # frame.
-        for d in iter(lambda: fp.read(4096), ''):
+        for d in iter(lambda: fp.read(4096), b''):
             self._writeframed(d)
-        self._writeframed("", flush=True)
+        self._writeframed(b"", flush=True)
 
         return self._pipei
 
     def _getamount(self):
         l = self._pipei.readline()
-        if l == '\n':
+        if l == b'\n':
             if self._autoreadstderr:
                 self._readerr()
-            msg = _('check previous remote output')
+            msg = _(b'check previous remote output')
             self._abort(error.OutOfBandError(hint=msg))
         if self._autoreadstderr:
             self._readerr()
         try:
             return int(l)
         except ValueError:
-            self._abort(error.ResponseError(_("unexpected response:"), l))
+            self._abort(error.ResponseError(_(b"unexpected response:"), l))
 
     def _readframed(self):
         size = self._getamount()
@@ -569,7 +569,7 @@
         return self._pipei.read(size)
 
     def _writeframed(self, data, flush=False):
-        self._pipeo.write("%d\n" % len(data))
+        self._pipeo.write(b"%d\n" % len(data))
         if data:
             self._pipeo.write(data)
         if flush:
@@ -631,7 +631,7 @@
     else:
         _cleanuppipes(ui, stdout, stdin, stderr)
         raise error.RepoError(
-            _('unknown version of SSH protocol: %s') % protoname
+            _(b'unknown version of SSH protocol: %s') % protoname
         )
 
 
@@ -641,19 +641,19 @@
     The returned object conforms to the ``wireprotov1peer.wirepeer`` interface.
     """
     u = util.url(path, parsequery=False, parsefragment=False)
-    if u.scheme != 'ssh' or not u.host or u.path is None:
-        raise error.RepoError(_("couldn't parse location %s") % path)
+    if u.scheme != b'ssh' or not u.host or u.path is None:
+        raise error.RepoError(_(b"couldn't parse location %s") % path)
 
     util.checksafessh(path)
 
     if u.passwd is not None:
-        raise error.RepoError(_('password in URL not supported'))
+        raise error.RepoError(_(b'password in URL not supported'))
 
-    sshcmd = ui.config('ui', 'ssh')
-    remotecmd = ui.config('ui', 'remotecmd')
-    sshaddenv = dict(ui.configitems('sshenv'))
+    sshcmd = ui.config(b'ui', b'ssh')
+    remotecmd = ui.config(b'ui', b'remotecmd')
+    sshaddenv = dict(ui.configitems(b'sshenv'))
     sshenv = procutil.shellenviron(sshaddenv)
-    remotepath = u.path or '.'
+    remotepath = u.path or b'.'
 
     args = procutil.sshargs(sshcmd, u.host, u.user, u.port)
 
@@ -664,21 +664,24 @@
         # supports said requested feature.
         if createopts:
             raise error.RepoError(
-                _('cannot create remote SSH repositories ' 'with extra options')
+                _(
+                    b'cannot create remote SSH repositories '
+                    b'with extra options'
+                )
             )
 
-        cmd = '%s %s %s' % (
+        cmd = b'%s %s %s' % (
             sshcmd,
             args,
             procutil.shellquote(
-                '%s init %s'
+                b'%s init %s'
                 % (_serverquote(remotecmd), _serverquote(remotepath))
             ),
         )
-        ui.debug('running %s\n' % cmd)
-        res = ui.system(cmd, blockedtag='sshpeer', environ=sshenv)
+        ui.debug(b'running %s\n' % cmd)
+        res = ui.system(cmd, blockedtag=b'sshpeer', environ=sshenv)
         if res != 0:
-            raise error.RepoError(_('could not create remote repo'))
+            raise error.RepoError(_(b'could not create remote repo'))
 
     proc, stdin, stdout, stderr = _makeconnection(
         ui, sshcmd, args, remotecmd, remotepath, sshenv
@@ -688,13 +691,13 @@
 
     # Finally, if supported by the server, notify it about our own
     # capabilities.
-    if 'protocaps' in peer.capabilities():
+    if b'protocaps' in peer.capabilities():
         try:
             peer._call(
-                "protocaps", caps=' '.join(sorted(_clientcapabilities()))
+                b"protocaps", caps=b' '.join(sorted(_clientcapabilities()))
             )
         except IOError:
             peer._cleanup()
-            raise error.RepoError(_('capability exchange failed'))
+            raise error.RepoError(_(b'capability exchange failed'))
 
     return peer