Mercurial > public > mercurial-scm > hg
comparison mercurial/chgserver.py @ 43860:5e0f6451e2d2
chg: fix chg to work with py3.7+ "coercing" the locale
When the environment is empty (specifically: it doesn't contain LC_ALL,
LC_CTYPE, or LANG), Python will "coerce" the locale environment variables to be
a UTF-8 capable one. It sets LC_CTYPE in the environment, and this breaks chg,
since chg operates by:
- start hg, using whatever environment the user has when chg starts
- hg stores a hash of this "original" environment, but python has already set
LC_CTYPE even though the user doesn't have it in their environment
- chg calls setenv over the commandserver. This clears the environment inside of
hg and sets it to be exactly what the environment in chg is (without
LC_CTYPE).
- chg calls validate to ensure that the environment hg is using (after the
setenv call) is the one that the chg process has - if not, it is assumed the
user changed their environment and we should use a different server. This will
*never* be true in this situation because LC_CTYPE was removed.
Differential Revision: https://phab.mercurial-scm.org/D7550
author | Kyle Lippincott <spectral@google.com> |
---|---|
date | Thu, 05 Dec 2019 14:28:21 -0800 |
parents | 975e517451a6 |
children | a61287a95dc3 |
comparison
equal
deleted
inserted
replaced
43859:8766728dbce6 | 43860:5e0f6451e2d2 |
---|---|
547 try: | 547 try: |
548 newenv = dict(s.split(b'=', 1) for s in l) | 548 newenv = dict(s.split(b'=', 1) for s in l) |
549 except ValueError: | 549 except ValueError: |
550 raise ValueError(b'unexpected value in setenv request') | 550 raise ValueError(b'unexpected value in setenv request') |
551 self.ui.log(b'chgserver', b'setenv: %r\n', sorted(newenv.keys())) | 551 self.ui.log(b'chgserver', b'setenv: %r\n', sorted(newenv.keys())) |
552 | |
553 # Python3 has some logic to "coerce" the C locale to a UTF-8 capable | |
554 # one, and it sets LC_CTYPE in the environment to C.UTF-8 if none of | |
555 # 'LC_CTYPE', 'LC_ALL' or 'LANG' are set (to any value). This can be | |
556 # disabled with PYTHONCOERCECLOCALE=0 in the environment. | |
557 # | |
558 # When fromui is called via _inithashstate, python has already set | |
559 # this, so that's in the environment right when we start up the hg | |
560 # process. Then chg will call us and tell us to set the environment to | |
561 # the one it has; this might NOT have LC_CTYPE, so we'll need to | |
562 # carry-forward the LC_CTYPE that was coerced in these situations. | |
563 # | |
564 # If this is not handled, we will fail config+env validation and fail | |
565 # to start chg. If this is just ignored instead of carried forward, we | |
566 # may have different behavior between chg and non-chg. | |
567 if pycompat.ispy3: | |
568 # Rename for wordwrapping purposes | |
569 oldenv = encoding.environ | |
570 if not any( | |
571 e.get(b'PYTHONCOERCECLOCALE') == b'0' for e in [oldenv, newenv] | |
572 ): | |
573 keys = [b'LC_CTYPE', b'LC_ALL', b'LANG'] | |
574 old_keys = [k for k, v in oldenv.items() if k in keys and v] | |
575 new_keys = [k for k, v in newenv.items() if k in keys and v] | |
576 # If the user's environment (from chg) doesn't have ANY of the | |
577 # keys that python looks for, and the environment (from | |
578 # initialization) has ONLY LC_CTYPE and it's set to C.UTF-8, | |
579 # carry it forward. | |
580 if ( | |
581 not new_keys | |
582 and old_keys == [b'LC_CTYPE'] | |
583 and oldenv[b'LC_CTYPE'] == b'C.UTF-8' | |
584 ): | |
585 newenv[b'LC_CTYPE'] = oldenv[b'LC_CTYPE'] | |
586 | |
552 encoding.environ.clear() | 587 encoding.environ.clear() |
553 encoding.environ.update(newenv) | 588 encoding.environ.update(newenv) |
554 | 589 |
555 capabilities = commandserver.server.capabilities.copy() | 590 capabilities = commandserver.server.capabilities.copy() |
556 capabilities.update( | 591 capabilities.update( |