Now allow every type of locales + archlinux fix

The previous version of this code was supporting only locales using the
format "<language>_<territory>.<charset>". But all the locales that
doesn't have this format were not installable (such as "fr_FR" or
"fr_FR@euro").
Also, if an invalid locales was provided, the module kept sending a
"changed" status.

Now :
 * if the user provides an invalid locales, the module failed. Locales
   are verified using /etc/locale.gen or /usr/share/i18n/SUPPORTED if
   Ubuntu
 * Every types of valid locales are now supported.
 * The locale module was not working on Archlinux, as there's no space
   between the "#" and the locale. This is now supported. Credits goes
   to danderson189, this is his code.

This module was tested on debian jessie, ubuntu 14 LTS and last
Archlinux.
pull/18777/head
Sterfield 10 years ago committed by Matt Clay
parent 1b10058475
commit a674cb06e7

@ -41,6 +41,26 @@ LOCALE_NORMALIZATION = {
# location module specific support methods. # location module specific support methods.
# #
def is_available(name, ubuntuMode):
"""Check if the given locale is available on the system. This is done by
checking either :
* if the locale is present in /etc/locales.gen
* or if the locale is present in /usr/share/i18n/SUPPORTED"""
if ubuntuMode:
__regexp = '^(?P<locale>\S+_\S+) (?P<charset>\S+)\s*$'
__locales_available = '/usr/share/i18n/SUPPORTED'
else:
__regexp = '^#{0,1}\s*(?P<locale>\S+_\S+) (?P<charset>\S+)\s*$'
__locales_available = '/etc/locale.gen'
re_compiled = re.compile(__regexp)
with open(__locales_available, 'r') as fd:
for line in fd:
result = re_compiled.match(line)
if result and result.group('locale') == name:
return True
return False
def is_present(name): def is_present(name):
"""Checks if the given locale is currently installed.""" """Checks if the given locale is currently installed."""
output = Popen(["locale", "-a"], stdout=PIPE).communicate()[0] output = Popen(["locale", "-a"], stdout=PIPE).communicate()[0]
@ -60,32 +80,42 @@ def replace_line(existing_line, new_line):
with open("/etc/locale.gen", "w") as f: with open("/etc/locale.gen", "w") as f:
f.write("".join(lines)) f.write("".join(lines))
def apply_change(targetState, name, encoding): def set_locale(name, enabled=True):
""" Sets the state of the locale. Defaults to enabled. """
search_string = '#{0,1}\s*%s (?P<charset>.+)' % name
if enabled:
new_string = '%s \g<charset>' % (name)
else:
new_string = '# %s \g<charset>' % (name)
with open("/etc/locale.gen", "r") as f:
lines = [re.sub(search_string, new_string, line) for line in f]
with open("/etc/locale.gen", "w") as f:
f.write("".join(lines))
def apply_change(targetState, name):
"""Create or remove locale. """Create or remove locale.
Keyword arguments: Keyword arguments:
targetState -- Desired state, either present or absent. targetState -- Desired state, either present or absent.
name -- Name including encoding such as de_CH.UTF-8. name -- Name including encoding such as de_CH.UTF-8.
encoding -- Encoding such as UTF-8.
""" """
if targetState=="present": if targetState=="present":
# Create locale. # Create locale.
replace_line("# "+name+" "+encoding, name+" "+encoding) set_locale(name, enabled=True)
else: else:
# Delete locale. # Delete locale.
replace_line(name+" "+encoding, "# "+name+" "+encoding) set_locale(name, enabled=False)
localeGenExitValue = call("locale-gen") localeGenExitValue = call("locale-gen")
if localeGenExitValue!=0: if localeGenExitValue!=0:
raise EnvironmentError(localeGenExitValue, "locale.gen failed to execute, it returned "+str(localeGenExitValue)) raise EnvironmentError(localeGenExitValue, "locale.gen failed to execute, it returned "+str(localeGenExitValue))
def apply_change_ubuntu(targetState, name, encoding): def apply_change_ubuntu(targetState, name):
"""Create or remove locale. """Create or remove locale.
Keyword arguments: Keyword arguments:
targetState -- Desired state, either present or absent. targetState -- Desired state, either present or absent.
name -- Name including encoding such as de_CH.UTF-8. name -- Name including encoding such as de_CH.UTF-8.
encoding -- Encoding such as UTF-8.
""" """
if targetState=="present": if targetState=="present":
# Create locale. # Create locale.
@ -97,7 +127,8 @@ def apply_change_ubuntu(targetState, name, encoding):
content = f.readlines() content = f.readlines()
with open("/var/lib/locales/supported.d/local", "w") as f: with open("/var/lib/locales/supported.d/local", "w") as f:
for line in content: for line in content:
if line!=(name+" "+encoding+"\n"): locale, charset = line.split(' ')
if locale != name:
f.write(line) f.write(line)
# Purge locales and regenerate. # Purge locales and regenerate.
# Please provide a patch if you know how to avoid regenerating the locales to keep! # Please provide a patch if you know how to avoid regenerating the locales to keep!
@ -120,8 +151,6 @@ def main():
) )
name = module.params['name'] name = module.params['name']
if not "." in name:
module.fail_json(msg="Locale does not match pattern. Did you specify the encoding?")
state = module.params['state'] state = module.params['state']
if not os.path.exists("/etc/locale.gen"): if not os.path.exists("/etc/locale.gen"):
@ -133,23 +162,26 @@ def main():
else: else:
# We found the common way to manage locales. # We found the common way to manage locales.
ubuntuMode = False ubuntuMode = False
if not is_available(name, ubuntuMode):
module.fail_json(msg="The locales you've entered is not available "
"on your system.")
prev_state = "present" if is_present(name) else "absent" prev_state = "present" if is_present(name) else "absent"
changed = (prev_state!=state) changed = (prev_state!=state)
if module.check_mode: if module.check_mode:
module.exit_json(changed=changed) module.exit_json(changed=changed)
else: else:
encoding = name.split(".")[1]
if changed: if changed:
try: try:
if ubuntuMode==False: if ubuntuMode==False:
apply_change(state, name, encoding) apply_change(state, name)
else: else:
apply_change_ubuntu(state, name, encoding) apply_change_ubuntu(state, name)
except EnvironmentError as e: except EnvironmentError as e:
module.fail_json(msg=e.strerror, exitValue=e.errno) module.fail_json(msg=e.strerror, exitValue=e.errno)
module.exit_json(name=name, changed=changed, msg="OK") module.exit_json(name=name, changed=changed, msg="OK")
# import module snippets # import module snippets

Loading…
Cancel
Save