mirror of
https://github.com/esphome/esphome.git
synced 2026-06-24 15:46:54 +00:00
[cli] Use pio run -t idedata to set up libretiny penv on cold hosts
The prior commit invoked 'pio pkg install' for the on-demand prep step,
which installs the libretiny platform package but does NOT recreate the
~/.platformio/penv/.libretiny/ virtualenv -- that's set up by libretiny's
ConfigurePythonVenv SCons step, which only fires during 'pio run'. So a
cold host (penv missing) still failed to find ltchiptool after the install
returned 'Already up-to-date'.
Wet test against bw15-device.yaml on a host with the libretiny penv
deleted:
esphome upload bw15-device.yaml --device /dev/null --prebuilt-dir ...
INFO ltchiptool not found on this host; installing the PlatformIO
rtl87xx platform package ...
Resolving bw15-device dependencies...
Already up-to-date.
ERROR ltchiptool not found. ...
Replace pkg install with 'pio run -t idedata'. The idedata target runs
SConscript without the actual compile target, so penv creation (libretiny)
and tool-package install (RP2040) happen as side effects of the SCons
configure phase -- but the build itself is skipped. Cost is a few seconds
of SCons configure, paid once per cold host.
Rename run_pkg_install -> prepare_platform_for_upload to match the new
semantics.
Issue: esphome/device-builder#572
Issue: esphome/device-builder#570
This commit is contained in:
@@ -1264,8 +1264,8 @@ def _ensure_platform_packages_for_prebuilt_upload(config: ConfigType) -> int:
|
||||
return 0
|
||||
|
||||
_LOGGER.info(
|
||||
"%s not found on this host; installing the PlatformIO %s "
|
||||
"platform package so the upload can flash the prebuilt firmware...",
|
||||
"%s not found on this host; configuring the PlatformIO %s "
|
||||
"platform so the upload can flash the prebuilt firmware...",
|
||||
tool_label,
|
||||
CORE.target_platform,
|
||||
)
|
||||
@@ -1275,7 +1275,10 @@ def _ensure_platform_packages_for_prebuilt_upload(config: ConfigType) -> int:
|
||||
|
||||
from esphome import platformio_api
|
||||
|
||||
return platformio_api.run_pkg_install(config, CORE.verbose)
|
||||
result = platformio_api.prepare_platform_for_upload(config, CORE.verbose)
|
||||
# prepare_platform_for_upload returns str on capture_stdout=True or int
|
||||
# on success/failure; in our call we don't capture stdout, so it's int.
|
||||
return result if isinstance(result, int) else 0
|
||||
|
||||
|
||||
def upload_program(
|
||||
|
||||
@@ -84,20 +84,26 @@ def run_compile(config, verbose):
|
||||
return run_platformio_cli_run(config, verbose, *args)
|
||||
|
||||
|
||||
def run_pkg_install(config, verbose) -> str | int:
|
||||
"""Install the PlatformIO platform + packages declared in platformio.ini
|
||||
for ``CORE.name``'s env, without compiling.
|
||||
def prepare_platform_for_upload(config, verbose) -> str | int:
|
||||
"""Configure the PlatformIO build environment for ``CORE.name`` without
|
||||
compiling, so platform-specific flashing tools end up on disk.
|
||||
|
||||
Used by ``esphome upload --prebuilt-dir`` on hosts that have never
|
||||
compiled the target platform locally: the flash tools we need
|
||||
(``ltchiptool`` for libretiny, ``picotool`` for RP2040) ship inside
|
||||
the PlatformIO platform package, so we trigger a package install to
|
||||
get them on disk without paying for a full compile.
|
||||
compiled the target platform locally. ``pio pkg install`` alone isn't
|
||||
enough on libretiny: the platform package downloads cleanly, but
|
||||
``ltchiptool`` lives in a platform-managed virtualenv at
|
||||
``~/.platformio/penv/.libretiny/`` that's only created by libretiny's
|
||||
``ConfigurePythonVenv`` SCons step, which runs during ``pio run`` (not
|
||||
``pio pkg install``). So we run ``pio run -t idedata`` instead: it
|
||||
triggers SConscript -- creating the penv on libretiny, installing the
|
||||
picotool tool package on RP2040 -- but skips the actual compile target
|
||||
so this is much cheaper than a full build.
|
||||
|
||||
The idedata JSON gets emitted to stdout as a side effect of the
|
||||
target; we don't filter it out -- the install runs once per cold host
|
||||
and the trailing JSON blob is harmless noise.
|
||||
"""
|
||||
command = ["pkg", "install", "-e", CORE.name, "-d", str(CORE.build_path)]
|
||||
if verbose:
|
||||
command += ["-v"]
|
||||
return run_platformio_cli(*command)
|
||||
return run_platformio_cli_run(config, verbose, "-t", "idedata")
|
||||
|
||||
|
||||
def _run_idedata(config):
|
||||
|
||||
@@ -1621,8 +1621,8 @@ def test_upload_program_prebuilt_dir_installs_libretiny_platform_if_missing(
|
||||
patch("esphome.__main__.get_ltchiptool_path", return_value=None) as mock_find,
|
||||
patch("esphome.__main__.write_cpp", return_value=0) as mock_write_cpp,
|
||||
patch(
|
||||
"esphome.platformio_api.run_pkg_install", return_value=0
|
||||
) as mock_pkg_install,
|
||||
"esphome.platformio_api.prepare_platform_for_upload", return_value=0
|
||||
) as mock_prep,
|
||||
patch("esphome.__main__.upload_using_ltchiptool", return_value=0),
|
||||
):
|
||||
exit_code, _ = upload_program({}, args, ["/dev/ttyUSB0"])
|
||||
@@ -1630,7 +1630,7 @@ def test_upload_program_prebuilt_dir_installs_libretiny_platform_if_missing(
|
||||
assert exit_code == 0
|
||||
mock_find.assert_called()
|
||||
mock_write_cpp.assert_called_once()
|
||||
mock_pkg_install.assert_called_once()
|
||||
mock_prep.assert_called_once()
|
||||
|
||||
|
||||
def test_upload_program_prebuilt_dir_skips_install_when_tool_present(
|
||||
@@ -1655,14 +1655,14 @@ def test_upload_program_prebuilt_dir_skips_install_when_tool_present(
|
||||
return_value=tmp_path / "ltchiptool",
|
||||
),
|
||||
patch("esphome.__main__.write_cpp") as mock_write_cpp,
|
||||
patch("esphome.platformio_api.run_pkg_install") as mock_pkg_install,
|
||||
patch("esphome.platformio_api.prepare_platform_for_upload") as mock_prep,
|
||||
patch("esphome.__main__.upload_using_ltchiptool", return_value=0),
|
||||
):
|
||||
exit_code, _ = upload_program({}, args, ["/dev/ttyUSB0"])
|
||||
|
||||
assert exit_code == 0
|
||||
mock_write_cpp.assert_not_called()
|
||||
mock_pkg_install.assert_not_called()
|
||||
mock_prep.assert_not_called()
|
||||
|
||||
|
||||
def test_upload_program_prebuilt_dir_write_cpp_failure_aborts_upload(
|
||||
@@ -1684,14 +1684,14 @@ def test_upload_program_prebuilt_dir_write_cpp_failure_aborts_upload(
|
||||
with (
|
||||
patch("esphome.__main__.get_ltchiptool_path", return_value=None),
|
||||
patch("esphome.__main__.write_cpp", return_value=3),
|
||||
patch("esphome.platformio_api.run_pkg_install") as mock_pkg_install,
|
||||
patch("esphome.platformio_api.prepare_platform_for_upload") as mock_prep,
|
||||
patch("esphome.__main__.upload_using_ltchiptool") as mock_upload,
|
||||
):
|
||||
exit_code, host = upload_program({}, args, ["/dev/ttyUSB0"])
|
||||
|
||||
assert exit_code == 3
|
||||
assert host is None
|
||||
mock_pkg_install.assert_not_called()
|
||||
mock_prep.assert_not_called()
|
||||
mock_upload.assert_not_called()
|
||||
|
||||
|
||||
@@ -1713,7 +1713,7 @@ def test_upload_program_prebuilt_dir_pkg_install_failure_aborts_upload(
|
||||
with (
|
||||
patch("esphome.__main__._find_picotool", return_value=None),
|
||||
patch("esphome.__main__.write_cpp", return_value=0),
|
||||
patch("esphome.platformio_api.run_pkg_install", return_value=2),
|
||||
patch("esphome.platformio_api.prepare_platform_for_upload", return_value=2),
|
||||
patch("esphome.__main__.upload_using_picotool") as mock_upload,
|
||||
patch("esphome.__main__._rp2040_serial_reset_to_bootsel") as mock_reset,
|
||||
):
|
||||
|
||||
Reference in New Issue
Block a user