Skip to content

Commit 6579fdd

Browse files
committed
proot: let users specify a custom proot binary via PD_PROOT_BIN
Adds an env var override for the proot executable, following the same override-and-validate pattern already used for --emulator. Consolidates the three previously-duplicated "shutil.which(proot) or proot" lookups into one arch.get_proot_bin() helper.
1 parent 7d9d77a commit 6579fdd

5 files changed

Lines changed: 30 additions & 5 deletions

File tree

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,9 @@ On startup the tool verifies that `proot` is available. If it isn't:
120120
install it via `pkg install -y -q proot`.
121121
- Otherwise, an install hint is printed and the program exits.
122122

123+
Set `PD_PROOT_BIN` to use a custom `proot` executable instead of the
124+
PATH lookup; see the environment variables table below.
125+
123126
PRoot-Distro also refuses to run inside another `proot` (nested proot
124127
is not supported by `proot` itself) and prints a warning if launched
125128
as the `root` user.
@@ -1233,6 +1236,7 @@ paths sit under `$BASE_CACHE_DIR` (`$RUNTIME_DIR/cache` on Termux,
12331236
| `XDG_DATA_HOME` | On non-Termux hosts, base for `$XDG_DATA_HOME/proot-distro/`. Defaults to `~/.local/share`. |
12341237
| `XDG_CACHE_HOME` | On non-Termux hosts, base for `$XDG_CACHE_HOME/proot-distro/`. Defaults to `~/.cache`. |
12351238
| `PD_DOCKER_AUTH` | Credentials for pulling and pushing Docker/OCI images. Must be in `username:password` or `username:PAT` format (colon required). Sent as HTTP Basic auth to the registry's token endpoint to obtain a scoped bearer token. Takes effect for `install`, `build` (`FROM` base-image pulls), and `push` (with `pull,push` scope). |
1239+
| `PD_PROOT_BIN` | Absolute path to a custom `proot` executable, used in place of the PATH lookup for `login`, `run`, and `build` RUN steps. Must point at an existing, executable file or the command exits with an error. |
12361240
| `PD_FORCE_NO_COLORS` | When set to any value, disables ANSI colors in PRoot-Distro's own output. |
12371241
| `PROOT_VERBOSE` | Inherited and forwarded to `proot` for debugging. Skipped in `--minimal` mode. |
12381242
| `COLUMNS` | Fallback terminal width for `--help` rendering. |

proot_distro/arch.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,23 @@ def normalize_arch(arch: str):
186186
}
187187

188188

189+
def get_proot_bin() -> str:
190+
"""Return the proot executable to invoke, honoring PD_PROOT_BIN.
191+
192+
A set override is validated like --emulator: it must point at an
193+
existing, executable file, or the process exits with an error.
194+
Unset falls back to the existing PATH lookup for "proot".
195+
"""
196+
override = os.environ.get("PD_PROOT_BIN")
197+
if override:
198+
if not os.path.isfile(override) or not os.access(override, os.X_OK):
199+
crit_error(f"PD_PROOT_BIN '{override}' is not found or not "
200+
f"executable.")
201+
sys.exit(1)
202+
return override
203+
return shutil.which("proot") or "proot"
204+
205+
189206
def get_emulator_args(
190207
dist_arch: str, device_arch: str, emulator_override: str = ""
191208
) -> list:

proot_distro/cli.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737

3838
from proot_distro.constants import IS_TERMUX, PROGRAM_NAME
3939
from proot_distro.message import C, msg, set_quiet, crit_error
40+
from proot_distro.arch import get_proot_bin
4041
from proot_distro.parser import (
4142
ALIAS_TO_CANONICAL, REQUIRED_ARGS, build_parser,
4243
)
@@ -125,6 +126,10 @@ def ensure_proot_installed() -> None:
125126
`build`, which defers this check until it knows the Dockerfile
126127
actually contains a RUN-family instruction.
127128
"""
129+
if os.environ.get("PD_PROOT_BIN"):
130+
get_proot_bin() # validates, crit_error()+exit(1) if bad
131+
return
132+
128133
if shutil.which("proot") is not None:
129134
return
130135

proot_distro/commands/login/__init__.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@
3232
import json
3333
import os
3434
import shlex
35-
import shutil
3635
import sys
3736

3837
from proot_distro.constants import (
@@ -48,6 +47,7 @@
4847
detect_installed_arch,
4948
get_device_cpu_arch,
5049
get_emulator_args,
50+
get_proot_bin,
5151
)
5252
from proot_distro.sysdata import setup_fake_sysdata
5353
from proot_distro.locking import ContainerLock
@@ -422,7 +422,7 @@ def _command_login_inner(container_name: str, args, lock) -> None:
422422
f"architecture-specific binaries.")
423423
sys.exit(1)
424424

425-
proot_bin = shutil.which("proot") or "proot"
425+
proot_bin = get_proot_bin()
426426
proot_args = build_proot_args(
427427
proot_bin=proot_bin,
428428
rootfs=rootfs,

proot_distro/helpers/build_engine/run_step.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@
3131
import os
3232
import signal
3333
import subprocess
34-
import shutil
3534

3635
from proot_distro.constants import (
3736
DEFAULT_PATH_ENV,
@@ -43,7 +42,7 @@
4342
)
4443
from proot_distro.message import log_info
4544
from proot_distro.arch import (
46-
ARCH_UNAME_M, get_device_cpu_arch, get_emulator_args,
45+
ARCH_UNAME_M, get_device_cpu_arch, get_emulator_args, get_proot_bin,
4746
)
4847
from proot_distro.sysdata import setup_fake_sysdata, fake_proc_bindings
4948
from proot_distro.helpers.build_cache import (
@@ -148,7 +147,7 @@ def _run_extra_inputs(engine):
148147
def _exec_proot(engine, stage, command, stdin_input):
149148
"""Invoke proot against *stage*'s rootfs to execute *command*."""
150149
rootfs = stage.rootfs_dir
151-
proot_bin = shutil.which("proot") or "proot"
150+
proot_bin = get_proot_bin()
152151
proot_args = [proot_bin]
153152

154153
emu_args = get_emulator_args(

0 commit comments

Comments
 (0)