Output a warning if LC_CTYPE is set to a value that causes libc toupper() and/or tolower() conversions not apply correctly to printable ASCII characters. --- pym/_emerge/actions.py | 3 +++ pym/portage/util/locale.py | 63 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 66 insertions(+) create mode 100644 pym/portage/util/locale.py
diff --git a/pym/_emerge/actions.py b/pym/_emerge/actions.py index 7f1cb59..e03e8d4 100644 --- a/pym/_emerge/actions.py +++ b/pym/_emerge/actions.py @@ -27,6 +27,7 @@ portage.proxy.lazyimport.lazyimport(globals(), 'portage.debug', 'portage.news:count_unread_news,display_news_notifications', 'portage.util._get_vm_info:get_vm_info', + 'portage.util.locale:check_locale', 'portage.emaint.modules.sync.sync:SyncRepos', '_emerge.chk_updated_cfg_files:chk_updated_cfg_files', '_emerge.help:help@emerge_help', @@ -2467,6 +2468,8 @@ def validate_ebuild_environment(trees): for line in textwrap.wrap(msg, 65): out.ewarn(line) + check_locale() + def check_procfs(): procfs_path = '/proc' if platform.system() not in ("Linux",) or \ diff --git a/pym/portage/util/locale.py b/pym/portage/util/locale.py new file mode 100644 index 0000000..6919ceb --- /dev/null +++ b/pym/portage/util/locale.py @@ -0,0 +1,63 @@ +#-*- coding:utf-8 -*- +# Copyright 2015 Gentoo Foundation +# Distributed under the terms of the GNU General Public License v2 +""" +Function to check whether the current used LC_CTYPE handles case +transformations of ASCII characters in a way compatible with the POSIX +locale. +get_ro_checker(). +""" +from __future__ import unicode_literals + +import logging +import textwrap + +from portage.util import writemsg_level +from portage.util._ctypes import find_library, LoadLibrary + + +def check_locale(): + """ + Check whether the locale is sane. Returns True if it is, prints + warning and returns False if it is not. Returns None if the check + can not be executed due to platform limitations. + """ + + libc_fn = find_library("c") + if libc_fn is None: + return None + libc = LoadLibrary(libc_fn) + if libc is None: + return None + + lc = list(range(ord('a'), ord('z')+1)) + uc = list(range(ord('A'), ord('Z')+1)) + rlc = [libc.tolower(c) for c in uc] + ruc = [libc.toupper(c) for c in lc] + + if lc != rlc or uc != ruc: + msg = ("WARNING: The LC_CTYPE variable is set to a locale " + + "that specifies transformation between lowercase " + + "and uppercase ASCII characters that is different than " + + "the one specified by POSIX locale. This can break " + + "ebuilds and cause issues in programs that rely on " + + "the common character conversion scheme. " + + "Please consider enabling another locale (such as " + + "en_US.UTF-8) in /etc/locale.gen and setting it " + + "as LC_CTYPE in make.conf.") + msg = [l for l in textwrap.wrap(msg, 70)] + msg.append("") + chars = lambda l: ''.join(chr(x) for x in l) + if uc != ruc: + msg.extend([ + " %s -> %s" % (chars(lc), chars(ruc)), + " %28s: %s" % ('expected', chars(uc))]) + if lc != rlc: + msg.extend([ + " %s -> %s" % (chars(uc), chars(rlc)), + " %28s: %s" % ('expected', chars(lc))]) + writemsg_level("".join(["!!! %s\n" % l for l in msg]), + level=logging.ERROR, noiselevel=-1) + return False + + return True -- 2.6.3