python3: wrap all uses of <exception>.strerror with strtolocal
authorAugie Fackler <raf@durin42.com>
Tue, 22 Aug 2017 20:03:07 -0400
changeset 39501 d5b2beca16c05f4f60fbd941682d47f053ccb909
parent 39500 31a2eb0f74e59327c0e1b49ee848c126993a29dc
child 39502 ba479850c9c79379743451faa28700afb581ea7a
push id564
push usergszorc@mozilla.com
push dateThu, 31 Aug 2017 22:34:10 +0000
python3: wrap all uses of <exception>.strerror with strtolocal Our string literals are bytes, and we mostly want to %-format a strerror into a one of those literals, so this fixes a ton of issues.
hgext/convert/common.py
hgext/mq.py
mercurial/cmdutil.py
mercurial/dirstate.py
mercurial/dispatch.py
mercurial/hgweb/common.py
mercurial/hgweb/hgwebdir_mod.py
mercurial/scmutil.py
mercurial/subrepo.py
mercurial/vfs.py
mercurial/win32.py
mercurial/windows.py
--- a/hgext/convert/common.py
+++ b/hgext/convert/common.py
@@ -10,16 +10,17 @@ import base64
 import datetime
 import errno
 import os
 import re
 import subprocess
 
 from mercurial.i18n import _
 from mercurial import (
+    encoding,
     error,
     phases,
     util,
 )
 
 pickle = util.pickle
 propertycache = util.propertycache
 
@@ -470,18 +471,19 @@ class mapfile(dict):
             super(mapfile, self).__setitem__(key, value)
         fp.close()
 
     def __setitem__(self, key, value):
         if self.fp is None:
             try:
                 self.fp = open(self.path, 'a')
             except IOError as err:
-                raise error.Abort(_('could not open map file %r: %s') %
-                                 (self.path, err.strerror))
+                raise error.Abort(
+                    _('could not open map file %r: %s') %
+                    (self.path, encoding.strtolocal(err.strerror)))
         self.fp.write('%s %s\n' % (key, value))
         self.fp.flush()
         super(mapfile, self).__setitem__(key, value)
 
     def close(self):
         if self.fp:
             self.fp.close()
             self.fp = None
--- a/hgext/mq.py
+++ b/hgext/mq.py
@@ -75,16 +75,17 @@ from mercurial.node import (
     nullid,
     nullrev,
     short,
 )
 from mercurial import (
     cmdutil,
     commands,
     dirstateguard,
+    encoding,
     error,
     extensions,
     hg,
     localrepo,
     lock as lockmod,
     patch as patchmod,
     phases,
     pycompat,
@@ -1201,17 +1202,17 @@ class queue(object):
         self.checktoppatch(repo)
         insert = self.fullseriesend()
         with repo.wlock():
             try:
                 # if patch file write fails, abort early
                 p = self.opener(patchfn, "w")
             except IOError as e:
                 raise error.Abort(_('cannot write patch "%s": %s')
-                                 % (patchfn, e.strerror))
+                                 % (patchfn, encoding.strtolocal(e.strerror)))
             try:
                 defaultmsg = "[mq]: %s" % patchfn
                 editor = cmdutil.getcommiteditor(editform=editform)
                 if edit:
                     def finishdesc(desc):
                         if desc.rstrip():
                             return desc
                         else:
