fix(pm): decode captured build output as UTF-8

Windows defaulted captured uv output to CP1252. A UnicodeDecodeError in
the pipe reader hid the OpenSSL build failure and left an empty diagnostic.
Decode uv and npm output as UTF-8, replacing malformed bytes while keeping
the exit status and build error.

Real subprocess tests cover stdout, stderr, legacy locale defaults, and
malformed output. The encoding tests passed on native Windows ARM64 and
Linux through scripts/run_tests.sh.
This commit is contained in:
ethernet
2026-09-11 13:29:45 -04:00
parent 493ae9daa3
commit caf27c01b9
2 changed files with 105 additions and 2 deletions

View File

@@ -382,6 +382,8 @@ def install_node_sidecar(
cwd=str(plugin_dir),
capture_output=True,
text=True,
encoding="utf-8",
errors="replace",
timeout=900,
)
except Exception as exc:
@@ -469,7 +471,8 @@ def lock_and_sync(
if not frozen:
lock = subprocess.run(
[uv_bin, "lock"], cwd=str(generated), env=run_env, capture_output=True, text=True, timeout=1800
[uv_bin, "lock"], cwd=str(generated), env=run_env,
capture_output=True, text=True, encoding="utf-8", errors="replace", timeout=1800,
)
if lock.returncode != 0:
raise classify_uv_failure("lock", lock.returncode, lock.stderr or lock.stdout)
@@ -484,7 +487,10 @@ def lock_and_sync(
cmd = [uv_bin, "sync", "--frozen", "--all-packages"]
for extra in sorted(set(extras or [])):
cmd += ["--extra", extra]
sync = subprocess.run(cmd, cwd=str(generated), env=run_env, capture_output=True, text=True, timeout=1800)
sync = subprocess.run(
cmd, cwd=str(generated), env=run_env,
capture_output=True, text=True, encoding="utf-8", errors="replace", timeout=1800,
)
if sync.returncode != 0:
# --frozen means the lock already resolved; a sync failure here is
# install/download/tooling, never a NEW resolution conflict.