cli(windows): capture setup.ps1 Write-Host output via -Command + *>&1

`unsloth studio update --local 2>&1 | tee logs/update.log` was
producing an empty update.log on windows-latest because
_run_setup_script() invoked powershell.exe -File studio/setup.ps1.
setup.ps1 emits every step/substep line via Write-Host, which on
PowerShell 5+ lands on the Information stream (#6) and is NOT
merged into stdout when -File is used and the parent's stdout is a
pipe. The bash tee in CI therefore saw nothing, and the post-step
grep for "prebuilt up to date and validated" failed with
::error::no prebuilt up-to-date marker in update.log.

Switch the Windows branch from -File to -Command, with the script
path single-quoted (apostrophes escaped per PowerShell rules) and
followed by *>&1 so all six PS streams (stdout, stderr, warning,
verbose, debug, information) are merged into the success stream.
That stream is then inherited by the Python subprocess and reaches
the parent's stdout pipe verbatim.

This also makes the install.ps1 -> unsloth.exe -> setup.ps1
grandchild output visible at install time for the first time, so
logs/install.log gains the existing "prebuilt installed and
validated" marker. The Windows-update workflow's filesystem-based
fallback is unchanged and still works.

Mac is untouched (still uses bash setup.sh -- plain stdout).
This commit is contained in:
Daniel Han 2026-05-08 02:43:22 +00:00
parent 0823562525
commit 47432b0bc7

View file

@ -998,7 +998,21 @@ def _run_setup_script(*, verbose: bool = False) -> None:
powershell_args.extend(
["-NoLogo", "-NoProfile", "-NonInteractive", "-WindowStyle", "Hidden"]
)
powershell_args.extend(["-ExecutionPolicy", "Bypass", "-File", str(script)])
# Use -Command + `*>&1` instead of -File so setup.ps1's
# Write-Host output (PowerShell Information stream / #6) is
# merged into the success stream and reaches the parent's
# stdout. With -File, Information stream output is dropped
# whenever stdout is a pipe, which is exactly the situation
# CI hits with `unsloth studio update --local 2>&1 | tee
# logs/update.log`. Single-quote escaping handles paths that
# contain apostrophes.
script_pwsh_literal = str(script).replace("'", "''")
powershell_args.extend(
[
"-ExecutionPolicy", "Bypass",
"-Command", f"& '{script_pwsh_literal}' *>&1",
]
)
result = subprocess.run(
powershell_args,
env = env,