diff --git a/esphome/components/esp32/__init__.py b/esphome/components/esp32/__init__.py index f8e78794b2..7daaaf7433 100644 --- a/esphome/components/esp32/__init__.py +++ b/esphome/components/esp32/__init__.py @@ -1,5 +1,5 @@ from dataclasses import dataclass -from typing import Union +from typing import Union, Optional from pathlib import Path import logging import os @@ -42,6 +42,7 @@ from .const import ( # noqa KEY_REFRESH, KEY_REPO, KEY_SDKCONFIG_OPTIONS, + KEY_SUBMODULES, KEY_VARIANT, VARIANT_ESP32C3, VARIANT_FRIENDLY, @@ -120,17 +121,28 @@ def add_idf_sdkconfig_option(name: str, value: SdkconfigValueType): def add_idf_component( - name: str, repo: str, ref: str = None, path: str = None, refresh: TimePeriod = None + *, + name: str, + repo: str, + ref: str = None, + path: str = None, + refresh: TimePeriod = None, + components: Optional[list[str]] = None, + submodules: Optional[list[str]] = None, ): """Add an esp-idf component to the project.""" if not CORE.using_esp_idf: raise ValueError("Not an esp-idf project") + if components is None: + components = [] if name not in CORE.data[KEY_ESP32][KEY_COMPONENTS]: CORE.data[KEY_ESP32][KEY_COMPONENTS][name] = { KEY_REPO: repo, KEY_REF: ref, KEY_PATH: path, KEY_REFRESH: refresh, + KEY_COMPONENTS: components, + KEY_SUBMODULES: submodules, } @@ -536,20 +548,41 @@ def copy_files(): ref=component[KEY_REF], refresh=component[KEY_REFRESH], domain="idf_components", + submodules=component[KEY_SUBMODULES], ) mkdir_p(CORE.relative_build_path("components")) component_dir = repo_dir if component[KEY_PATH] is not None: component_dir = component_dir / component[KEY_PATH] - shutil.copytree( - component_dir, - CORE.relative_build_path(f"components/{name}"), - dirs_exist_ok=True, - ignore=shutil.ignore_patterns(".git", ".github"), - symlinks=True, - ignore_dangling_symlinks=True, - ) + if component[KEY_COMPONENTS] == ["*"]: + shutil.copytree( + component_dir, + CORE.relative_build_path("components"), + dirs_exist_ok=True, + ignore=shutil.ignore_patterns(".git*"), + symlinks=True, + ignore_dangling_symlinks=True, + ) + elif len(component[KEY_COMPONENTS]) > 0: + for comp in component[KEY_COMPONENTS]: + shutil.copytree( + component_dir / comp, + CORE.relative_build_path(f"components/{comp}"), + dirs_exist_ok=True, + ignore=shutil.ignore_patterns(".git*"), + symlinks=True, + ignore_dangling_symlinks=True, + ) + else: + shutil.copytree( + component_dir, + CORE.relative_build_path(f"components/{name}"), + dirs_exist_ok=True, + ignore=shutil.ignore_patterns(".git*"), + symlinks=True, + ignore_dangling_symlinks=True, + ) dir = os.path.dirname(__file__) post_build_file = os.path.join(dir, "post_build.py.script") diff --git a/esphome/components/esp32/const.py b/esphome/components/esp32/const.py index d13df01d3a..698310dacb 100644 --- a/esphome/components/esp32/const.py +++ b/esphome/components/esp32/const.py @@ -9,6 +9,7 @@ KEY_REPO = "repo" KEY_REF = "ref" KEY_REFRESH = "refresh" KEY_PATH = "path" +KEY_SUBMODULES = "submodules" VARIANT_ESP32 = "ESP32" VARIANT_ESP32S2 = "ESP32S2" diff --git a/esphome/components/mdns/__init__.py b/esphome/components/mdns/__init__.py index d9b36c7b09..e7d700d149 100644 --- a/esphome/components/mdns/__init__.py +++ b/esphome/components/mdns/__init__.py @@ -86,10 +86,10 @@ async def to_code(config): 5, 0, 0 ): add_idf_component( - "mdns", - "https://github.com/espressif/esp-protocols.git", - "mdns-v1.0.9", - "components/mdns", + name="mdns", + repo="https://github.com/espressif/esp-protocols.git", + ref="mdns-v1.0.9", + path="components/mdns", ) if config[CONF_DISABLED]: diff --git a/esphome/git.py b/esphome/git.py index a607325b73..dcc3e4d0c8 100644 --- a/esphome/git.py +++ b/esphome/git.py @@ -15,6 +15,7 @@ _LOGGER = logging.getLogger(__name__) def run_git_command(cmd, cwd=None) -> str: + _LOGGER.debug("Running git command: %s", " ".join(cmd)) try: ret = subprocess.run(cmd, cwd=cwd, capture_output=True, check=False) except FileNotFoundError as err: @@ -48,6 +49,7 @@ def clone_or_update( domain: str, username: str = None, password: str = None, + submodules: Optional[list[str]] = None, ) -> tuple[Path, Optional[Callable[[], None]]]: key = f"{url}@{ref}" @@ -74,6 +76,14 @@ def clone_or_update( run_git_command(["git", "fetch", "--", "origin", ref], str(repo_dir)) run_git_command(["git", "reset", "--hard", "FETCH_HEAD"], str(repo_dir)) + if submodules is not None: + _LOGGER.info( + "Initialising submodules (%s) for %s", ", ".join(submodules), key + ) + run_git_command( + ["git", "submodule", "update", "--init"] + submodules, str(repo_dir) + ) + else: # Check refresh needed file_timestamp = Path(repo_dir / ".git" / "FETCH_HEAD") @@ -97,6 +107,14 @@ def clone_or_update( # Hard reset to FETCH_HEAD (short-lived git ref corresponding to most recent fetch) run_git_command(["git", "reset", "--hard", "FETCH_HEAD"], str(repo_dir)) + if submodules is not None: + _LOGGER.info( + "Updating submodules (%s) for %s", ", ".join(submodules), key + ) + run_git_command( + ["git", "submodule", "update", "--init"] + submodules, str(repo_dir) + ) + def revert(): _LOGGER.info("Reverting changes to %s -> %s", key, old_sha) run_git_command(["git", "reset", "--hard", old_sha], str(repo_dir))