##// END OF EJS Templates
chg: force-set LC_CTYPE on server start to actual value from the environment...
Kyle Lippincott -
r44733:04a3ae7a default
parent child Browse files
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 LANG=
368 LANG=
General Comments 0
You need to be logged in to leave comments. Login now