Show More
@@ -226,6 +226,16 b' static void execcmdserver(const struct c' | |||||
226 | } |
|
226 | } | |
227 | argv[argsize - 1] = NULL; |
|
227 | argv[argsize - 1] = NULL; | |
228 |
|
228 | |||
|
229 | const char *lc_ctype_env = getenv("LC_CTYPE"); | |||
|
230 | if (lc_ctype_env == NULL) { | |||
|
231 | if (putenv("CHG_CLEAR_LC_CTYPE=") != 0) | |||
|
232 | abortmsgerrno("failed to putenv CHG_CLEAR_LC_CTYPE"); | |||
|
233 | } else { | |||
|
234 | if (setenv("CHGORIG_LC_CTYPE", lc_ctype_env, 1) != 0) { | |||
|
235 | abortmsgerrno("failed to setenv CHGORIG_LC_CTYYPE"); | |||
|
236 | } | |||
|
237 | } | |||
|
238 | ||||
229 | if (putenv("CHGINTERNALMARK=") != 0) |
|
239 | if (putenv("CHGINTERNALMARK=") != 0) | |
230 | abortmsgerrno("failed to putenv"); |
|
240 | abortmsgerrno("failed to putenv"); | |
231 | if (execvp(hgcmd, (char **)argv) < 0) |
|
241 | if (execvp(hgcmd, (char **)argv) < 0) |
@@ -550,40 +550,6 b' class chgcmdserver(commandserver.server)' | |||||
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 |
|
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 |
|
||||
587 | encoding.environ.clear() |
|
553 | encoding.environ.clear() | |
588 | encoding.environ.update(newenv) |
|
554 | encoding.environ.update(newenv) | |
589 |
|
555 | |||
@@ -730,6 +696,16 b' def chgunixservice(ui, repo, opts):' | |||||
730 | # environ cleaner. |
|
696 | # environ cleaner. | |
731 | if b'CHGINTERNALMARK' in encoding.environ: |
|
697 | if b'CHGINTERNALMARK' in encoding.environ: | |
732 | del encoding.environ[b'CHGINTERNALMARK'] |
|
698 | del encoding.environ[b'CHGINTERNALMARK'] | |
|
699 | # Python3.7+ "coerces" the LC_CTYPE environment variable to a UTF-8 one if | |||
|
700 | # it thinks the current value is "C". This breaks the hash computation and | |||
|
701 | # causes chg to restart loop. | |||
|
702 | if b'CHGORIG_LC_CTYPE' in encoding.environ: | |||
|
703 | encoding.environ[b'LC_CTYPE'] = encoding.environ[b'CHGORIG_LC_CTYPE'] | |||
|
704 | del encoding.environ[b'CHGORIG_LC_CTYPE'] | |||
|
705 | elif b'CHG_CLEAR_LC_CTYPE' in encoding.environ: | |||
|
706 | if b'LC_CTYPE' in encoding.environ: | |||
|
707 | del encoding.environ[b'LC_CTYPE'] | |||
|
708 | del encoding.environ[b'CHG_CLEAR_LC_CTYPE'] | |||
733 |
|
709 | |||
734 | if repo: |
|
710 | if repo: | |
735 | # one chgserver can serve multiple repos. drop repo information |
|
711 | # one chgserver can serve multiple repos. drop repo information |
@@ -332,8 +332,8 b' check server log:' | |||||
332 | YYYY/MM/DD HH:MM:SS (PID)> log -R cached |
|
332 | YYYY/MM/DD HH:MM:SS (PID)> log -R cached | |
333 | YYYY/MM/DD HH:MM:SS (PID)> loaded repo into cache: $TESTTMP/cached (in ...s) |
|
333 | YYYY/MM/DD HH:MM:SS (PID)> loaded repo into cache: $TESTTMP/cached (in ...s) | |
334 |
|
334 | |||
335 | Test that chg works even when python "coerces" the locale (py3.7+, which is done |
|
335 | Test that chg works (sets to the user's actual LC_CTYPE) even when python | |
336 | by default if none of LC_ALL, LC_CTYPE, or LANG are set in the environment) |
|
336 | "coerces" the locale (py3.7+) | |
337 |
|
337 | |||
338 | $ cat > $TESTTMP/debugenv.py <<EOF |
|
338 | $ cat > $TESTTMP/debugenv.py <<EOF | |
339 | > from mercurial import encoding |
|
339 | > from mercurial import encoding | |
@@ -347,9 +347,22 b' by default if none of LC_ALL, LC_CTYPE, ' | |||||
347 | > if v is not None: |
|
347 | > if v is not None: | |
348 | > ui.write(b'%s=%s\n' % (k, encoding.environ[k])) |
|
348 | > ui.write(b'%s=%s\n' % (k, encoding.environ[k])) | |
349 | > EOF |
|
349 | > EOF | |
|
350 | (hg keeps python's modified LC_CTYPE, chg doesn't) | |||
|
351 | $ (unset LC_ALL; unset LANG; LC_CTYPE= "$CHGHG" \ | |||
|
352 | > --config extensions.debugenv=$TESTTMP/debugenv.py debugenv) | |||
|
353 | LC_CTYPE=C.UTF-8 (py37 !) | |||
|
354 | LC_CTYPE= (no-py37 !) | |||
|
355 | $ (unset LC_ALL; unset LANG; LC_CTYPE= chg \ | |||
|
356 | > --config extensions.debugenv=$TESTTMP/debugenv.py debugenv) | |||
|
357 | LC_CTYPE= | |||
|
358 | $ (unset LC_ALL; unset LANG; LC_CTYPE=unsupported_value chg \ | |||
|
359 | > --config extensions.debugenv=$TESTTMP/debugenv.py debugenv) | |||
|
360 | LC_CTYPE=unsupported_value | |||
|
361 | $ (unset LC_ALL; unset LANG; LC_CTYPE= chg \ | |||
|
362 | > --config extensions.debugenv=$TESTTMP/debugenv.py debugenv) | |||
|
363 | LC_CTYPE= | |||
350 | $ LANG= LC_ALL= LC_CTYPE= chg \ |
|
364 | $ LANG= LC_ALL= LC_CTYPE= chg \ | |
351 | > --config extensions.debugenv=$TESTTMP/debugenv.py debugenv |
|
365 | > --config extensions.debugenv=$TESTTMP/debugenv.py debugenv | |
352 | LC_ALL= |
|
366 | LC_ALL= | |
353 | LC_CTYPE=C.UTF-8 (py37 !) |
|
367 | LC_CTYPE= | |
354 | LC_CTYPE= (no-py37 !) |
|
|||
355 |
|
|
368 | LANG= |
General Comments 0
You need to be logged in to leave comments.
Login now