--- a/mercurial/cmdutil.py
+++ b/mercurial/cmdutil.py
@@ -772,17 +772,17 @@ def logmessage(ui, opts):
     if not message and logfile:
         try:
             if isstdiofilename(logfile):
                 message = ui.fin.read()
             else:
                 message = '\n'.join(util.readfile(logfile).splitlines())
         except IOError as inst:
             raise error.Abort(_("can't read commit message '%s': %s") %
-                             (logfile, inst.strerror))
+                             (logfile, encoding.strtolocal(inst.strerror)))
     return message
 
 def mergeeditform(ctxorbool, baseformname):
     """return appropriate editform name (referencing a committemplate)
 
     'ctxorbool' is either a ctx to be committed, or a bool indicating whether
     merging is committed.
 
@@ -1094,17 +1094,17 @@ def copy(ui, repo, pats, opts, rename=Fa
                     util.copyfile(src, target)
                 srcexists = True
             except IOError as inst:
                 if inst.errno == errno.ENOENT:
                     ui.warn(_('%s: deleted in working directory\n') % relsrc)
                     srcexists = False
                 else:
                     ui.warn(_('%s: cannot copy - %s\n') %
-                            (relsrc, inst.strerror))
+                            (relsrc, encoding.strtolocal(inst.strerror)))
                     return True # report a failure
 
         if ui.verbose or not exact:
             if rename:
                 ui.status(_('moving %s to %s\n') % (relsrc, reltarget))
             else:
                 ui.status(_('copying %s to %s\n') % (relsrc, reltarget))
 
--- a/mercurial/dirstate.py
+++ b/mercurial/dirstate.py
@@ -977,17 +977,17 @@ class dirstate(object):
                 else: # does it match a missing directory?
                     if alldirs is None:
                         alldirs = util.dirs(dmap)
                     if nf in alldirs:
                         if matchedir:
                             matchedir(nf)
                         notfoundadd(nf)
                     else:
-                        badfn(ff, inst.strerror)
+                        badfn(ff, encoding.strtolocal(inst.strerror))
 
         # Case insensitive filesystems cannot rely on lstat() failing to detect
         # a case-only rename.  Prune the stat object for any file that does not
         # match the case in the filesystem, if there are multiple files that
         # normalize to the same path.
         if match.isexact() and self._checkcase:
             normed = {}
 
@@ -1083,17 +1083,18 @@ class dirstate(object):
                 if nd == '.':
                     nd = ''
                 else:
                     skip = '.hg'
                 try:
                     entries = listdir(join(nd), stat=True, skip=skip)
                 except OSError as inst:
                     if inst.errno in (errno.EACCES, errno.ENOENT):
-                        match.bad(self.pathto(nd), inst.strerror)
+                        match.bad(self.pathto(nd),
+                                  encoding.strtolocal(inst.strerror))
                         continue
                     raise
                 for f, kind, st in entries:
                     if normalizefile:
                         # even though f might be a directory, we're only
                         # interested in comparing it to files currently in the
                         # dmap -- therefore normalizefile is enough
                         nf = normalizefile(nd and (nd + "/" + f) or f, True,
--- a/mercurial/dispatch.py
+++ b/mercurial/dispatch.py
@@ -83,17 +83,18 @@ def run():
         status = -1
     if util.safehasattr(req.ui, 'fout'):
         try:
             req.ui.fout.flush()
         except IOError as err:
             status = -1
     if util.safehasattr(req.ui, 'ferr'):
         if err is not None and err.errno != errno.EPIPE:
-            req.ui.ferr.write('abort: %s\n' % err.strerror)
+            req.ui.ferr.write('abort: %s\n' %
+                              encoding.strtolocal(err.strerror))
         req.ui.ferr.flush()
     sys.exit(status & 255)
 
 def _getsimilar(symbols, value):
     sim = lambda x: difflib.SequenceMatcher(None, value, x).ratio()
     # The cutoff for similarity here is pretty arbitrary. It should
     # probably be investigated and tweaked.
     return [s for s in symbols if sim(s) > 0.6]
@@ -671,17 +672,17 @@ def _getlocal(ui, rpath, wd=None):
 
     Takes paths in [cwd]/.hg/hgrc into account."
     """
     if wd is None:
         try:
             wd = pycompat.getcwd()
         except OSError as e:
             raise error.Abort(_("error getting current working directory: %s") %
-                              e.strerror)
+                              encoding.strtolocal(e.strerror))
     path = cmdutil.findrepo(wd) or ""
     if not path:
         lui = ui
     else:
         lui = ui.copy()
         lui.readconfig(os.path.join(path, ".hg", "hgrc"), path)
 
     if rpath and rpath[-1]:
--- a/mercurial/hgweb/common.py
+++ b/mercurial/hgweb/common.py
@@ -173,17 +173,18 @@ def staticfile(directory, fname, req):
 
         req.respond(HTTP_OK, ct, body=data)
     except TypeError:
         raise ErrorResponse(HTTP_SERVER_ERROR, 'illegal filename')
     except OSError as err:
         if err.errno == errno.ENOENT:
             raise ErrorResponse(HTTP_NOT_FOUND)
         else:
