Skip to content

Commit

Permalink
Rework system locale
Browse files Browse the repository at this point in the history
  • Loading branch information
codefiles committed Aug 17, 2022
1 parent b1ab5ba commit 76b1ba6
Showing 1 changed file with 107 additions and 16 deletions.
123 changes: 107 additions & 16 deletions archinstall/lib/installer.py
Expand Up @@ -12,7 +12,7 @@
from .disk import get_partitions_in_use, Partition
from .general import SysCommand, generate_password
from .hardware import has_uefi, is_vm, cpu_vendor
from .locale_helpers import verify_keyboard_layout, verify_x11_keyboard_layout
from .locale_helpers import list_locales, verify_keyboard_layout, verify_x11_keyboard_layout
from .disk.helpers import findmnt
from .mirrors import use_mirrors
from .plugins import plugins
Expand Down Expand Up @@ -443,29 +443,120 @@ def set_locale(self, locale :str, encoding :str = 'UTF-8', *args :str, **kwargs
if not len(locale):
return True

modifier = ''
# Get locale entries from /etc/locale.gen
entries = list_locales()

entry = ''

# Validate locale with entries from /etc/locale.gen
for row in entries:
entry_locale_name, entry_encoding = row.split()
if '.' in entry_locale_name:
entry_locale = entry_locale_name.split('.', 1)[0]
else:
entry_locale = entry_locale_name
if locale == entry_locale and encoding == entry_encoding:
entry = row
locale_name = entry_locale_name
locale = entry_locale
break
else:
self.log(f"Locale language '{locale}' and encoding '{encoding}' not found in /etc/locale.gen.", fg="red", level=logging.ERROR)
return False

# A user could modify /etc/locale.gen in the install environment and add an invalid entry before launching the installer.
# Verify the locale did not validate against an invalid entry due to a user modified /etc/locale.gen.
if not os.path.exists(f'{self.target}/usr/share/i18n/locales/{locale}'):
self.log(f'Invalid locale: {locale}.', fg="red", level=logging.ERROR)
return False

# This is a temporary patch to fix #1200
if '.' in locale:
locale, potential_encoding = locale.split('.', 1)
# Check if the locale is already installed using the output of localedef.
# Encodings are formatted differently in the output of localedef (no dashes and lowercase).
formatted_encoding = encoding.replace('-','').lower()
locale_formatted_encoding = f'{locale}.{formatted_encoding}'

# Override encoding if encoding is set to the default parameter
# and the "found" encoding differs.
if encoding == 'UTF-8' and encoding != potential_encoding:
encoding = potential_encoding
installed = []

# Get installed locales from the output of localedef.
for line in SysCommand(['localedef', '--list-archive']).decode().split():
installed.append(line)

# Install the locale if it is not already installed.
if locale_formatted_encoding not in installed:
# Before installing the locale check if the locale archive already exists and remove it if it does.
try:
os.remove('f{self.target}/usr/lib/locale/locale-archive')
except FileNotFoundError:
pass

# Use localdef rather than local-gen since local-gen is a wrapper of localdef for user convenience
# and all necessary parameters for localedef are avaliable.
command = f'localedef -i {locale} -c -f {encoding} -A /usr/share/locale/locale.alias {locale_name}'

if not subprocess.run(command).returncode == 0:
self.log(f"Failed to install locale language '{locale}' with '{encoding}'.", fg="red", level=logging.ERROR)
return False

modifier = ''

# Make sure we extract the modifier, that way we can put it in if needed.
if '@' in locale:
locale, modifier = locale.split('@', 1)
modifier = locale.split('@', 1)[1]
modifier = f"@{modifier}"
# - End patch

with open(f'{self.target}/etc/locale.gen', 'a') as fh:
fh.write(f'{locale}.{encoding}{modifier} {encoding}\n')
with open(f'{self.target}/etc/locale.conf', 'w') as fh:
fh.write(f'LANG={locale}.{encoding}{modifier}\n')
# A format of locale to check and set the system locale with.
formatted_locale = f'{locale}.{encoding}{modifier}'

locale_conf = f'{self.target}/etc/locale.conf'

return True if SysCommand(f'/usr/bin/arch-chroot {self.target} locale-gen').exit_code == 0 else False
found = ''

# Check if the system locale is already set correctly.
try:
with open(locale_conf, 'r') as fh:
regex = re.compile(rf'^LANG="?({locale_name}|{formatted_locale})"?$')

for line in fh:
found = regex.search(line)
if found:
found = found.group(1)
break
except FileNotFoundError:
pass

# Change the system locale if it is not set or not set correctly.
if not found:
with open(locale_conf, 'w') as fh:
fh.write(f'LANG={formatted_locale}\n')

locale_gen = f'{self.target}/etc/locale.gen'

# Update /etc/locale.gen if necessary so that locale-gen will function properly.
# Check if the locale is the only uncommented entry.
with open(locale_gen, 'r') as fh:
uncommented = []
for line in fh:
if line[0] != '#':
uncommented.append(line.strip())

if len(uncommented) == 1 and entry in uncommented:
return True

# Uncomment the entry for the locale and comment all other uncommented entries.
with open(locale_gen, 'r') as fh:
contents = fh.readlines()

index = 0
for index, line in enumerate(contents):
uncommented_line = line.replace('#', '')
if uncommented_line.rstrip() == entry:
contents[index] = uncommented_line
continue
if line[0] != '#':
contents[index] = f'#{contents[index]}'

with open(locale_gen, 'w') as fh:
return True if fh.writelines(contents) else False

def set_timezone(self, zone :str, *args :str, **kwargs :str) -> bool:
if not zone:
Expand Down

0 comments on commit 76b1ba6

Please sign in to comment.