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.
This commit is contained in:
Sterfield 2015-01-03 18:01:13 +01:00 committed by Matt Clay
parent 1b10058475
commit a674cb06e7

View file

@ -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