forked from Mirror/pmbootstrap
With the new chroot type, we can now write fancy paths in the pythonic way. Convert most of the codebase over, as well as adding various other type hints. Signed-off-by: Caleb Connolly <caleb@postmarketos.org>
94 lines
3.6 KiB
Python
94 lines
3.6 KiB
Python
# Copyright 2023 Oliver Smith
|
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
|
import os
|
|
from pathlib import Path, PurePath
|
|
import shutil
|
|
from typing import Sequence
|
|
|
|
import pmb.config
|
|
import pmb.chroot
|
|
import pmb.chroot.binfmt
|
|
import pmb.helpers.run
|
|
import pmb.helpers.run_core
|
|
from pmb.core import Chroot
|
|
from pmb.core.types import Env, PathString, PmbArgs
|
|
|
|
|
|
def executables_absolute_path():
|
|
"""
|
|
Get the absolute paths to the sh and chroot executables.
|
|
"""
|
|
ret = {}
|
|
for binary in ["sh", "chroot"]:
|
|
path = shutil.which(binary, path=pmb.config.chroot_host_path)
|
|
if not path:
|
|
raise RuntimeError(f"Could not find the '{binary}'"
|
|
" executable. Make sure that it is in"
|
|
" your current user's PATH.")
|
|
ret[binary] = path
|
|
return ret
|
|
|
|
|
|
def root(args: PmbArgs, cmd: Sequence[PathString], chroot: Chroot=Chroot.native(), working_dir: PurePath=PurePath("/"), output="log",
|
|
output_return=False, check=None, env={}, auto_init=True,
|
|
disable_timeout=False, add_proxy_env_vars=True):
|
|
"""
|
|
Run a command inside a chroot as root.
|
|
|
|
:param env: dict of environment variables to be passed to the command, e.g.
|
|
{"JOBS": "5"}
|
|
:param auto_init: automatically initialize the chroot
|
|
:param working_dir: chroot-relative working directory
|
|
:param add_proxy_env_vars: if True, preserve HTTP_PROXY etc. vars from host
|
|
environment. pmb.chroot.user sets this to False
|
|
when calling pmb.chroot.root, because it already
|
|
makes the variables part of the cmd argument.
|
|
|
|
See pmb.helpers.run_core.core() for a detailed description of all other
|
|
arguments and the return value.
|
|
"""
|
|
# Initialize chroot
|
|
if not auto_init and not (chroot / "bin/sh").is_symlink():
|
|
raise RuntimeError(f"Chroot does not exist: {chroot}")
|
|
if auto_init:
|
|
pmb.chroot.init(args, chroot)
|
|
|
|
# Convert any Path objects to their string representation
|
|
cmd_str = [os.fspath(x) for x in cmd]
|
|
|
|
# Readable log message (without all the escaping)
|
|
msg = f"({chroot}) % "
|
|
for key, value in env.items():
|
|
msg += f"{key}={value} "
|
|
if working_dir != PurePath("/"):
|
|
msg += f"cd {working_dir}; "
|
|
msg += " ".join(cmd_str)
|
|
|
|
# Merge env with defaults into env_all
|
|
env_all: Env = {"CHARSET": "UTF-8",
|
|
"HISTFILE": "~/.ash_history",
|
|
"HOME": "/root",
|
|
"LANG": "UTF-8",
|
|
"PATH": pmb.config.chroot_path,
|
|
"PYTHONUNBUFFERED": "1",
|
|
"SHELL": "/bin/ash",
|
|
"TERM": "xterm"}
|
|
for key, value in env.items():
|
|
env_all[key] = value
|
|
if add_proxy_env_vars:
|
|
pmb.helpers.run_core.add_proxy_env_vars(env_all)
|
|
|
|
# Build the command in steps and run it, e.g.:
|
|
# cmd: ["echo", "test"]
|
|
# cmd_chroot: ["/sbin/chroot", "/..._native", "/bin/sh", "-c", "echo test"]
|
|
# 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))]
|
|
cmd_sudo = pmb.config.sudo([
|
|
"env", "-i", executables["sh"], "-c",
|
|
pmb.helpers.run_core.flat_cmd(cmd_chroot, env=env_all)]
|
|
)
|
|
return pmb.helpers.run_core.core(args, msg, cmd_sudo, None, output,
|
|
output_return, check, True,
|
|
disable_timeout)
|