-            raise ErrorResponse(HTTP_SERVER_ERROR, err.strerror)
+            raise ErrorResponse(HTTP_SERVER_ERROR,
+                                encoding.strtolocal(err.strerror))
 
 def paritygen(stripecount, offset=0):
     """count parity of horizontal stripes for easier reading"""
     if stripecount and offset:
         # account for offset, e.g. due to building the list in reverse
         count = (stripecount + offset) % stripecount
         parity = (stripecount + offset) / stripecount & 1
     else:
--- a/mercurial/hgweb/hgwebdir_mod.py
+++ b/mercurial/hgweb/hgwebdir_mod.py
@@ -284,17 +284,17 @@ class hgwebdir(object):
                 real = repos.get(virtualrepo)
                 if real:
                     req.env['REPO_NAME'] = virtualrepo
                     try:
                         # ensure caller gets private copy of ui
                         repo = hg.repository(self.ui.copy(), real)
                         return hgweb_mod.hgweb(repo).run_wsgi(req)
                     except IOError as inst:
-                        msg = inst.strerror
+                        msg = encoding.strtolocal(inst.strerror)
                         raise ErrorResponse(HTTP_SERVER_ERROR, msg)
                     except error.RepoError as inst:
                         raise ErrorResponse(HTTP_SERVER_ERROR, str(inst))
 
             # browse subdirectories
             subdir = virtual + '/'
             if [r for r in repos if r.startswith(subdir)]:
                 req.respond(HTTP_OK, ctype)
--- a/mercurial/scmutil.py
+++ b/mercurial/scmutil.py
@@ -158,17 +158,18 @@ def callcatch(ui, func):
             reason = _('timed out waiting for lock held by %r') % inst.locker
         else:
             reason = _('lock held by %r') % inst.locker
         ui.warn(_("abort: %s: %s\n") % (inst.desc or inst.filename, reason))
         if not inst.locker:
             ui.warn(_("(lock might be very busy)\n"))
     except error.LockUnavailable as inst:
         ui.warn(_("abort: could not lock %s: %s\n") %
-               (inst.desc or inst.filename, inst.strerror))
+               (inst.desc or inst.filename,
+                encoding.strtolocal(inst.strerror)))
     except error.OutOfBandError as inst:
         if inst.args:
             msg = _("abort: remote error:\n")
         else:
             msg = _("abort: remote error\n")
         ui.warn(msg)
         if inst.args:
             ui.warn(''.join(inst.args))
@@ -221,26 +222,28 @@ def callcatch(ui, func):
                 # SSLError of Python 2.7.9 contains a unicode
                 reason = encoding.unitolocal(reason)
             ui.warn(_("abort: error: %s\n") % reason)
         elif (util.safehasattr(inst, "args")
               and inst.args and inst.args[0] == errno.EPIPE):
             pass
         elif getattr(inst, "strerror", None):
             if getattr(inst, "filename", None):
-                ui.warn(_("abort: %s: %s\n") % (inst.strerror, inst.filename))
+                ui.warn(_("abort: %s: %s\n") % (
+                    encoding.strtolocal(inst.strerror), inst.filename))
             else:
-                ui.warn(_("abort: %s\n") % inst.strerror)
+                ui.warn(_("abort: %s\n") % encoding.strtolocal(inst.strerror))
         else:
             raise
     except OSError as inst:
         if getattr(inst, "filename", None) is not None:
-            ui.warn(_("abort: %s: '%s'\n") % (inst.strerror, inst.filename))
+            ui.warn(_("abort: %s: '%s'\n") % (
+                encoding.strtolocal(inst.strerror), inst.filename))
         else:
-            ui.warn(_("abort: %s\n") % inst.strerror)
+            ui.warn(_("abort: %s\n") % encoding.strtolocal(inst.strerror))
     except MemoryError:
         ui.warn(_("abort: out of memory\n"))
     except SystemExit as inst:
         # Commands shouldn't sys.exit directly, but give a return code.
         # Just in case catch this and and pass exit code to caller.
         return inst.code
     except socket.error as inst:
         ui.warn(_("abort: %s\n") % inst.args[-1])
