[core] Fix PlatformIO progress bar rendering in subprocess mode (#15681)

This commit is contained in:
Jonathan Swoboda
2026-04-12 22:51:55 -04:00
committed by Jesse Hills
parent 6d894dd6ee
commit c3769e4fce
2 changed files with 30 additions and 3 deletions

View File

@@ -65,9 +65,6 @@ def run_platformio_cli(*args, **kwargs) -> str | int:
os.environ.setdefault("UV_HTTP_RETRIES", "10")
cmd = [sys.executable, "-m", "esphome.platformio_runner"] + list(args)
if not CORE.verbose:
kwargs["filter_lines"] = FILTER_PLATFORMIO_LINES
return run_external_process(*cmd, **kwargs)

View File

@@ -105,6 +105,36 @@ def main() -> int:
patch_structhash()
patch_file_downloader()
# Wrap stdout/stderr with RedirectText before PlatformIO runs:
#
# 1. RedirectText.isatty() unconditionally returns True. Click, tqdm, and
# PlatformIO's own progress-bar code check ``stream.isatty()`` to
# decide whether to emit TTY-format output (``\r`` cursor moves, ANSI
# colors, fancy progress bars). With the wrapper in place they always
# emit TTY format, even when our real stdout is a pipe to the parent
# process. Downstream consumers (local terminals and the Home
# Assistant dashboard log viewer) render the TTY control sequences
# correctly, so the user sees real progress bars.
#
# 2. FILTER_PLATFORMIO_LINES is applied inside RedirectText.write() in
# this subprocess, so noisy PlatformIO output is dropped before it
# ever leaves the runner. This replaces the parent-side filtering
# that was lost when we switched from in-process to subprocess — the
# parent's ``subprocess.run`` uses ``.fileno()`` on RedirectText and
# bypasses its ``write()`` path entirely.
#
# Filtering is disabled when the user passed -v / --verbose to
# ``esphome compile``, preserving the previous in-process behavior where
# verbose mode let all PlatformIO output through unfiltered.
from esphome.platformio_api import FILTER_PLATFORMIO_LINES
from esphome.util import RedirectText
is_verbose = any(arg in ("-v", "--verbose") for arg in sys.argv[1:])
filter_lines = None if is_verbose else FILTER_PLATFORMIO_LINES
sys.stdout = RedirectText(sys.stdout, filter_lines=filter_lines)
sys.stderr = RedirectText(sys.stderr, filter_lines=filter_lines)
import platformio.__main__
return platformio.__main__.main() or 0