forked from Mirror/pmbootstrap
chroot: run: support running multiple commands with one call (MR 2252)
Building the command strings and entering the chroot is a not-insubstantial amount of overhead. Implement support for running multiple commands with a new pmb.chroot.rootm() function. TODO: add alternative for chroot.user and run.root/user. Signed-off-by: Caleb Connolly <caleb@postmarketos.org>
This commit is contained in:
parent
3a74018f89
commit
8a61d67053
5 changed files with 26 additions and 17 deletions
|
@ -29,11 +29,11 @@ def executables_absolute_path():
|
|||
return ret
|
||||
|
||||
|
||||
def root(cmd: Sequence[PathString], chroot: Chroot=Chroot.native(), working_dir: PurePath=PurePath("/"), output="log",
|
||||
def rootm(cmds: Sequence[Sequence[PathString]], chroot: Chroot=Chroot.native(), working_dir: PurePath=PurePath("/"), output="log",
|
||||
output_return=False, check=None, env={},
|
||||
disable_timeout=False, add_proxy_env_vars=True):
|
||||
"""
|
||||
Run a command inside a chroot as root.
|
||||
Run a list of commands inside a chroot as root.
|
||||
|
||||
:param env: dict of environment variables to be passed to the command, e.g.
|
||||
{"JOBS": "5"}
|
||||
|
@ -48,7 +48,7 @@ def root(cmd: Sequence[PathString], chroot: Chroot=Chroot.native(), working_dir:
|
|||
"""
|
||||
|
||||
# Convert any Path objects to their string representation
|
||||
cmd_str = [os.fspath(x) for x in cmd]
|
||||
cmd_strs = [[os.fspath(x) for x in cmd] for cmd in cmds]
|
||||
|
||||
# Readable log message (without all the escaping)
|
||||
msg = f"({chroot}) % "
|
||||
|
@ -56,7 +56,7 @@ def root(cmd: Sequence[PathString], chroot: Chroot=Chroot.native(), working_dir:
|
|||
msg += f"{key}={value} "
|
||||
if working_dir != PurePath("/"):
|
||||
msg += f"cd {working_dir}; "
|
||||
msg += " ".join(cmd_str)
|
||||
msg += "; ".join([" ".join(cmd_str) for cmd_str in cmd_strs])
|
||||
|
||||
# Merge env with defaults into env_all
|
||||
env_all: Env = {"CHARSET": "UTF-8",
|
||||
|
@ -78,16 +78,23 @@ def root(cmd: Sequence[PathString], chroot: Chroot=Chroot.native(), working_dir:
|
|||
# cmd_sudo: ["sudo", "env", "-i", "sh", "-c", "PATH=... /sbin/chroot ..."]
|
||||
executables = executables_absolute_path()
|
||||
cmd_chroot = [executables["chroot"], chroot.path, "/bin/sh", "-c",
|
||||
pmb.helpers.run_core.flat_cmd(cmd_str, Path(working_dir))]
|
||||
pmb.helpers.run_core.flat_cmd(cmd_strs, Path(working_dir))]
|
||||
cmd_sudo = pmb.config.sudo([
|
||||
"env", "-i", executables["sh"], "-c",
|
||||
pmb.helpers.run_core.flat_cmd(cmd_chroot, env=env_all)]
|
||||
pmb.helpers.run_core.flat_cmd([cmd_chroot], env=env_all)]
|
||||
)
|
||||
return pmb.helpers.run_core.core(msg, cmd_sudo, None, output,
|
||||
output_return, check, True,
|
||||
disable_timeout)
|
||||
|
||||
|
||||
def root(cmds: Sequence[PathString], chroot: Chroot=Chroot.native(), working_dir: PurePath=PurePath("/"), output="log",
|
||||
output_return=False, check=None, env={},
|
||||
disable_timeout=False, add_proxy_env_vars=True):
|
||||
return rootm([cmds], chroot, working_dir, output, output_return, check, env,
|
||||
disable_timeout, add_proxy_env_vars)
|
||||
|
||||
|
||||
def user(cmd, chroot: Chroot=Chroot.native(), working_dir: Path = Path("/"), output="log",
|
||||
output_return=False, check=None, env={}):
|
||||
"""
|
||||
|
@ -107,7 +114,7 @@ def user(cmd, chroot: Chroot=Chroot.native(), working_dir: Path = Path("/"), out
|
|||
if "HOME" not in env:
|
||||
env["HOME"] = "/home/pmos"
|
||||
|
||||
flat_cmd = pmb.helpers.run_core.flat_cmd(cmd, env=env)
|
||||
flat_cmd = pmb.helpers.run_core.flat_cmd([cmd], env=env)
|
||||
cmd = ["busybox", "su", "pmos", "-c", flat_cmd]
|
||||
return pmb.chroot.root(cmd, chroot, working_dir, output,
|
||||
output_return, check, {},
|
||||
|
|
|
@ -41,7 +41,7 @@ def _create_command_with_progress(command, fifo):
|
|||
"""
|
||||
flags = ["--no-progress", "--progress-fd", "3"]
|
||||
command_full = [command[0]] + flags + command[1:]
|
||||
command_flat = pmb.helpers.run_core.flat_cmd(command_full)
|
||||
command_flat = pmb.helpers.run_core.flat_cmd([command_full])
|
||||
command_flat = f"exec 3>{fifo}; {command_flat}"
|
||||
return ["sh", "-c", command_flat]
|
||||
|
||||
|
|
|
@ -32,7 +32,7 @@ def user(cmd: Sequence[PathString], working_dir: Optional[Path] = None, output:
|
|||
env = env.copy()
|
||||
pmb.helpers.run_core.add_proxy_env_vars(env)
|
||||
if env:
|
||||
cmd_parts = ["sh", "-c", pmb.helpers.run_core.flat_cmd(cmd_parts, env=env)]
|
||||
cmd_parts = ["sh", "-c", pmb.helpers.run_core.flat_cmd([cmd_parts], env=env)]
|
||||
return pmb.helpers.run_core.core(msg, cmd_parts, working_dir, output,
|
||||
output_return, check, sudo)
|
||||
|
||||
|
@ -60,7 +60,7 @@ def root(cmd: Sequence[PathString], working_dir=None, output="log", output_retur
|
|||
pmb.helpers.run_core.add_proxy_env_vars(env)
|
||||
|
||||
if env:
|
||||
cmd = ["sh", "-c", pmb.helpers.run_core.flat_cmd(cmd, env=env)]
|
||||
cmd = ["sh", "-c", pmb.helpers.run_core.flat_cmd([cmd], env=env)]
|
||||
cmd = pmb.config.sudo(cmd)
|
||||
|
||||
return user(cmd, working_dir, output, output_return, check, env,
|
||||
|
|
|
@ -20,10 +20,10 @@ import pmb.helpers.run
|
|||
called by core(). """
|
||||
|
||||
|
||||
def flat_cmd(cmd: Sequence[PathString], working_dir: Optional[Path]=None, env: Env={}):
|
||||
def flat_cmd(cmds: Sequence[Sequence[PathString]], working_dir: Optional[Path]=None, env: Env={}):
|
||||
"""Convert a shell command passed as list into a flat shell string with proper escaping.
|
||||
|
||||
:param cmd: command as list, e.g. ["echo", "string with spaces"]
|
||||
:param cmds: list of commands as list, e.g. ["echo", "string with spaces"]
|
||||
:param working_dir: when set, prepend "cd ...;" to execute the command
|
||||
in the given working directory
|
||||
:param env: dict of environment variables to be passed to the command, e.g.
|
||||
|
@ -36,8 +36,10 @@ def flat_cmd(cmd: Sequence[PathString], working_dir: Optional[Path]=None, env: E
|
|||
escaped = []
|
||||
for key, value in env.items():
|
||||
escaped.append(key + "=" + shlex.quote(os.fspath(value)))
|
||||
for cmd in cmds:
|
||||
for i in range(len(cmd)):
|
||||
escaped.append(shlex.quote(os.fspath(cmd[i])))
|
||||
escaped.append(";")
|
||||
|
||||
# Prepend working dir
|
||||
ret = " ".join(escaped)
|
||||
|
|
|
@ -34,7 +34,7 @@ def scp_abuild_key(args: PmbArgs, user: str, host: str, port: str):
|
|||
keyname = os.path.join("/tmp", os.path.basename(key))
|
||||
remote_cmd_l: List[PathString] = ['sudo', '-p', pmb.config.sideload_sudo_prompt,
|
||||
'-S', 'mv', '-n', keyname, "/etc/apk/keys/"]
|
||||
remote_cmd = pmb.helpers.run_core.flat_cmd(remote_cmd_l)
|
||||
remote_cmd = pmb.helpers.run_core.flat_cmd([remote_cmd_l])
|
||||
command = ['ssh', '-t', '-p', port, f'{user}@{host}', remote_cmd]
|
||||
pmb.helpers.run.user(command, output="tui")
|
||||
|
||||
|
@ -72,8 +72,8 @@ def ssh_install_apks(args: PmbArgs, user, host, port, paths):
|
|||
logging.info(f"Installing packages at {user}@{host}")
|
||||
add_cmd = ['sudo', '-p', pmb.config.sideload_sudo_prompt,
|
||||
'-S', 'apk', '--wait', '30', 'add'] + remote_paths
|
||||
add_cmd = pmb.helpers.run_core.flat_cmd(add_cmd)
|
||||
clean_cmd = pmb.helpers.run_core.flat_cmd(['rm'] + remote_paths)
|
||||
add_cmd = pmb.helpers.run_core.flat_cmd([add_cmd])
|
||||
clean_cmd = pmb.helpers.run_core.flat_cmd([['rm'] + remote_paths])
|
||||
add_cmd_complete = shlex.quote(f"{add_cmd}; rc=$?; {clean_cmd}; exit $rc")
|
||||
# Run apk command in a subshell in case the foreign device has a non-POSIX shell.
|
||||
command = ['ssh', '-t', '-p', port, f'{user}@{host}',
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue