diff --git a/mercurial/encoding.py b/mercurial/encoding.py --- a/mercurial/encoding.py +++ b/mercurial/encoding.py @@ -284,13 +284,73 @@ strmethod = pycompat.identity + +def lower(s): + # type: (bytes) -> bytes + """best-effort encoding-aware case-folding of local string s""" + try: + return asciilower(s) + except UnicodeDecodeError: + pass + try: + if isinstance(s, localstr): + u = s._utf8.decode("utf-8") + else: + u = s.decode(_sysstr(encoding), _sysstr(encodingmode)) + + lu = u.lower() + if u == lu: + return s # preserve localstring + return lu.encode(_sysstr(encoding)) + except UnicodeError: + return s.lower() # we don't know how to fold this except in ASCII + except LookupError as k: + raise error.Abort(k, hint=b"please check your locale settings") + + +def upper(s): + # type: (bytes) -> bytes + """best-effort encoding-aware case-folding of local string s""" + try: + return asciiupper(s) + except UnicodeDecodeError: + return upperfallback(s) + + +def upperfallback(s): + # type: (Any) -> Any + try: + if isinstance(s, localstr): + u = s._utf8.decode("utf-8") + else: + u = s.decode(_sysstr(encoding), _sysstr(encodingmode)) + + uu = u.upper() + if u == uu: + return s # preserve localstring + return uu.encode(_sysstr(encoding)) + except UnicodeError: + return s.upper() # we don't know how to fold this except in ASCII + except LookupError as k: + raise error.Abort(k, hint=b"please check your locale settings") + + if not _nativeenviron: # now encoding and helper functions are available, recreate the environ # dict to be exported to other modules - environ = { - tolocal(k.encode('utf-8')): tolocal(v.encode('utf-8')) - for k, v in os.environ.items() # re-exports - } + if pycompat.iswindows and pycompat.ispy3: + + class WindowsEnviron(dict): + """`os.environ` normalizes environment variables to uppercase on windows""" + + def get(self, key, default=None): + return super().get(upper(key), default) + + environ = WindowsEnviron() + + for k, v in os.environ.items(): # re-exports + environ[tolocal(k.encode('utf-8'))] = tolocal(v.encode('utf-8')) + if pycompat.ispy3: # os.getcwd() on Python 3 returns string, but it has os.getcwdb() which @@ -441,56 +501,6 @@ return ellipsis # no enough room for multi-column characters -def lower(s): - # type: (bytes) -> bytes - """best-effort encoding-aware case-folding of local string s""" - try: - return asciilower(s) - except UnicodeDecodeError: - pass - try: - if isinstance(s, localstr): - u = s._utf8.decode("utf-8") - else: - u = s.decode(_sysstr(encoding), _sysstr(encodingmode)) - - lu = u.lower() - if u == lu: - return s # preserve localstring - return lu.encode(_sysstr(encoding)) - except UnicodeError: - return s.lower() # we don't know how to fold this except in ASCII - except LookupError as k: - raise error.Abort(k, hint=b"please check your locale settings") - - -def upper(s): - # type: (bytes) -> bytes - """best-effort encoding-aware case-folding of local string s""" - try: - return asciiupper(s) - except UnicodeDecodeError: - return upperfallback(s) - - -def upperfallback(s): - # type: (Any) -> Any - try: - if isinstance(s, localstr): - u = s._utf8.decode("utf-8") - else: - u = s.decode(_sysstr(encoding), _sysstr(encodingmode)) - - uu = u.upper() - if u == uu: - return s # preserve localstring - return uu.encode(_sysstr(encoding)) - except UnicodeError: - return s.upper() # we don't know how to fold this except in ASCII - except LookupError as k: - raise error.Abort(k, hint=b"please check your locale settings") - - class normcasespecs(object): """what a platform's normcase does to ASCII strings