utils: add parameter to avoid clearing the LC_* variables

We used to set LC_ALL=C unconditionally when executing a command. This
is a problem if we want the output of a specific command to be
translated (provided a locale definition and an actual translation exist
for the requested language).

This patch adds the clean_locale parameter, which can be used to specify
if we want the locale variable to be cleaned, to most of the helpers
that execute commands.

The value defaults to True so the default behavior is preserved.
If one wants a command to be translated, they have to  explicitly pass
clean_locale=False.

Signed-off-by: Olivier Gayot <olivier.gayot@canonical.com>
This commit is contained in:
Olivier Gayot 2023-02-01 22:58:26 +01:00
parent d410022340
commit f284d25757
1 changed files with 14 additions and 11 deletions

View File

@ -24,13 +24,13 @@ from typing import List, Sequence
log = logging.getLogger("subiquitycore.utils")
def _clean_env(env):
def _clean_env(env, *, locale=True):
if env is None:
env = os.environ.copy()
else:
env = env.copy()
# Do we always want to do this?
env['LC_ALL'] = 'C'
if locale:
env['LC_ALL'] = 'C'
# Maaaybe want to remove SNAP here too.
return env
@ -52,7 +52,8 @@ def orig_environ(env):
def run_command(cmd: Sequence[str], *, input=None, stdout=subprocess.PIPE,
stderr=subprocess.PIPE, encoding='utf-8', errors='replace',
env=None, **kw) -> subprocess.CompletedProcess:
env=None, clean_locale=True,
**kw) -> subprocess.CompletedProcess:
"""A wrapper around subprocess.run with logging and different defaults.
We never ever want a subprocess to inherit our file descriptors!
@ -64,7 +65,7 @@ def run_command(cmd: Sequence[str], *, input=None, stdout=subprocess.PIPE,
log.debug("run_command called: %s", cmd)
try:
cp = subprocess.run(cmd, input=input, stdout=stdout, stderr=stderr,
env=_clean_env(env), **kw)
env=_clean_env(env, locale=clean_locale), **kw)
if encoding:
if isinstance(cp.stdout, bytes):
cp.stdout = cp.stdout.decode(encoding)
@ -81,7 +82,7 @@ def run_command(cmd: Sequence[str], *, input=None, stdout=subprocess.PIPE,
async def arun_command(cmd: Sequence[str], *,
stdout=subprocess.PIPE, stderr=subprocess.PIPE,
encoding='utf-8', input=None, errors='replace',
env=None, check=False, **kw) \
env=None, clean_locale=True, check=False, **kw) \
-> subprocess.CompletedProcess:
if input is None:
if 'stdin' not in kw:
@ -91,7 +92,8 @@ async def arun_command(cmd: Sequence[str], *,
input = input.encode(encoding)
log.debug("arun_command called: %s", cmd)
proc = await asyncio.create_subprocess_exec(
*cmd, stdout=stdout, stderr=stderr, env=_clean_env(env), **kw)
*cmd, stdout=stdout, stderr=stderr,
env=_clean_env(env, locale=clean_locale), **kw)
stdout, stderr = await proc.communicate(input=input)
if encoding:
if stdout is not None:
@ -111,11 +113,12 @@ async def arun_command(cmd: Sequence[str], *,
async def astart_command(cmd: Sequence[str], *, stdout=subprocess.PIPE,
stderr=subprocess.PIPE, stdin=subprocess.DEVNULL,
env=None, **kw) -> asyncio.subprocess.Process:
env=None, clean_locale=True,
**kw) -> asyncio.subprocess.Process:
log.debug("astart_command called: %s", cmd)
return await asyncio.create_subprocess_exec(
*cmd, stdout=stdout, stderr=stderr, stdin=stdin,
env=_clean_env(env), **kw)
env=_clean_env(env, locale=clean_locale), **kw)
async def split_cmd_output(cmd: Sequence[str], split_on: str) -> List[str]:
@ -126,14 +129,14 @@ async def split_cmd_output(cmd: Sequence[str], split_on: str) -> List[str]:
def start_command(cmd: Sequence[str], *,
stdin=subprocess.DEVNULL, stdout=subprocess.PIPE,
stderr=subprocess.PIPE, encoding='utf-8', errors='replace',
env=None, **kw) -> subprocess.Popen:
env=None, clean_locale=True, **kw) -> subprocess.Popen:
"""A wrapper around subprocess.Popen with logging and different defaults.
We never ever want a subprocess to inherit our file descriptors!
"""
log.debug('start_command called: %s', cmd)
return subprocess.Popen(cmd, stdin=stdin, stdout=stdout, stderr=stderr,
env=_clean_env(env), **kw)
env=_clean_env(env, locale=clean_locale), **kw)
# FIXME: replace with passlib and update package deps