mirror of
				https://github.com/esphome/esphome.git
				synced 2025-10-30 22:53:59 +00:00 
			
		
		
		
	Improve external components error messages (#2026)
This commit is contained in:
		| @@ -109,7 +109,15 @@ def _compute_destination_path(key: str) -> Path: | |||||||
|     return base_dir / h.hexdigest()[:8] |     return base_dir / h.hexdigest()[:8] | ||||||
|  |  | ||||||
|  |  | ||||||
| def _handle_git_response(ret): | def _run_git_command(cmd): | ||||||
|  |     try: | ||||||
|  |         ret = subprocess.run(cmd, capture_output=True, check=False) | ||||||
|  |     except FileNotFoundError as err: | ||||||
|  |         raise cv.Invalid( | ||||||
|  |             "git is not installed but required for external_components.\n" | ||||||
|  |             "Please see https://git-scm.com/book/en/v2/Getting-Started-Installing-Git for installing git" | ||||||
|  |         ) from err | ||||||
|  |  | ||||||
|     if ret.returncode != 0 and ret.stderr: |     if ret.returncode != 0 and ret.stderr: | ||||||
|         err_str = ret.stderr.decode("utf-8") |         err_str = ret.stderr.decode("utf-8") | ||||||
|         lines = [x.strip() for x in err_str.splitlines()] |         lines = [x.strip() for x in err_str.splitlines()] | ||||||
| @@ -118,46 +126,59 @@ def _handle_git_response(ret): | |||||||
|         raise cv.Invalid(err_str) |         raise cv.Invalid(err_str) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def _process_git_config(config: dict, refresh) -> str: | ||||||
|  |     key = f"{config[CONF_URL]}@{config.get(CONF_REF)}" | ||||||
|  |     repo_dir = _compute_destination_path(key) | ||||||
|  |     if not repo_dir.is_dir(): | ||||||
|  |         _LOGGER.info("Cloning %s", key) | ||||||
|  |         _LOGGER.debug("Location: %s", repo_dir) | ||||||
|  |         cmd = ["git", "clone", "--depth=1"] | ||||||
|  |         if CONF_REF in config: | ||||||
|  |             cmd += ["--branch", config[CONF_REF]] | ||||||
|  |         cmd += ["--", config[CONF_URL], str(repo_dir)] | ||||||
|  |         _run_git_command(cmd) | ||||||
|  |  | ||||||
|  |     else: | ||||||
|  |         # Check refresh needed | ||||||
|  |         file_timestamp = Path(repo_dir / ".git" / "FETCH_HEAD") | ||||||
|  |         # On first clone, FETCH_HEAD does not exists | ||||||
|  |         if not file_timestamp.exists(): | ||||||
|  |             file_timestamp = Path(repo_dir / ".git" / "HEAD") | ||||||
|  |         age = datetime.datetime.now() - datetime.datetime.fromtimestamp( | ||||||
|  |             file_timestamp.stat().st_mtime | ||||||
|  |         ) | ||||||
|  |         if age.seconds > refresh.total_seconds: | ||||||
|  |             _LOGGER.info("Updating %s", key) | ||||||
|  |             _LOGGER.debug("Location: %s", repo_dir) | ||||||
|  |             # Stash local changes (if any) | ||||||
|  |             _run_git_command(["git", "stash", "push", "--include-untracked"]) | ||||||
|  |             # Fetch remote ref | ||||||
|  |             cmd = ["git", "fetch", "--", "origin"] | ||||||
|  |             if CONF_REF in config: | ||||||
|  |                 cmd.append(config[CONF_REF]) | ||||||
|  |             _run_git_command(cmd) | ||||||
|  |             # Hard reset to FETCH_HEAD (short-lived git ref corresponding to most recent fetch) | ||||||
|  |             _run_git_command(["git", "reset", "--hard", "FETCH_HEAD"]) | ||||||
|  |  | ||||||
|  |     if (repo_dir / "esphome" / "components").is_dir(): | ||||||
|  |         components_dir = repo_dir / "esphome" / "components" | ||||||
|  |     elif (repo_dir / "components").is_dir(): | ||||||
|  |         components_dir = repo_dir / "components" | ||||||
|  |     else: | ||||||
|  |         raise cv.Invalid( | ||||||
|  |             "Could not find components folder for source. Please check the source contains a 'components' or 'esphome/components' folder" | ||||||
|  |         ) | ||||||
|  |  | ||||||
|  |     return components_dir | ||||||
|  |  | ||||||
|  |  | ||||||
| def _process_single_config(config: dict): | def _process_single_config(config: dict): | ||||||
|     conf = config[CONF_SOURCE] |     conf = config[CONF_SOURCE] | ||||||
|     if conf[CONF_TYPE] == TYPE_GIT: |     if conf[CONF_TYPE] == TYPE_GIT: | ||||||
|         key = f"{conf[CONF_URL]}@{conf.get(CONF_REF)}" |         with cv.prepend_path([CONF_SOURCE]): | ||||||
|         repo_dir = _compute_destination_path(key) |             components_dir = _process_git_config( | ||||||
|         if not repo_dir.is_dir(): |                 config[CONF_SOURCE], config[CONF_REFRESH] | ||||||
|             cmd = ["git", "clone", "--depth=1"] |  | ||||||
|             if CONF_REF in conf: |  | ||||||
|                 cmd += ["--branch", conf[CONF_REF]] |  | ||||||
|             cmd += [conf[CONF_URL], str(repo_dir)] |  | ||||||
|             ret = subprocess.run(cmd, capture_output=True, check=False) |  | ||||||
|             _handle_git_response(ret) |  | ||||||
|  |  | ||||||
|         else: |  | ||||||
|             # Check refresh needed |  | ||||||
|             file_timestamp = Path(repo_dir / ".git" / "FETCH_HEAD") |  | ||||||
|             # On first clone, FETCH_HEAD does not exists |  | ||||||
|             if not file_timestamp.exists(): |  | ||||||
|                 file_timestamp = Path(repo_dir / ".git" / "HEAD") |  | ||||||
|             age = datetime.datetime.now() - datetime.datetime.fromtimestamp( |  | ||||||
|                 file_timestamp.stat().st_mtime |  | ||||||
|             ) |             ) | ||||||
|             if age.seconds > config[CONF_REFRESH].total_seconds: |  | ||||||
|                 _LOGGER.info("Executing git pull %s", key) |  | ||||||
|                 cmd = ["git", "pull"] |  | ||||||
|                 ret = subprocess.run( |  | ||||||
|                     cmd, cwd=repo_dir, capture_output=True, check=False |  | ||||||
|                 ) |  | ||||||
|                 _handle_git_response(ret) |  | ||||||
|  |  | ||||||
|         if (repo_dir / "esphome" / "components").is_dir(): |  | ||||||
|             components_dir = repo_dir / "esphome" / "components" |  | ||||||
|         elif (repo_dir / "components").is_dir(): |  | ||||||
|             components_dir = repo_dir / "components" |  | ||||||
|         else: |  | ||||||
|             raise cv.Invalid( |  | ||||||
|                 "Could not find components folder for source. Please check the source contains a 'components' or 'esphome/components' folder", |  | ||||||
|                 [CONF_SOURCE], |  | ||||||
|             ) |  | ||||||
|  |  | ||||||
|     elif conf[CONF_TYPE] == TYPE_LOCAL: |     elif conf[CONF_TYPE] == TYPE_LOCAL: | ||||||
|         components_dir = Path(CORE.relative_config_path(conf[CONF_PATH])) |         components_dir = Path(CORE.relative_config_path(conf[CONF_PATH])) | ||||||
|     else: |     else: | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user