"Fossies" - the Fresh Open Source Software Archive

Member "salt-3004.1/salt/modules/localemod.py" (1 Mar 2022, 12120 Bytes) of package /linux/misc/salt-3004.1.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Python source code syntax highlighting (style: standard) with prefixed line numbers. Alternatively you can here view or download the uninterpreted source code file. For more information about "localemod.py" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 3003.3_vs_3004rc1.

    1 """
    2 Module for managing locales on POSIX-like systems.
    3 """
    4 
    5 import logging
    6 import os
    7 import re
    8 
    9 import salt.utils.locales
   10 import salt.utils.path
   11 import salt.utils.platform
   12 import salt.utils.systemd
   13 from salt.exceptions import CommandExecutionError
   14 
   15 try:
   16     import dbus
   17 except ImportError:
   18     dbus = None
   19 
   20 
   21 log = logging.getLogger(__name__)
   22 
   23 # Define the module's virtual name
   24 __virtualname__ = "locale"
   25 
   26 
   27 def __virtual__():
   28     """
   29     Exclude Windows OS.
   30     """
   31     if salt.utils.platform.is_windows():
   32         return False, "Cannot load locale module: windows platforms are unsupported"
   33 
   34     return __virtualname__
   35 
   36 
   37 def _parse_dbus_locale():
   38     """
   39     Get the 'System Locale' parameters from dbus
   40     """
   41     bus = dbus.SystemBus()
   42     localed = bus.get_object("org.freedesktop.locale1", "/org/freedesktop/locale1")
   43     properties = dbus.Interface(localed, "org.freedesktop.DBus.Properties")
   44     system_locale = properties.Get("org.freedesktop.locale1", "Locale")
   45 
   46     ret = {}
   47     for env_var in system_locale:
   48         env_var = str(env_var)
   49         match = re.match(r"^([A-Z_]+)=(.*)$", env_var)
   50         if match:
   51             ret[match.group(1)] = match.group(2).replace('"', "")
   52         else:
   53             log.error(
   54                 'Odd locale parameter "%s" detected in dbus locale '
   55                 "output. This should not happen. You should "
   56                 "probably investigate what caused this.",
   57                 env_var,
   58             )
   59 
   60     return ret
   61 
   62 
   63 def _localectl_status():
   64     """
   65     Parse localectl status into a dict.
   66     :return: dict
   67     """
   68     if salt.utils.path.which("localectl") is None:
   69         raise CommandExecutionError('Unable to find "localectl"')
   70 
   71     ret = {}
   72     locale_ctl_out = (__salt__["cmd.run"]("localectl status") or "").strip()
   73     ctl_key = None
   74     for line in locale_ctl_out.splitlines():
   75         if ": " in line:  # Keys are separate with ":" and a space (!).
   76             ctl_key, ctl_data = line.split(": ")
   77             ctl_key = ctl_key.strip().lower().replace(" ", "_")
   78         else:
   79             ctl_data = line.strip()
   80         if not ctl_data:
   81             continue
   82         if ctl_key:
   83             if "=" in ctl_data:
   84                 loc_set = ctl_data.split("=")
   85                 if len(loc_set) == 2:
   86                     if ctl_key not in ret:
   87                         ret[ctl_key] = {}
   88                     ret[ctl_key][loc_set[0]] = loc_set[1]
   89             else:
   90                 ret[ctl_key] = {"data": None if ctl_data == "n/a" else ctl_data}
   91     if not ret:
   92         log.debug(
   93             "Unable to find any locale information inside the following data:\n%s",
   94             locale_ctl_out,
   95         )
   96         raise CommandExecutionError('Unable to parse result of "localectl"')
   97 
   98     return ret
   99 
  100 
  101 def _localectl_set(locale=""):
  102     """
  103     Use systemd's localectl command to set the LANG locale parameter, making
  104     sure not to trample on other params that have been set.
  105     """
  106     locale_params = (
  107         _parse_dbus_locale()
  108         if dbus is not None
  109         else _localectl_status().get("system_locale", {})
  110     )
  111     locale_params["LANG"] = str(locale)
  112     args = " ".join(
  113         ['{}="{}"'.format(k, v) for k, v in locale_params.items() if v is not None]
  114     )
  115     return not __salt__["cmd.retcode"](
  116         "localectl set-locale {}".format(args), python_shell=False
  117     )
  118 
  119 
  120 def list_avail():
  121     """
  122     Lists available (compiled) locales
  123 
  124     CLI Example:
  125 
  126     .. code-block:: bash
  127 
  128         salt '*' locale.list_avail
  129     """
  130     return __salt__["cmd.run"]("locale -a").split("\n")
  131 
  132 
  133 def get_locale():
  134     """
  135     Get the current system locale
  136 
  137     CLI Example:
  138 
  139     .. code-block:: bash
  140 
  141         salt '*' locale.get_locale
  142     """
  143     ret = ""
  144     lc_ctl = salt.utils.systemd.booted(__context__)
  145     # localectl on SLE12 is installed but the integration is still broken in latest SP3 due to
  146     # config is rewritten by by many %post installation hooks in the older packages.
  147     # If you use it -- you will break your config. This is not the case in SLE15 anymore.
  148     if lc_ctl and not (
  149         __grains__["os_family"] in ["Suse"] and __grains__["osmajorrelease"] in [12]
  150     ):
  151         ret = (
  152             _parse_dbus_locale()
  153             if dbus is not None
  154             else _localectl_status()["system_locale"]
  155         ).get("LANG", "")
  156     else:
  157         if "Suse" in __grains__["os_family"]:
  158             cmd = 'grep "^RC_LANG" /etc/sysconfig/language'
  159         elif "RedHat" in __grains__["os_family"]:
  160             cmd = 'grep "^LANG=" /etc/sysconfig/i18n'
  161         elif "Debian" in __grains__["os_family"]:
  162             # this block only applies to Debian without systemd
  163             cmd = 'grep "^LANG=" /etc/default/locale'
  164         elif "Gentoo" in __grains__["os_family"]:
  165             cmd = "eselect --brief locale show"
  166             return __salt__["cmd.run"](cmd).strip()
  167         elif "Solaris" in __grains__["os_family"]:
  168             cmd = 'grep "^LANG=" /etc/default/init'
  169         else:  # don't waste time on a failing cmd.run
  170             raise CommandExecutionError(
  171                 'Error: "{}" is unsupported!'.format(__grains__["oscodename"])
  172             )
  173 
  174         if cmd:
  175             try:
  176                 ret = __salt__["cmd.run"](cmd).split("=")[1].replace('"', "")
  177             except IndexError as err:
  178                 log.error('Error occurred while running "%s": %s', cmd, err)
  179 
  180     return ret
  181 
  182 
  183 def set_locale(locale):
  184     """
  185     Sets the current system locale
  186 
  187     CLI Example:
  188 
  189     .. code-block:: bash
  190 
  191         salt '*' locale.set_locale 'en_US.UTF-8'
  192     """
  193     lc_ctl = salt.utils.systemd.booted(__context__)
  194     # localectl on SLE12 is installed but the integration is broken -- config is rewritten by YaST2
  195     if lc_ctl and not (
  196         __grains__["os_family"] in ["Suse"] and __grains__["osmajorrelease"] in [12]
  197     ):
  198         return _localectl_set(locale)
  199 
  200     if "Suse" in __grains__["os_family"]:
  201         # this block applies to all SUSE systems - also with systemd
  202         if not __salt__["file.file_exists"]("/etc/sysconfig/language"):
  203             __salt__["file.touch"]("/etc/sysconfig/language")
  204         __salt__["file.replace"](
  205             "/etc/sysconfig/language",
  206             "^RC_LANG=.*",
  207             'RC_LANG="{}"'.format(locale),
  208             append_if_not_found=True,
  209         )
  210     elif "RedHat" in __grains__["os_family"]:
  211         if not __salt__["file.file_exists"]("/etc/sysconfig/i18n"):
  212             __salt__["file.touch"]("/etc/sysconfig/i18n")
  213         __salt__["file.replace"](
  214             "/etc/sysconfig/i18n",
  215             "^LANG=.*",
  216             'LANG="{}"'.format(locale),
  217             append_if_not_found=True,
  218         )
  219     elif "Debian" in __grains__["os_family"]:
  220         # this block only applies to Debian without systemd
  221         update_locale = salt.utils.path.which("update-locale")
  222         if update_locale is None:
  223             raise CommandExecutionError(
  224                 'Cannot set locale: "update-locale" was not found.'
  225             )
  226         __salt__["cmd.run"](update_locale)  # (re)generate /etc/default/locale
  227         __salt__["file.replace"](
  228             "/etc/default/locale",
  229             "^LANG=.*",
  230             'LANG="{}"'.format(locale),
  231             append_if_not_found=True,
  232         )
  233     elif "Gentoo" in __grains__["os_family"]:
  234         cmd = "eselect --brief locale set {}".format(locale)
  235         return __salt__["cmd.retcode"](cmd, python_shell=False) == 0
  236     elif "Solaris" in __grains__["os_family"]:
  237         if locale not in __salt__["locale.list_avail"]():
  238             return False
  239         __salt__["file.replace"](
  240             "/etc/default/init",
  241             "^LANG=.*",
  242             'LANG="{}"'.format(locale),
  243             append_if_not_found=True,
  244         )
  245     else:
  246         raise CommandExecutionError("Error: Unsupported platform!")
  247 
  248     return True
  249 
  250 
  251 def avail(locale):
  252     """
  253     Check if a locale is available.
  254 
  255     .. versionadded:: 2014.7.0
  256 
  257     CLI Example:
  258 
  259     .. code-block:: bash
  260 
  261         salt '*' locale.avail 'en_US.UTF-8'
  262     """
  263     try:
  264         normalized_locale = salt.utils.locales.normalize_locale(locale)
  265     except IndexError:
  266         log.error('Unable to validate locale "%s"', locale)
  267         return False
  268     avail_locales = __salt__["locale.list_avail"]()
  269     locale_exists = next(
  270         (
  271             True
  272             for x in avail_locales
  273             if salt.utils.locales.normalize_locale(x.strip()) == normalized_locale
  274         ),
  275         False,
  276     )
  277     return locale_exists
  278 
  279 
  280 def gen_locale(locale, **kwargs):
  281     """
  282     Generate a locale. Options:
  283 
  284     .. versionadded:: 2014.7.0
  285 
  286     :param locale: Any locale listed in /usr/share/i18n/locales or
  287         /usr/share/i18n/SUPPORTED for Debian and Gentoo based distributions,
  288         which require the charmap to be specified as part of the locale
  289         when generating it.
  290 
  291     verbose
  292         Show extra warnings about errors that are normally ignored.
  293 
  294     CLI Example:
  295 
  296     .. code-block:: bash
  297 
  298         salt '*' locale.gen_locale en_US.UTF-8
  299         salt '*' locale.gen_locale 'en_IE.UTF-8 UTF-8'    # Debian/Gentoo only
  300     """
  301     on_debian = __grains__.get("os") == "Debian"
  302     on_ubuntu = __grains__.get("os") == "Ubuntu"
  303     on_gentoo = __grains__.get("os_family") == "Gentoo"
  304     on_suse = __grains__.get("os_family") == "Suse"
  305     on_solaris = __grains__.get("os_family") == "Solaris"
  306 
  307     if on_solaris:  # all locales are pre-generated
  308         return locale in __salt__["locale.list_avail"]()
  309 
  310     locale_info = salt.utils.locales.split_locale(locale)
  311     locale_search_str = "{}_{}".format(
  312         locale_info["language"], locale_info["territory"]
  313     )
  314 
  315     # if the charmap has not been supplied, normalize by appening it
  316     if not locale_info["charmap"] and not on_ubuntu:
  317         locale_info["charmap"] = locale_info["codeset"]
  318         locale = salt.utils.locales.join_locale(locale_info)
  319 
  320     if on_debian or on_gentoo:  # file-based search
  321         search = "/usr/share/i18n/SUPPORTED"
  322         valid = __salt__["file.search"](
  323             search, "^{}$".format(locale), flags=re.MULTILINE
  324         )
  325     else:  # directory-based search
  326         if on_suse:
  327             search = "/usr/share/locale"
  328         else:
  329             search = "/usr/share/i18n/locales"
  330 
  331         try:
  332             valid = locale_search_str in os.listdir(search)
  333         except OSError as ex:
  334             log.error(ex)
  335             raise CommandExecutionError('Locale "{}" is not available.'.format(locale))
  336 
  337     if not valid:
  338         log.error('The provided locale "%s" is not found in %s', locale, search)
  339         return False
  340 
  341     if os.path.exists("/etc/locale.gen"):
  342         __salt__["file.replace"](
  343             "/etc/locale.gen",
  344             r"^\s*#\s*{}\s*$".format(locale),
  345             "{}\n".format(locale),
  346             append_if_not_found=True,
  347         )
  348     elif on_ubuntu:
  349         __salt__["file.touch"](
  350             "/var/lib/locales/supported.d/{}".format(locale_info["language"])
  351         )
  352         __salt__["file.replace"](
  353             "/var/lib/locales/supported.d/{}".format(locale_info["language"]),
  354             locale,
  355             locale,
  356             append_if_not_found=True,
  357         )
  358 
  359     if salt.utils.path.which("locale-gen"):
  360         cmd = ["locale-gen"]
  361         if on_gentoo:
  362             cmd.append("--generate")
  363         if on_ubuntu:
  364             cmd.append(salt.utils.locales.normalize_locale(locale))
  365         else:
  366             cmd.append(locale)
  367     elif salt.utils.path.which("localedef"):
  368         cmd = [
  369             "localedef",
  370             "--force",
  371             "-i",
  372             locale_search_str,
  373             "-f",
  374             locale_info["codeset"],
  375             "{}.{}".format(locale_search_str, locale_info["codeset"]),
  376             kwargs.get("verbose", False) and "--verbose" or "--quiet",
  377         ]
  378     else:
  379         raise CommandExecutionError(
  380             'Command "locale-gen" or "localedef" was not found on this system.'
  381         )
  382 
  383     res = __salt__["cmd.run_all"](cmd)
  384     if res["retcode"]:
  385         log.error(res["stderr"])
  386 
  387     if kwargs.get("verbose"):
  388         return res
  389     else:
  390         return res["retcode"] == 0