mirror of
https://github.com/esphome/esphome.git
synced 2026-08-23 06:36:23 +00:00
[esp8266] Speed up builds with ccache when available (#17722)
This commit is contained in:
@@ -322,6 +322,149 @@ def test_run_platformio_cli_sets_environment_variables(
|
||||
assert "arg" in args
|
||||
|
||||
|
||||
def test_ccache_env_enabled_by_default(setup_core: Path) -> None:
|
||||
"""Ccache is enabled when the binary is on PATH and no override is set."""
|
||||
CORE.build_path = setup_core / "build" / "test"
|
||||
|
||||
with (
|
||||
patch.dict(os.environ, {}, clear=True),
|
||||
patch.object(toolchain.shutil, "which", return_value="/usr/bin/ccache"),
|
||||
):
|
||||
env = toolchain._ccache_env()
|
||||
|
||||
assert env["ESPHOME_CCACHE_ENABLE"] == "1"
|
||||
assert env["CCACHE_BASEDIR"] == str((setup_core / "build" / "test").resolve())
|
||||
assert env["CCACHE_DIR"].endswith("platformio-ccache")
|
||||
assert env["CCACHE_NOHASHDIR"] == "true"
|
||||
# Nothing may leak into os.environ: a later ESP-IDF build in the same
|
||||
# process would otherwise skip its own ccache defaults.
|
||||
assert "CCACHE_BASEDIR" not in os.environ
|
||||
assert "ESPHOME_CCACHE_ENABLE" not in os.environ
|
||||
|
||||
|
||||
def test_ccache_env_disabled_without_binary(setup_core: Path) -> None:
|
||||
"""Ccache stays off when the binary is not on PATH."""
|
||||
CORE.build_path = setup_core / "build" / "test"
|
||||
|
||||
with (
|
||||
patch.dict(os.environ, {}, clear=True),
|
||||
patch.object(toolchain.shutil, "which", return_value=None),
|
||||
):
|
||||
env = toolchain._ccache_env()
|
||||
|
||||
assert env == {"ESPHOME_CCACHE_ENABLE": "0"}
|
||||
|
||||
|
||||
def test_ccache_env_opt_out(setup_core: Path) -> None:
|
||||
"""ESPHOME_CCACHE_ENABLE=0 disables ccache even with the binary present."""
|
||||
CORE.build_path = setup_core / "build" / "test"
|
||||
|
||||
with (
|
||||
patch.dict(os.environ, {"ESPHOME_CCACHE_ENABLE": "0"}, clear=True),
|
||||
patch.object(toolchain.shutil, "which", return_value="/usr/bin/ccache"),
|
||||
):
|
||||
env = toolchain._ccache_env()
|
||||
|
||||
assert env == {"ESPHOME_CCACHE_ENABLE": "0"}
|
||||
|
||||
|
||||
def test_ccache_env_normalizes_enable_value(setup_core: Path) -> None:
|
||||
"""A truthy override value is normalized to "1" for the build scripts."""
|
||||
CORE.build_path = setup_core / "build" / "test"
|
||||
|
||||
with (
|
||||
patch.dict(os.environ, {"ESPHOME_CCACHE_ENABLE": "yes"}, clear=True),
|
||||
patch.object(toolchain.shutil, "which", return_value=None),
|
||||
):
|
||||
env = toolchain._ccache_env()
|
||||
|
||||
assert env["ESPHOME_CCACHE_ENABLE"] == "1"
|
||||
|
||||
|
||||
def test_ccache_env_respects_user_values_and_refreshes_basedir(
|
||||
setup_core: Path,
|
||||
) -> None:
|
||||
"""User CCACHE_* values win, but CCACHE_BASEDIR follows the build dir."""
|
||||
user_env = {
|
||||
"CCACHE_DIR": "/custom/cache",
|
||||
"CCACHE_BASEDIR": "/stale/other-device",
|
||||
}
|
||||
CORE.build_path = setup_core / "build" / "test"
|
||||
|
||||
with (
|
||||
patch.dict(os.environ, user_env, clear=True),
|
||||
patch.object(toolchain.shutil, "which", return_value="/usr/bin/ccache"),
|
||||
):
|
||||
env = toolchain._ccache_env()
|
||||
|
||||
# CCACHE_DIR is not returned, so the user's os.environ value applies in
|
||||
# the subprocess; CCACHE_BASEDIR is always refreshed to the build dir.
|
||||
assert "CCACHE_DIR" not in env
|
||||
assert env["CCACHE_BASEDIR"] == str((setup_core / "build" / "test").resolve())
|
||||
|
||||
|
||||
def test_run_platformio_cli_passes_ccache_env_to_subprocess_only(
|
||||
setup_core: Path, mock_run_external_process: Mock
|
||||
) -> None:
|
||||
"""The ccache settings reach the subprocess env without touching os.environ."""
|
||||
CORE.build_path = str(setup_core / "build" / "test")
|
||||
|
||||
with (
|
||||
patch.dict(os.environ, {}, clear=False),
|
||||
patch.object(toolchain.shutil, "which", return_value="/usr/bin/ccache"),
|
||||
):
|
||||
os.environ.pop("ESPHOME_CCACHE_ENABLE", None)
|
||||
mock_run_external_process.return_value = 0
|
||||
toolchain.run_platformio_cli("test", "arg")
|
||||
|
||||
env = mock_run_external_process.call_args[1]["env"]
|
||||
assert env["ESPHOME_CCACHE_ENABLE"] == "1"
|
||||
assert env["CCACHE_BASEDIR"] == str((setup_core / "build" / "test").resolve())
|
||||
assert "ESPHOME_CCACHE_ENABLE" not in os.environ
|
||||
assert "CCACHE_BASEDIR" not in os.environ
|
||||
|
||||
|
||||
def test_ccache_env_requires_build_path(setup_core: Path) -> None:
|
||||
"""Enabling ccache without a build path fails loudly."""
|
||||
CORE.build_path = None
|
||||
|
||||
with (
|
||||
patch.dict(os.environ, {}, clear=True),
|
||||
patch.object(toolchain.shutil, "which", return_value="/usr/bin/ccache"),
|
||||
pytest.raises(ValueError, match="CORE.build_path must be set"),
|
||||
):
|
||||
toolchain._ccache_env()
|
||||
|
||||
|
||||
def test_run_platformio_cli_merges_caller_env(
|
||||
setup_core: Path, mock_run_external_process: Mock
|
||||
) -> None:
|
||||
"""A caller-supplied env is the base and gains the ccache settings."""
|
||||
CORE.build_path = str(setup_core / "build" / "test")
|
||||
|
||||
with patch.object(toolchain.shutil, "which", return_value="/usr/bin/ccache"):
|
||||
mock_run_external_process.return_value = 0
|
||||
toolchain.run_platformio_cli(
|
||||
"test", env={"CUSTOM_VAR": "1", "ESPHOME_CCACHE_ENABLE": "0"}
|
||||
)
|
||||
|
||||
env = mock_run_external_process.call_args[1]["env"]
|
||||
assert env["CUSTOM_VAR"] == "1"
|
||||
# The normalized enable flag still lands in the subprocess env.
|
||||
assert "ESPHOME_CCACHE_ENABLE" in env
|
||||
|
||||
|
||||
def test_copy_ccache_script(setup_core: Path) -> None:
|
||||
"""The shared ccache pre-script is copied into the build dir."""
|
||||
CORE.build_path = setup_core / "build" / "test"
|
||||
|
||||
toolchain.copy_ccache_script()
|
||||
|
||||
dest = setup_core / "build" / "test" / "ccache.py"
|
||||
source = Path(toolchain.__file__).parent / "ccache.py.script"
|
||||
assert dest.read_text() == source.read_text()
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("platform", "input_path", "expected"),
|
||||
[
|
||||
@@ -375,7 +518,10 @@ def test_run_platformio_cli_strips_win_long_path_prefix(
|
||||
)
|
||||
|
||||
with (
|
||||
patch.dict(os.environ, {}, clear=False),
|
||||
# Pin ccache off: patching sys.platform to win32 (sys is a singleton,
|
||||
# so the stdlib sees it too) would send shutil.which down the Windows
|
||||
# code path, which crashes on a POSIX host.
|
||||
patch.dict(os.environ, {"ESPHOME_CCACHE_ENABLE": "0"}, clear=False),
|
||||
patch("esphome.platformio.toolchain.sys.platform", "win32"),
|
||||
patch("esphome.platformio.toolchain.sys.executable", prefixed_exe),
|
||||
):
|
||||
|
||||
Reference in New Issue
Block a user