46 lines
1.2 KiB
Python
46 lines
1.2 KiB
Python
from __future__ import annotations
|
|
|
|
import shlex
|
|
import json
|
|
import subprocess
|
|
|
|
|
|
def shell_quote(value: str) -> str:
|
|
return shlex.quote(str(value))
|
|
|
|
|
|
def run_shell(script: str, timeout: float = 120.0) -> tuple[int, str, str]:
|
|
try:
|
|
r = subprocess.run(
|
|
["/bin/bash", "-lc", script],
|
|
capture_output=True,
|
|
text=True,
|
|
timeout=timeout,
|
|
)
|
|
return r.returncode, r.stdout or "", r.stderr or ""
|
|
except Exception as exc: # noqa: BLE001
|
|
return 1, "", str(exc)
|
|
|
|
|
|
def run_shell_as_admin(script: str, timeout: float = 180.0) -> tuple[int, str, str]:
|
|
"""Run a shell script through macOS' standard admin prompt.
|
|
|
|
This avoids silent failures for commands like ``networksetup`` and
|
|
``scutil --set`` when the user is not currently root.
|
|
"""
|
|
apple_script = (
|
|
"do shell script "
|
|
+ json.dumps(script)
|
|
+ " with administrator privileges"
|
|
)
|
|
try:
|
|
r = subprocess.run(
|
|
["osascript", "-e", apple_script],
|
|
capture_output=True,
|
|
text=True,
|
|
timeout=timeout,
|
|
)
|
|
return r.returncode, r.stdout or "", r.stderr or ""
|
|
except Exception as exc: # noqa: BLE001
|
|
return 1, "", str(exc)
|