--- a/mercurial/subrepo.py
+++ b/mercurial/subrepo.py
@@ -1341,29 +1341,30 @@ class gitsubrepo(abstractsubrepo):
     def _ensuregit(self):
         try:
             self._gitexecutable = 'git'
             out, err = self._gitnodir(['--version'])
         except OSError as e:
             genericerror = _("error executing git for subrepo '%s': %s")
             notfoundhint = _("check git is installed and in your PATH")
             if e.errno != errno.ENOENT:
-                raise error.Abort(genericerror % (self._path, e.strerror))
+                raise error.Abort(genericerror % (
+                    self._path, encoding.strtolocal(e.strerror)))
             elif pycompat.osname == 'nt':
                 try:
                     self._gitexecutable = 'git.cmd'
                     out, err = self._gitnodir(['--version'])
                 except OSError as e2:
                     if e2.errno == errno.ENOENT:
                         raise error.Abort(_("couldn't find 'git' or 'git.cmd'"
                             " for subrepo '%s'") % self._path,
                             hint=notfoundhint)
                     else:
                         raise error.Abort(genericerror % (self._path,
-                            e2.strerror))
+                            encoding.strtolocal(e2.strerror)))
             else:
                 raise error.Abort(_("couldn't find git for subrepo '%s'")
                     % self._path, hint=notfoundhint)
         versionstatus = self._checkversion(out)
         if versionstatus == 'unknown':
             self.ui.warn(_('cannot retrieve git version\n'))
         elif versionstatus == 'abort':
             raise error.Abort(_('git subrepo requires at least 1.6.0 or later'))
--- a/mercurial/vfs.py
+++ b/mercurial/vfs.py
@@ -11,16 +11,17 @@ import errno
 import os
 import shutil
 import stat
 import tempfile
 import threading
 
 from .i18n import _
 from . import (
+    encoding,
     error,
     pathutil,
     pycompat,
     util,
 )
 
 def _avoidambig(path, oldstat):
     """Avoid file stat ambiguity forcibly
@@ -429,17 +430,18 @@ class vfs(abstractvfs):
 
         util.makedirs(os.path.dirname(linkname), self.createmode)
 
         if self._cansymlink:
             try:
                 os.symlink(src, linkname)
             except OSError as err:
                 raise OSError(err.errno, _('could not symlink to %r: %s') %
-                              (src, err.strerror), linkname)
+                              (src, encoding.strtolocal(err.strerror)),
+                              linkname)
         else:
             self.write(dst, src)
 
     def join(self, path, *insidef):
         if path:
             return os.path.join(self.base, path, *insidef)
         else:
             return self.base
--- a/mercurial/win32.py
+++ b/mercurial/win32.py
@@ -281,17 +281,18 @@ except AttributeError:
 
 def _raiseoserror(name):
     # Force the code to a signed int to avoid an 'int too large' error.
     # See https://bugs.python.org/issue28474
     code = _kernel32.GetLastError()
     if code > 0x7fffffff:
         code -= 2**32
     err = ctypes.WinError(code=code)
-    raise OSError(err.errno, '%s: %s' % (name, err.strerror))
+    raise OSError(err.errno, '%s: %s' % (name,
+                                         encoding.strtolocal(err.strerror)))
 
 def _getfileinfo(name):
     fh = _kernel32.CreateFileA(name, 0,
             _FILE_SHARE_READ | _FILE_SHARE_WRITE | _FILE_SHARE_DELETE,
             None, _OPEN_EXISTING, _FILE_FLAG_BACKUP_SEMANTICS, None)
     if fh == _INVALID_HANDLE_VALUE:
         _raiseoserror(name)
     try:
--- a/mercurial/windows.py
+++ b/mercurial/windows.py
@@ -132,17 +132,18 @@ def posixfile(name, mode='r', buffering=
             fp.seek(0, os.SEEK_END)
 
         if '+' in mode:
             return mixedfilemodewrapper(fp)
 
         return fp
     except WindowsError as err:
         # convert to a friendlier exception
-        raise IOError(err.errno, '%s: %s' % (name, err.strerror))
+        raise IOError(err.errno, '%s: %s' % (
+            name, encoding.strtolocal(err.strerror)))
 
 # may be wrapped by win32mbcs extension
 listdir = osutil.listdir
 
 class winstdout(object):
     '''stdout on windows misbehaves if sent through a pipe'''
 
     def __init__(self, fp):