mirror of
https://github.com/espressif/esp-idf.git
synced 2025-10-03 02:20:57 +02:00
Merge branch 'contrib/github_pr_17586' into 'master'
Fix warning message in install.sh. (GitHub PR) Closes IDFGH-16454 See merge request espressif/esp-idf!41890
This commit is contained in:
@@ -1,5 +1,4 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
# coding=utf-8
|
|
||||||
#
|
#
|
||||||
# SPDX-FileCopyrightText: 2019-2025 Espressif Systems (Shanghai) CO LTD
|
# SPDX-FileCopyrightText: 2019-2025 Espressif Systems (Shanghai) CO LTD
|
||||||
#
|
#
|
||||||
@@ -64,16 +63,11 @@ except RuntimeError as e:
|
|||||||
print(e)
|
print(e)
|
||||||
raise SystemExit(1)
|
raise SystemExit(1)
|
||||||
|
|
||||||
|
from collections.abc import Callable
|
||||||
|
from collections.abc import Iterator
|
||||||
from typing import IO
|
from typing import IO
|
||||||
from typing import Any
|
from typing import Any
|
||||||
from typing import Callable
|
|
||||||
from typing import Dict
|
|
||||||
from typing import Iterator
|
|
||||||
from typing import List
|
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
from typing import Set
|
|
||||||
from typing import Tuple
|
|
||||||
from typing import Union
|
|
||||||
from urllib.error import ContentTooShortError
|
from urllib.error import ContentTooShortError
|
||||||
from urllib.parse import urljoin
|
from urllib.parse import urljoin
|
||||||
from urllib.parse import urlparse
|
from urllib.parse import urlparse
|
||||||
@@ -123,7 +117,7 @@ class GlobalVarsStore:
|
|||||||
|
|
||||||
def __new__(cls, *args: Any, **kwargs: Any) -> 'GlobalVarsStore':
|
def __new__(cls, *args: Any, **kwargs: Any) -> 'GlobalVarsStore':
|
||||||
if not cls._instance:
|
if not cls._instance:
|
||||||
cls._instance = super(GlobalVarsStore, cls).__new__(cls, *args, **kwargs)
|
cls._instance = super().__new__(cls, *args, **kwargs)
|
||||||
cls._instance._initialize_properties()
|
cls._instance._initialize_properties()
|
||||||
return cls._instance
|
return cls._instance
|
||||||
|
|
||||||
@@ -137,7 +131,7 @@ class GlobalVarsStore:
|
|||||||
|
|
||||||
def __getattr__(self, name: str) -> Any:
|
def __getattr__(self, name: str) -> Any:
|
||||||
if name in self._bool_properties + self._string_properties:
|
if name in self._bool_properties + self._string_properties:
|
||||||
value: Union[str, bool] = getattr(self, f'_{name}')
|
value: str | bool = getattr(self, f'_{name}')
|
||||||
if value is None and name in self._string_properties:
|
if value is None and name in self._string_properties:
|
||||||
raise ReferenceError(f'Variable {name} accessed before initialization.')
|
raise ReferenceError(f'Variable {name} accessed before initialization.')
|
||||||
return value
|
return value
|
||||||
@@ -169,7 +163,7 @@ def warn(text: str, *args: str) -> None:
|
|||||||
sys.stderr.write(f'WARNING: {text}\n', *args)
|
sys.stderr.write(f'WARNING: {text}\n', *args)
|
||||||
|
|
||||||
|
|
||||||
def info(text: str, f: Optional[IO[str]] = None, *args: str) -> None:
|
def info(text: str, f: IO[str] | None = None, *args: str) -> None:
|
||||||
"""
|
"""
|
||||||
Writes text to a stream specified by second arg, sys.stdout by default.
|
Writes text to a stream specified by second arg, sys.stdout by default.
|
||||||
"""
|
"""
|
||||||
@@ -278,7 +272,7 @@ class Platforms:
|
|||||||
UNSUPPORTED_PLATFORMS = ['Linux-armv6l']
|
UNSUPPORTED_PLATFORMS = ['Linux-armv6l']
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def detect_linux_arm_platform(supposed_platform: Optional[str]) -> Optional[str]:
|
def detect_linux_arm_platform(supposed_platform: str | None) -> str | None:
|
||||||
"""
|
"""
|
||||||
We probe the python binary to check exactly what environment the script is running in.
|
We probe the python binary to check exactly what environment the script is running in.
|
||||||
|
|
||||||
@@ -314,7 +308,7 @@ class Platforms:
|
|||||||
return supposed_platform
|
return supposed_platform
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get(platform_alias: Optional[str]) -> str:
|
def get(platform_alias: str | None) -> str:
|
||||||
"""
|
"""
|
||||||
Get a proper platform name based on PLATFORM_FROM_NAME dict.
|
Get a proper platform name based on PLATFORM_FROM_NAME dict.
|
||||||
"""
|
"""
|
||||||
@@ -423,9 +417,7 @@ MrY=
|
|||||||
DL_CERT_DICT = {'dl.espressif.com': DIGICERT_ROOT_G2_CERT, 'github.com': DIGICERT_ROOT_CA_CERT}
|
DL_CERT_DICT = {'dl.espressif.com': DIGICERT_ROOT_G2_CERT, 'github.com': DIGICERT_ROOT_CA_CERT}
|
||||||
|
|
||||||
|
|
||||||
def run_cmd_check_output(
|
def run_cmd_check_output(cmd: list[str], input_text: str | None = None, extra_paths: list[str] | None = None) -> bytes:
|
||||||
cmd: List[str], input_text: Optional[str] = None, extra_paths: Optional[List[str]] = None
|
|
||||||
) -> bytes:
|
|
||||||
"""
|
"""
|
||||||
Runs command and checks output for exceptions. If AttributeError or TypeError occurs, function re-runs the process.
|
Runs command and checks output for exceptions. If AttributeError or TypeError occurs, function re-runs the process.
|
||||||
If return code was not 0, subprocess.CalledProcessError is raised, otherwise, the original error is masked.
|
If return code was not 0, subprocess.CalledProcessError is raised, otherwise, the original error is masked.
|
||||||
@@ -453,7 +445,7 @@ def run_cmd_check_output(
|
|||||||
input_bytes = None
|
input_bytes = None
|
||||||
if input_text:
|
if input_text:
|
||||||
input_bytes = input_text.encode()
|
input_bytes = input_text.encode()
|
||||||
result = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, check=True, input=input_bytes)
|
result = subprocess.run(cmd, capture_output=True, check=True, input=input_bytes)
|
||||||
return result.stdout + result.stderr
|
return result.stdout + result.stderr
|
||||||
except (AttributeError, TypeError):
|
except (AttributeError, TypeError):
|
||||||
p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.PIPE)
|
p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||||
@@ -466,7 +458,7 @@ def run_cmd_check_output(
|
|||||||
return stdout + stderr
|
return stdout + stderr
|
||||||
|
|
||||||
|
|
||||||
def to_shell_specific_paths(paths_list: List[str]) -> List[str]:
|
def to_shell_specific_paths(paths_list: list[str]) -> list[str]:
|
||||||
"""
|
"""
|
||||||
Converts / (linux) to \\ (Windows) if called under win32 platform.
|
Converts / (linux) to \\ (Windows) if called under win32 platform.
|
||||||
"""
|
"""
|
||||||
@@ -476,7 +468,7 @@ def to_shell_specific_paths(paths_list: List[str]) -> List[str]:
|
|||||||
return paths_list
|
return paths_list
|
||||||
|
|
||||||
|
|
||||||
def get_env_for_extra_paths(extra_paths: List[str]) -> Dict[str, str]:
|
def get_env_for_extra_paths(extra_paths: list[str]) -> dict[str, str]:
|
||||||
"""
|
"""
|
||||||
Return a copy of environment variables dict, prepending paths listed in extra_paths
|
Return a copy of environment variables dict, prepending paths listed in extra_paths
|
||||||
to the PATH environment variable.
|
to the PATH environment variable.
|
||||||
@@ -487,7 +479,7 @@ def get_env_for_extra_paths(extra_paths: List[str]) -> Dict[str, str]:
|
|||||||
return env_arg
|
return env_arg
|
||||||
|
|
||||||
|
|
||||||
def get_file_size_sha256(filename: str, block_size: int = 65536) -> Tuple[int, str]:
|
def get_file_size_sha256(filename: str, block_size: int = 65536) -> tuple[int, str]:
|
||||||
"""
|
"""
|
||||||
Gets file size and its sha256.
|
Gets file size and its sha256.
|
||||||
"""
|
"""
|
||||||
@@ -506,7 +498,7 @@ def report_progress(count: int, block_size: int, total_size: int) -> None:
|
|||||||
"""
|
"""
|
||||||
percent = int(count * block_size * 100 / total_size)
|
percent = int(count * block_size * 100 / total_size)
|
||||||
percent = min(100, percent)
|
percent = min(100, percent)
|
||||||
sys.stdout.write('\r%d%%' % percent)
|
sys.stdout.write(f'\r{percent}%')
|
||||||
sys.stdout.flush()
|
sys.stdout.flush()
|
||||||
|
|
||||||
|
|
||||||
@@ -528,10 +520,10 @@ def unpack(filename: str, destination: str) -> None:
|
|||||||
"""
|
"""
|
||||||
info(f'Extracting {filename} to {destination}')
|
info(f'Extracting {filename} to {destination}')
|
||||||
if filename.endswith(('.tar.gz', '.tgz')):
|
if filename.endswith(('.tar.gz', '.tgz')):
|
||||||
archive_obj: Union[TarFile, ZipFile] = tarfile.open(filename, 'r:gz')
|
archive_obj: TarFile | ZipFile = tarfile.open(filename, 'r:gz')
|
||||||
elif filename.endswith(('.tar.xz')):
|
elif filename.endswith('.tar.xz'):
|
||||||
archive_obj = tarfile.open(filename, 'r:xz')
|
archive_obj = tarfile.open(filename, 'r:xz')
|
||||||
elif filename.endswith(('.tar.bz2')):
|
elif filename.endswith('.tar.bz2'):
|
||||||
archive_obj = tarfile.open(filename, 'r:bz2')
|
archive_obj = tarfile.open(filename, 'r:bz2')
|
||||||
elif filename.endswith('zip'):
|
elif filename.endswith('zip'):
|
||||||
archive_obj = ZipFile(filename)
|
archive_obj = ZipFile(filename)
|
||||||
@@ -555,7 +547,7 @@ def unpack(filename: str, destination: str) -> None:
|
|||||||
os.chmod(extracted_file, extracted_permissions)
|
os.chmod(extracted_file, extracted_permissions)
|
||||||
|
|
||||||
|
|
||||||
def splittype(url: str) -> Tuple[Optional[str], str]:
|
def splittype(url: str) -> tuple[str | None, str]:
|
||||||
"""
|
"""
|
||||||
Splits given url into its type (e.g. https, file) and the rest.
|
Splits given url into its type (e.g. https, file) and the rest.
|
||||||
"""
|
"""
|
||||||
@@ -569,10 +561,10 @@ def splittype(url: str) -> Tuple[Optional[str], str]:
|
|||||||
def urlretrieve_ctx(
|
def urlretrieve_ctx(
|
||||||
url: str,
|
url: str,
|
||||||
filename: str,
|
filename: str,
|
||||||
reporthook: Optional[Callable[[int, int, int], None]] = None,
|
reporthook: Callable[[int, int, int], None] | None = None,
|
||||||
data: Optional[bytes] = None,
|
data: bytes | None = None,
|
||||||
context: Optional[SSLContext] = None,
|
context: SSLContext | None = None,
|
||||||
) -> Tuple[str, addinfourl]:
|
) -> tuple[str, addinfourl]:
|
||||||
"""
|
"""
|
||||||
Retrieve data from given URL. An alternative version of urlretrieve which takes SSL context as an argument.
|
Retrieve data from given URL. An alternative version of urlretrieve which takes SSL context as an argument.
|
||||||
"""
|
"""
|
||||||
@@ -614,12 +606,12 @@ def urlretrieve_ctx(
|
|||||||
reporthook(blocknum, bs, size)
|
reporthook(blocknum, bs, size)
|
||||||
|
|
||||||
if size >= 0 and read < size:
|
if size >= 0 and read < size:
|
||||||
raise ContentTooShortError('retrieval incomplete: got only %i out of %i bytes' % (read, size), result)
|
raise ContentTooShortError(f'retrieval incomplete: got only {read} out of {size} bytes', result)
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
def download(url: str, destination: str) -> Union[None, Exception]:
|
def download(url: str, destination: str) -> None | Exception:
|
||||||
"""
|
"""
|
||||||
Download from given url and save into given destination.
|
Download from given url and save into given destination.
|
||||||
"""
|
"""
|
||||||
@@ -725,7 +717,7 @@ class ToolBinaryError(RuntimeError):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class IDFToolDownload(object):
|
class IDFToolDownload:
|
||||||
"""
|
"""
|
||||||
Structure to store all the relevant information about particular download.
|
Structure to store all the relevant information about particular download.
|
||||||
"""
|
"""
|
||||||
@@ -739,7 +731,7 @@ class IDFToolDownload(object):
|
|||||||
|
|
||||||
|
|
||||||
@functools.total_ordering
|
@functools.total_ordering
|
||||||
class IDFToolVersion(object):
|
class IDFToolVersion:
|
||||||
"""
|
"""
|
||||||
Used for storing information about version; status (recommended, supported, deprecated)
|
Used for storing information about version; status (recommended, supported, deprecated)
|
||||||
and easy way of comparing different versions. Also allows platform compatibility check
|
and easy way of comparing different versions. Also allows platform compatibility check
|
||||||
@@ -778,7 +770,7 @@ class IDFToolVersion(object):
|
|||||||
"""
|
"""
|
||||||
self.downloads[platform_name] = IDFToolDownload(platform_name, url, size, sha256, rename_dist)
|
self.downloads[platform_name] = IDFToolDownload(platform_name, url, size, sha256, rename_dist)
|
||||||
|
|
||||||
def get_download_for_platform(self, platform_name: Optional[str]) -> Optional[IDFToolDownload]:
|
def get_download_for_platform(self, platform_name: str | None) -> IDFToolDownload | None:
|
||||||
"""
|
"""
|
||||||
Get download for given platform if usable download already exists.
|
Get download for given platform if usable download already exists.
|
||||||
"""
|
"""
|
||||||
@@ -793,13 +785,13 @@ class IDFToolVersion(object):
|
|||||||
return self.downloads['any']
|
return self.downloads['any']
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def compatible_with_platform(self, platform_name: Optional[str] = PYTHON_PLATFORM) -> bool:
|
def compatible_with_platform(self, platform_name: str | None = PYTHON_PLATFORM) -> bool:
|
||||||
"""
|
"""
|
||||||
Check whether this version is compatible with given platform name.
|
Check whether this version is compatible with given platform name.
|
||||||
"""
|
"""
|
||||||
return self.get_download_for_platform(platform_name) is not None
|
return self.get_download_for_platform(platform_name) is not None
|
||||||
|
|
||||||
def get_supported_platforms(self) -> Set[str]:
|
def get_supported_platforms(self) -> set[str]:
|
||||||
"""
|
"""
|
||||||
Get all platforms for which this version has a valid download record.
|
Get all platforms for which this version has a valid download record.
|
||||||
"""
|
"""
|
||||||
@@ -825,7 +817,7 @@ IDFToolOptions = namedtuple(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class IDFTool(object):
|
class IDFTool:
|
||||||
"""
|
"""
|
||||||
Used to store info about IDF tools from tools.json file in a Python-accesible form.
|
Used to store info about IDF tools from tools.json file in a Python-accesible form.
|
||||||
The term "IDF tool" is used for e.g. CMake, ninja, QUEMU and toolchains.
|
The term "IDF tool" is used for e.g. CMake, ninja, QUEMU and toolchains.
|
||||||
@@ -843,10 +835,10 @@ class IDFTool(object):
|
|||||||
install: str,
|
install: str,
|
||||||
info_url: str,
|
info_url: str,
|
||||||
lic: str,
|
lic: str,
|
||||||
version_cmd: List[str],
|
version_cmd: list[str],
|
||||||
version_regex: str,
|
version_regex: str,
|
||||||
supported_targets: List[str],
|
supported_targets: list[str],
|
||||||
version_regex_replace: Optional[str] = None,
|
version_regex_replace: str | None = None,
|
||||||
strip_container_dirs: int = 0,
|
strip_container_dirs: int = 0,
|
||||||
is_executable: bool = True,
|
is_executable: bool = True,
|
||||||
tool_info_file: str = '',
|
tool_info_file: str = '',
|
||||||
@@ -854,8 +846,8 @@ class IDFTool(object):
|
|||||||
self.name = name
|
self.name = name
|
||||||
self.description = description
|
self.description = description
|
||||||
self.drop_versions()
|
self.drop_versions()
|
||||||
self.version_in_path: Optional[str] = None
|
self.version_in_path: str | None = None
|
||||||
self.versions_installed: List[str] = []
|
self.versions_installed: list[str] = []
|
||||||
if version_regex_replace is None:
|
if version_regex_replace is None:
|
||||||
version_regex_replace = VERSION_REGEX_REPLACE_DEFAULT
|
version_regex_replace = VERSION_REGEX_REPLACE_DEFAULT
|
||||||
self.options = IDFToolOptions(
|
self.options = IDFToolOptions(
|
||||||
@@ -872,7 +864,7 @@ class IDFTool(object):
|
|||||||
strip_container_dirs,
|
strip_container_dirs,
|
||||||
supported_targets,
|
supported_targets,
|
||||||
) # type: ignore
|
) # type: ignore
|
||||||
self.platform_overrides: List[Dict[str, str]] = []
|
self.platform_overrides: list[dict[str, str]] = []
|
||||||
self._platform = CURRENT_PLATFORM
|
self._platform = CURRENT_PLATFORM
|
||||||
self._update_current_options()
|
self._update_current_options()
|
||||||
self.is_executable = is_executable
|
self.is_executable = is_executable
|
||||||
@@ -903,7 +895,7 @@ class IDFTool(object):
|
|||||||
"""
|
"""
|
||||||
Clear self.versions dictionary.
|
Clear self.versions dictionary.
|
||||||
"""
|
"""
|
||||||
self.versions: Dict[str, IDFToolVersion] = OrderedDict()
|
self.versions: dict[str, IDFToolVersion] = OrderedDict()
|
||||||
|
|
||||||
def add_version(self, version: IDFToolVersion) -> None:
|
def add_version(self, version: IDFToolVersion) -> None:
|
||||||
"""
|
"""
|
||||||
@@ -925,14 +917,14 @@ class IDFTool(object):
|
|||||||
assert version in self.versions
|
assert version in self.versions
|
||||||
return os.path.join(self.get_path(), version)
|
return os.path.join(self.get_path(), version)
|
||||||
|
|
||||||
def get_export_paths(self, version: str) -> List[str]:
|
def get_export_paths(self, version: str) -> list[str]:
|
||||||
"""
|
"""
|
||||||
Returns a list of paths that need to be exported.
|
Returns a list of paths that need to be exported.
|
||||||
"""
|
"""
|
||||||
tool_path = self.get_path_for_version(version)
|
tool_path = self.get_path_for_version(version)
|
||||||
return [os.path.join(tool_path, *p) for p in self._current_options.export_paths] # type: ignore
|
return [os.path.join(tool_path, *p) for p in self._current_options.export_paths] # type: ignore
|
||||||
|
|
||||||
def get_export_vars(self, version: str) -> Dict[str, str]:
|
def get_export_vars(self, version: str) -> dict[str, str]:
|
||||||
"""
|
"""
|
||||||
Get the dictionary of environment variables to be exported, for the given version.
|
Get the dictionary of environment variables to be exported, for the given version.
|
||||||
Expands:
|
Expands:
|
||||||
@@ -960,7 +952,7 @@ class IDFTool(object):
|
|||||||
return UNKNOWN_VERSION
|
return UNKNOWN_VERSION
|
||||||
return re.sub(self._current_options.version_regex, self._current_options.version_regex_replace, match.group(0)) # type: ignore
|
return re.sub(self._current_options.version_regex, self._current_options.version_regex_replace, match.group(0)) # type: ignore
|
||||||
|
|
||||||
def get_version(self, extra_paths: Optional[List[str]] = None, executable_path: Optional[str] = None) -> str:
|
def get_version(self, extra_paths: list[str] | None = None, executable_path: str | None = None) -> str:
|
||||||
"""
|
"""
|
||||||
Execute the tool, optionally prepending extra_paths to PATH,
|
Execute the tool, optionally prepending extra_paths to PATH,
|
||||||
extract the version string and return it as a result.
|
extract the version string and return it as a result.
|
||||||
@@ -1005,7 +997,7 @@ class IDFTool(object):
|
|||||||
info_file_path = os.path.join(self.get_path_for_version(version), info_file_path)
|
info_file_path = os.path.join(self.get_path_for_version(version), info_file_path)
|
||||||
if not os.path.exists(info_file_path):
|
if not os.path.exists(info_file_path):
|
||||||
raise ToolNotFoundError(f'Tool {self.name} not found: No info file.')
|
raise ToolNotFoundError(f'Tool {self.name} not found: No info file.')
|
||||||
with open(info_file_path, 'r', encoding='utf-8') as f:
|
with open(info_file_path, encoding='utf-8') as f:
|
||||||
try:
|
try:
|
||||||
tool_info = json.load(f)
|
tool_info = json.load(f)
|
||||||
except (json.JSONDecodeError, UnicodeDecodeError):
|
except (json.JSONDecodeError, UnicodeDecodeError):
|
||||||
@@ -1032,7 +1024,7 @@ class IDFTool(object):
|
|||||||
warn(f'tool {self.name} version {version} is installed, but reporting version {ver_str}')
|
warn(f'tool {self.name} version {version} is installed, but reporting version {ver_str}')
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def check_version(self, executable_path: Optional[str]) -> bool:
|
def check_version(self, executable_path: str | None) -> bool:
|
||||||
"""
|
"""
|
||||||
Check if tool's version from executable path is in self.version dictionary.
|
Check if tool's version from executable path is in self.version dictionary.
|
||||||
"""
|
"""
|
||||||
@@ -1045,13 +1037,13 @@ class IDFTool(object):
|
|||||||
"""
|
"""
|
||||||
return self._current_options.install # type: ignore
|
return self._current_options.install # type: ignore
|
||||||
|
|
||||||
def get_supported_targets(self) -> List[str]:
|
def get_supported_targets(self) -> list[str]:
|
||||||
"""
|
"""
|
||||||
Returns list of supported targets with current options.
|
Returns list of supported targets with current options.
|
||||||
"""
|
"""
|
||||||
return self._current_options.supported_targets # type: ignore
|
return self._current_options.supported_targets # type: ignore
|
||||||
|
|
||||||
def is_supported_for_any_of_targets(self, targets: List[str]) -> bool:
|
def is_supported_for_any_of_targets(self, targets: list[str]) -> bool:
|
||||||
"""
|
"""
|
||||||
Checks whether the tool is suitable for at least one of the specified targets.
|
Checks whether the tool is suitable for at least one of the specified targets.
|
||||||
"""
|
"""
|
||||||
@@ -1064,7 +1056,7 @@ class IDFTool(object):
|
|||||||
"""
|
"""
|
||||||
return any([v.compatible_with_platform() for v in self.versions.values()])
|
return any([v.compatible_with_platform() for v in self.versions.values()])
|
||||||
|
|
||||||
def get_supported_platforms(self) -> Set[str]:
|
def get_supported_platforms(self) -> set[str]:
|
||||||
"""
|
"""
|
||||||
Return set of platforms that are supported by at least one version of the tool.
|
Return set of platforms that are supported by at least one version of the tool.
|
||||||
"""
|
"""
|
||||||
@@ -1073,7 +1065,7 @@ class IDFTool(object):
|
|||||||
result.update(v.get_supported_platforms())
|
result.update(v.get_supported_platforms())
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def get_recommended_version(self) -> Optional[str]:
|
def get_recommended_version(self) -> str | None:
|
||||||
"""
|
"""
|
||||||
Get all recommended versions of the tool. If more versions are recommended, highest version is returned.
|
Get all recommended versions of the tool. If more versions are recommended, highest version is returned.
|
||||||
"""
|
"""
|
||||||
@@ -1087,7 +1079,7 @@ class IDFTool(object):
|
|||||||
return recommended_versions[0]
|
return recommended_versions[0]
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def get_preferred_installed_version(self) -> Optional[str]:
|
def get_preferred_installed_version(self) -> str | None:
|
||||||
"""
|
"""
|
||||||
Get the preferred installed version of the tool.
|
Get the preferred installed version of the tool.
|
||||||
If more versions installed, return recommended version if exists, otherwise return the highest supported version
|
If more versions installed, return recommended version if exists, otherwise return the highest supported version
|
||||||
@@ -1176,7 +1168,7 @@ class IDFTool(object):
|
|||||||
if tool_error:
|
if tool_error:
|
||||||
raise ToolBinaryError
|
raise ToolBinaryError
|
||||||
|
|
||||||
def latest_installed_version(self) -> Optional[str]:
|
def latest_installed_version(self) -> str | None:
|
||||||
"""
|
"""
|
||||||
Get the latest installed tool version by directly checking the
|
Get the latest installed tool version by directly checking the
|
||||||
tool's version directories.
|
tool's version directories.
|
||||||
@@ -1286,7 +1278,7 @@ class IDFTool(object):
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_json(cls, tool_dict: Dict[str, Union[str, List[str], Dict[str, str]]]) -> 'IDFTool':
|
def from_json(cls, tool_dict: dict[str, str | list[str] | dict[str, str]]) -> 'IDFTool':
|
||||||
"""
|
"""
|
||||||
Create IDFTool class instance form its JSON dump.
|
Create IDFTool class instance form its JSON dump.
|
||||||
"""
|
"""
|
||||||
@@ -1356,7 +1348,7 @@ class IDFTool(object):
|
|||||||
raise RuntimeError(f'supported_targets for tool {tool_name} is not a list of strings')
|
raise RuntimeError(f'supported_targets for tool {tool_name} is not a list of strings')
|
||||||
|
|
||||||
# Create the object
|
# Create the object
|
||||||
tool_obj: 'IDFTool' = cls(
|
tool_obj: IDFTool = cls(
|
||||||
tool_name,
|
tool_name,
|
||||||
description,
|
description,
|
||||||
install,
|
install,
|
||||||
@@ -1380,40 +1372,34 @@ class IDFTool(object):
|
|||||||
for index, override in enumerate(overrides_list):
|
for index, override in enumerate(overrides_list):
|
||||||
platforms_list = override.get('platforms') # type: ignore
|
platforms_list = override.get('platforms') # type: ignore
|
||||||
if type(platforms_list) is not list:
|
if type(platforms_list) is not list:
|
||||||
raise RuntimeError('platforms for override %d of tool %s is not a list' % (index, tool_name))
|
raise RuntimeError(f'platforms for override {index} of tool {tool_name} is not a list')
|
||||||
|
|
||||||
install = override.get('install') # type: ignore
|
install = override.get('install') # type: ignore
|
||||||
if install is not None and not isinstance(install, str):
|
if install is not None and not isinstance(install, str):
|
||||||
raise RuntimeError('install for override %d of tool %s is not a string' % (index, tool_name))
|
raise RuntimeError(f'install for override {index} of tool {tool_name} is not a string')
|
||||||
|
|
||||||
version_cmd = override.get('version_cmd') # type: ignore
|
version_cmd = override.get('version_cmd') # type: ignore
|
||||||
if version_cmd is not None and type(version_cmd) is not list:
|
if version_cmd is not None and type(version_cmd) is not list:
|
||||||
raise RuntimeError(
|
raise RuntimeError(f'version_cmd for override {index} of tool {tool_name} is not a list of strings')
|
||||||
'version_cmd for override %d of tool %s is not a list of strings' % (index, tool_name)
|
|
||||||
)
|
|
||||||
|
|
||||||
version_regex = override.get('version_regex') # type: ignore
|
version_regex = override.get('version_regex') # type: ignore
|
||||||
if version_regex is not None and (not isinstance(version_regex, str) or not version_regex):
|
if version_regex is not None and (not isinstance(version_regex, str) or not version_regex):
|
||||||
raise RuntimeError(
|
raise RuntimeError(f'version_regex for override {index} of tool {tool_name} is not a non-empty string')
|
||||||
'version_regex for override %d of tool %s is not a non-empty string' % (index, tool_name)
|
|
||||||
)
|
|
||||||
|
|
||||||
version_regex_replace = override.get('version_regex_replace') # type: ignore
|
version_regex_replace = override.get('version_regex_replace') # type: ignore
|
||||||
if version_regex_replace is not None and not isinstance(version_regex_replace, str):
|
if version_regex_replace is not None and not isinstance(version_regex_replace, str):
|
||||||
raise RuntimeError(
|
raise RuntimeError(f'version_regex_replace for override {index} of tool {tool_name} is not a string')
|
||||||
'version_regex_replace for override %d of tool %s is not a string' % (index, tool_name)
|
|
||||||
)
|
|
||||||
|
|
||||||
export_paths = override.get('export_paths') # type: ignore
|
export_paths = override.get('export_paths') # type: ignore
|
||||||
if export_paths is not None and type(export_paths) is not list:
|
if export_paths is not None and type(export_paths) is not list:
|
||||||
raise RuntimeError('export_paths for override %d of tool %s is not a list' % (index, tool_name))
|
raise RuntimeError(f'export_paths for override {index} of tool {tool_name} is not a list')
|
||||||
|
|
||||||
export_vars = override.get('export_vars') # type: ignore
|
export_vars = override.get('export_vars') # type: ignore
|
||||||
if export_vars is not None and type(export_vars) is not dict:
|
if export_vars is not None and type(export_vars) is not dict:
|
||||||
raise RuntimeError('export_vars for override %d of tool %s is not a mapping' % (index, tool_name))
|
raise RuntimeError(f'export_vars for override {index} of tool {tool_name} is not a mapping')
|
||||||
tool_obj.platform_overrides.append(override) # type: ignore
|
tool_obj.platform_overrides.append(override) # type: ignore
|
||||||
|
|
||||||
recommended_versions: Dict[str, List[str]] = {}
|
recommended_versions: dict[str, list[str]] = {}
|
||||||
for version_dict in versions: # type: ignore
|
for version_dict in versions: # type: ignore
|
||||||
version = version_dict.get('name') # type: ignore
|
version = version_dict.get('name') # type: ignore
|
||||||
if not isinstance(version, str):
|
if not isinstance(version, str):
|
||||||
@@ -1432,7 +1418,7 @@ class IDFTool(object):
|
|||||||
try:
|
try:
|
||||||
Platforms.get(platform_id)
|
Platforms.get(platform_id)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
raise RuntimeError('invalid platform %s for tool %s version %s' % (platform_id, tool_name, version))
|
raise RuntimeError(f'invalid platform {platform_id} for tool {tool_name} version {version}')
|
||||||
|
|
||||||
version_obj.add_download(
|
version_obj.add_download(
|
||||||
platform_id,
|
platform_id,
|
||||||
@@ -1532,8 +1518,8 @@ class IDFRecord:
|
|||||||
def __init__(self) -> None:
|
def __init__(self) -> None:
|
||||||
self.version: str = ''
|
self.version: str = ''
|
||||||
self.path: str = ''
|
self.path: str = ''
|
||||||
self._features: List[str] = ['core']
|
self._features: list[str] = ['core']
|
||||||
self._targets: List[str] = []
|
self._targets: list[str] = []
|
||||||
|
|
||||||
def __iter__(self): # type: ignore
|
def __iter__(self): # type: ignore
|
||||||
yield from {
|
yield from {
|
||||||
@@ -1560,10 +1546,10 @@ class IDFRecord:
|
|||||||
return not self.__eq__(other)
|
return not self.__eq__(other)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def features(self) -> List[str]:
|
def features(self) -> list[str]:
|
||||||
return self._features
|
return self._features
|
||||||
|
|
||||||
def update_features(self, add: Tuple[str, ...] = (), remove: Tuple[str, ...] = ()) -> None:
|
def update_features(self, add: tuple[str, ...] = (), remove: tuple[str, ...] = ()) -> None:
|
||||||
# Update features, but maintain required feature 'core'
|
# Update features, but maintain required feature 'core'
|
||||||
# If the same feature is present in both argument's tuples, do not update this feature
|
# If the same feature is present in both argument's tuples, do not update this feature
|
||||||
add_set = set(add)
|
add_set = set(add)
|
||||||
@@ -1583,7 +1569,7 @@ class IDFRecord:
|
|||||||
Check if feature requirements files exist.
|
Check if feature requirements files exist.
|
||||||
If not, remove the feature from the features list.
|
If not, remove the feature from the features list.
|
||||||
"""
|
"""
|
||||||
features_to_remove: Tuple[str, ...] = ()
|
features_to_remove: tuple[str, ...] = ()
|
||||||
for feature in self._features:
|
for feature in self._features:
|
||||||
if not os.path.isfile(feature_to_requirements_path(feature)):
|
if not os.path.isfile(feature_to_requirements_path(feature)):
|
||||||
info(
|
info(
|
||||||
@@ -1598,10 +1584,10 @@ class IDFRecord:
|
|||||||
self.update_features(remove=features_to_remove)
|
self.update_features(remove=features_to_remove)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def targets(self) -> List[str]:
|
def targets(self) -> list[str]:
|
||||||
return self._targets
|
return self._targets
|
||||||
|
|
||||||
def extend_targets(self, targets: List[str]) -> None:
|
def extend_targets(self, targets: list[str]) -> None:
|
||||||
# Targets can be only updated, but always maintain existing targets.
|
# Targets can be only updated, but always maintain existing targets.
|
||||||
self._targets = list(set(targets + self._targets))
|
self._targets = list(set(targets + self._targets))
|
||||||
|
|
||||||
@@ -1613,7 +1599,7 @@ class IDFRecord:
|
|||||||
return idf_record_obj
|
return idf_record_obj
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_idf_record_from_dict(cls, record_dict: Dict[str, Any]) -> 'IDFRecord':
|
def get_idf_record_from_dict(cls, record_dict: dict[str, Any]) -> 'IDFRecord':
|
||||||
idf_record_obj = cls()
|
idf_record_obj = cls()
|
||||||
try:
|
try:
|
||||||
idf_record_obj.version = record_dict['version']
|
idf_record_obj.version = record_dict['version']
|
||||||
@@ -1640,7 +1626,7 @@ class IDFEnv:
|
|||||||
|
|
||||||
def __init__(self) -> None:
|
def __init__(self) -> None:
|
||||||
active_idf_id = active_repo_id()
|
active_idf_id = active_repo_id()
|
||||||
self.idf_installed: Dict[str, IDFRecord] = {active_idf_id: IDFRecord.get_active_idf_record()}
|
self.idf_installed: dict[str, IDFRecord] = {active_idf_id: IDFRecord.get_active_idf_record()}
|
||||||
|
|
||||||
def __iter__(self): # type: ignore
|
def __iter__(self): # type: ignore
|
||||||
yield from {
|
yield from {
|
||||||
@@ -1667,7 +1653,7 @@ class IDFEnv:
|
|||||||
with open(idf_env_file_path, 'w', encoding='utf-8') as w:
|
with open(idf_env_file_path, 'w', encoding='utf-8') as w:
|
||||||
info(f'Updating {idf_env_file_path}')
|
info(f'Updating {idf_env_file_path}')
|
||||||
json.dump(dict(self), w, cls=IDFEnvEncoder, ensure_ascii=False, indent=4) # type: ignore
|
json.dump(dict(self), w, cls=IDFEnvEncoder, ensure_ascii=False, indent=4) # type: ignore
|
||||||
except (IOError, OSError):
|
except OSError:
|
||||||
if not os.access(g.idf_tools_path, os.W_OK):
|
if not os.access(g.idf_tools_path, os.W_OK):
|
||||||
raise OSError(
|
raise OSError(
|
||||||
f'IDF_TOOLS_PATH {g.idf_tools_path} is not accessible to write. '
|
f'IDF_TOOLS_PATH {g.idf_tools_path} is not accessible to write. '
|
||||||
@@ -1690,7 +1676,7 @@ class IDFEnv:
|
|||||||
idf_env_obj = cls()
|
idf_env_obj = cls()
|
||||||
try:
|
try:
|
||||||
idf_env_file_path = os.path.join(g.idf_tools_path, IDF_ENV_FILE)
|
idf_env_file_path = os.path.join(g.idf_tools_path, IDF_ENV_FILE)
|
||||||
with open(idf_env_file_path, 'r', encoding='utf-8') as idf_env_file:
|
with open(idf_env_file_path, encoding='utf-8') as idf_env_file:
|
||||||
idf_env_json = json.load(idf_env_file)
|
idf_env_json = json.load(idf_env_file)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@@ -1702,7 +1688,7 @@ class IDFEnv:
|
|||||||
else:
|
else:
|
||||||
# Load and verify ESP-IDF records found in IDF_ENV_FILE
|
# Load and verify ESP-IDF records found in IDF_ENV_FILE
|
||||||
idf_installed.pop('sha', None)
|
idf_installed.pop('sha', None)
|
||||||
idf_installed_verified: Dict[str, IDFRecord] = {}
|
idf_installed_verified: dict[str, IDFRecord] = {}
|
||||||
for idf in idf_installed:
|
for idf in idf_installed:
|
||||||
try:
|
try:
|
||||||
idf_installed_verified[idf] = IDFRecord.get_idf_record_from_dict(idf_installed[idf])
|
idf_installed_verified[idf] = IDFRecord.get_idf_record_from_dict(idf_installed[idf])
|
||||||
@@ -1713,7 +1699,7 @@ class IDFEnv:
|
|||||||
# If the active record is already in idf_installed, it is not overwritten
|
# If the active record is already in idf_installed, it is not overwritten
|
||||||
idf_env_obj.idf_installed = dict(idf_env_obj.idf_installed, **idf_installed_verified)
|
idf_env_obj.idf_installed = dict(idf_env_obj.idf_installed, **idf_installed_verified)
|
||||||
|
|
||||||
except (IOError, OSError, ValueError):
|
except (OSError, ValueError):
|
||||||
# If no, empty or not-accessible to read IDF_ENV_FILE found, use default values from constructor
|
# If no, empty or not-accessible to read IDF_ENV_FILE found, use default values from constructor
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@@ -1737,7 +1723,7 @@ class ENVState:
|
|||||||
deactivate_file_path = os.environ.get(env_key, '')
|
deactivate_file_path = os.environ.get(env_key, '')
|
||||||
|
|
||||||
def __init__(self) -> None:
|
def __init__(self) -> None:
|
||||||
self.idf_variables: Dict[str, Any] = {}
|
self.idf_variables: dict[str, Any] = {}
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_env_state(cls) -> 'ENVState':
|
def get_env_state(cls) -> 'ENVState':
|
||||||
@@ -1745,9 +1731,9 @@ class ENVState:
|
|||||||
|
|
||||||
if cls.deactivate_file_path:
|
if cls.deactivate_file_path:
|
||||||
try:
|
try:
|
||||||
with open(cls.deactivate_file_path, 'r', encoding='utf-8') as fp:
|
with open(cls.deactivate_file_path, encoding='utf-8') as fp:
|
||||||
env_state_obj.idf_variables = json.load(fp)
|
env_state_obj.idf_variables = json.load(fp)
|
||||||
except (IOError, OSError, ValueError):
|
except (OSError, ValueError):
|
||||||
pass
|
pass
|
||||||
return env_state_obj
|
return env_state_obj
|
||||||
|
|
||||||
@@ -1760,7 +1746,7 @@ class ENVState:
|
|||||||
with tempfile.NamedTemporaryFile(delete=False, suffix=f'idf_{str(os.getppid())}') as fp:
|
with tempfile.NamedTemporaryFile(delete=False, suffix=f'idf_{str(os.getppid())}') as fp:
|
||||||
self.deactivate_file_path = fp.name
|
self.deactivate_file_path = fp.name
|
||||||
fp.write(json.dumps(self.idf_variables, ensure_ascii=False, indent=4).encode('utf-8'))
|
fp.write(json.dumps(self.idf_variables, ensure_ascii=False, indent=4).encode('utf-8'))
|
||||||
except (IOError, OSError):
|
except OSError:
|
||||||
warn(
|
warn(
|
||||||
f'File storing IDF env variables {self.deactivate_file_path} is not accessible to write. '
|
f'File storing IDF env variables {self.deactivate_file_path} is not accessible to write. '
|
||||||
'Potentional switching ESP-IDF versions may cause problems'
|
'Potentional switching ESP-IDF versions may cause problems'
|
||||||
@@ -1768,14 +1754,14 @@ class ENVState:
|
|||||||
return self.deactivate_file_path
|
return self.deactivate_file_path
|
||||||
|
|
||||||
|
|
||||||
def load_tools_info() -> Dict[str, IDFTool]:
|
def load_tools_info() -> dict[str, IDFTool]:
|
||||||
"""
|
"""
|
||||||
Load tools metadata from tools.json, return a dictionary: tool name - tool info.
|
Load tools metadata from tools.json, return a dictionary: tool name - tool info.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
tool_versions_file_name = g.tools_json
|
tool_versions_file_name = g.tools_json
|
||||||
|
|
||||||
with open(tool_versions_file_name, 'r', encoding='utf-8') as f: # type: ignore
|
with open(tool_versions_file_name, encoding='utf-8') as f: # type: ignore
|
||||||
tools_info = json.load(f)
|
tools_info = json.load(f)
|
||||||
|
|
||||||
return parse_tools_info_json(tools_info) # type: ignore
|
return parse_tools_info_json(tools_info) # type: ignore
|
||||||
@@ -1799,7 +1785,7 @@ def parse_tools_info_json(tools_info): # type: ignore
|
|||||||
return tools_dict
|
return tools_dict
|
||||||
|
|
||||||
|
|
||||||
def dump_tools_json(tools_info: Optional[Dict[str, IDFTool]]): # type: ignore
|
def dump_tools_json(tools_info: dict[str, IDFTool] | None): # type: ignore
|
||||||
"""
|
"""
|
||||||
Dump all the tools into JSON.
|
Dump all the tools into JSON.
|
||||||
"""
|
"""
|
||||||
@@ -1814,7 +1800,7 @@ def dump_tools_json(tools_info: Optional[Dict[str, IDFTool]]): # type: ignore
|
|||||||
return json.dumps({}, indent=2, separators=(',', ': '), sort_keys=True)
|
return json.dumps({}, indent=2, separators=(',', ': '), sort_keys=True)
|
||||||
|
|
||||||
|
|
||||||
def get_python_exe_and_subdir() -> Tuple[str, str]:
|
def get_python_exe_and_subdir() -> tuple[str, str]:
|
||||||
"""
|
"""
|
||||||
Returns:
|
Returns:
|
||||||
* python executable name (python on Unix, python.exe on Win)
|
* python executable name (python on Unix, python.exe on Win)
|
||||||
@@ -1833,11 +1819,11 @@ def get_idf_version() -> str:
|
|||||||
"""
|
"""
|
||||||
Return ESP-IDF version.
|
Return ESP-IDF version.
|
||||||
"""
|
"""
|
||||||
idf_version: Optional[str] = None
|
idf_version: str | None = None
|
||||||
|
|
||||||
version_file_path = os.path.join(g.idf_path, 'version.txt')
|
version_file_path = os.path.join(g.idf_path, 'version.txt')
|
||||||
if os.path.exists(version_file_path):
|
if os.path.exists(version_file_path):
|
||||||
with open(version_file_path, 'r', encoding='utf-8') as version_file:
|
with open(version_file_path, encoding='utf-8') as version_file:
|
||||||
idf_version_str = version_file.read()
|
idf_version_str = version_file.read()
|
||||||
|
|
||||||
match = re.match(r'^v([0-9]+\.[0-9]+).*', idf_version_str)
|
match = re.match(r'^v([0-9]+\.[0-9]+).*', idf_version_str)
|
||||||
@@ -1865,7 +1851,7 @@ def get_idf_version() -> str:
|
|||||||
return idf_version
|
return idf_version
|
||||||
|
|
||||||
|
|
||||||
def get_python_env_path() -> Tuple[str, str, str, str]:
|
def get_python_env_path() -> tuple[str, str, str, str]:
|
||||||
"""
|
"""
|
||||||
Returns tuple of Python environment path, Python env. path with subdir and
|
Returns tuple of Python environment path, Python env. path with subdir and
|
||||||
full path from Python (i.e. with executable).
|
full path from Python (i.e. with executable).
|
||||||
@@ -1882,7 +1868,7 @@ def get_python_env_path() -> Tuple[str, str, str, str]:
|
|||||||
return idf_python_env_path, idf_python_export_path, virtualenv_python, idf_version
|
return idf_python_env_path, idf_python_export_path, virtualenv_python, idf_version
|
||||||
|
|
||||||
|
|
||||||
def parse_tools_arg(tools_str: List[str]) -> List[str]:
|
def parse_tools_arg(tools_str: list[str]) -> list[str]:
|
||||||
"""
|
"""
|
||||||
Base parsing "tools" arguments: all, required, etc.
|
Base parsing "tools" arguments: all, required, etc.
|
||||||
"""
|
"""
|
||||||
@@ -1892,7 +1878,7 @@ def parse_tools_arg(tools_str: List[str]) -> List[str]:
|
|||||||
return tools_str
|
return tools_str
|
||||||
|
|
||||||
|
|
||||||
def expand_tools_arg(tools_spec: List[str], overall_tools: OrderedDict, targets: List[str]) -> List[str]:
|
def expand_tools_arg(tools_spec: list[str], overall_tools: OrderedDict, targets: list[str]) -> list[str]:
|
||||||
"""
|
"""
|
||||||
Expand list of tools 'tools_spec' in according:
|
Expand list of tools 'tools_spec' in according:
|
||||||
- a tool is in the 'overall_tools' list
|
- a tool is in the 'overall_tools' list
|
||||||
@@ -1925,7 +1911,7 @@ def expand_tools_arg(tools_spec: List[str], overall_tools: OrderedDict, targets:
|
|||||||
return tools
|
return tools
|
||||||
|
|
||||||
|
|
||||||
def parse_targets_arg(targets_str: str) -> List[str]:
|
def parse_targets_arg(targets_str: str) -> list[str]:
|
||||||
"""
|
"""
|
||||||
Parse and check if targets_str is a valid list of targets and return a target list.
|
Parse and check if targets_str is a valid list of targets and return a target list.
|
||||||
"""
|
"""
|
||||||
@@ -1941,13 +1927,13 @@ def parse_targets_arg(targets_str: str) -> List[str]:
|
|||||||
if invalid_targets:
|
if invalid_targets:
|
||||||
warn(
|
warn(
|
||||||
f'Targets: "{", ".join(invalid_targets)}" are not supported. '
|
f'Targets: "{", ".join(invalid_targets)}" are not supported. '
|
||||||
'Only allowed options are: {", ".join(targets_from_tools_json)}.'
|
f'Only allowed options are: {", ".join(targets_from_tools_json)}.'
|
||||||
)
|
)
|
||||||
raise SystemExit(1)
|
raise SystemExit(1)
|
||||||
return targets
|
return targets
|
||||||
|
|
||||||
|
|
||||||
def add_and_check_targets(idf_env_obj: IDFEnv, targets_str: str) -> List[str]:
|
def add_and_check_targets(idf_env_obj: IDFEnv, targets_str: str) -> list[str]:
|
||||||
"""
|
"""
|
||||||
Define targets from targets_str, check that the target names are valid and add them to idf_env_obj.
|
Define targets from targets_str, check that the target names are valid and add them to idf_env_obj.
|
||||||
"""
|
"""
|
||||||
@@ -1963,7 +1949,7 @@ def feature_to_requirements_path(feature: str) -> str:
|
|||||||
return os.path.join(g.idf_path, 'tools', 'requirements', f'requirements.{feature}.txt')
|
return os.path.join(g.idf_path, 'tools', 'requirements', f'requirements.{feature}.txt')
|
||||||
|
|
||||||
|
|
||||||
def process_and_check_features(idf_env_obj: IDFEnv, features_str: str) -> List[str]:
|
def process_and_check_features(idf_env_obj: IDFEnv, features_str: str) -> list[str]:
|
||||||
"""
|
"""
|
||||||
Check whether new feature is valid. If yes, update features in active IDF record.
|
Check whether new feature is valid. If yes, update features in active IDF record.
|
||||||
"""
|
"""
|
||||||
@@ -1992,12 +1978,12 @@ def process_and_check_features(idf_env_obj: IDFEnv, features_str: str) -> List[s
|
|||||||
return idf_env_obj.get_active_idf_record().features
|
return idf_env_obj.get_active_idf_record().features
|
||||||
|
|
||||||
|
|
||||||
def get_all_targets_from_tools_json() -> List[str]:
|
def get_all_targets_from_tools_json() -> list[str]:
|
||||||
"""
|
"""
|
||||||
Returns list of all targets from tools.json file.
|
Returns list of all targets from tools.json file.
|
||||||
"""
|
"""
|
||||||
tools_info = load_tools_info()
|
tools_info = load_tools_info()
|
||||||
targets_from_tools_json: List[str] = []
|
targets_from_tools_json: list[str] = []
|
||||||
|
|
||||||
for _, v in tools_info.items():
|
for _, v in tools_info.items():
|
||||||
targets_from_tools_json.extend(v.get_supported_targets())
|
targets_from_tools_json.extend(v.get_supported_targets())
|
||||||
@@ -2008,7 +1994,7 @@ def get_all_targets_from_tools_json() -> List[str]:
|
|||||||
return sorted(targets_from_tools_json)
|
return sorted(targets_from_tools_json)
|
||||||
|
|
||||||
|
|
||||||
def filter_tools_info(idf_env_obj: IDFEnv, tools_info: Dict[str, IDFTool]) -> Dict[str, IDFTool]:
|
def filter_tools_info(idf_env_obj: IDFEnv, tools_info: dict[str, IDFTool]) -> dict[str, IDFTool]:
|
||||||
"""
|
"""
|
||||||
Filter tools info; return only those targets which:
|
Filter tools info; return only those targets which:
|
||||||
* are installable (install type is INSTALL_ALWAYS or INSTALL_ON_REQUEST)
|
* are installable (install type is INSTALL_ALWAYS or INSTALL_ON_REQUEST)
|
||||||
@@ -2027,7 +2013,7 @@ def filter_tools_info(idf_env_obj: IDFEnv, tools_info: Dict[str, IDFTool]) -> Di
|
|||||||
return OrderedDict(filtered_tools_spec)
|
return OrderedDict(filtered_tools_spec)
|
||||||
|
|
||||||
|
|
||||||
def add_variables_to_deactivate_file(args: List[str], new_idf_vars: Dict[str, Any]) -> str:
|
def add_variables_to_deactivate_file(args: list[str], new_idf_vars: dict[str, Any]) -> str:
|
||||||
"""
|
"""
|
||||||
Add IDF global variables that need to be removed when the active esp-idf environment is deactivated.
|
Add IDF global variables that need to be removed when the active esp-idf environment is deactivated.
|
||||||
"""
|
"""
|
||||||
@@ -2054,7 +2040,7 @@ def add_variables_to_deactivate_file(args: List[str], new_idf_vars: Dict[str, An
|
|||||||
return deactivate_file_path
|
return deactivate_file_path
|
||||||
|
|
||||||
|
|
||||||
def print_deactivate_statement(args: List[str]) -> None:
|
def print_deactivate_statement(args: list[str]) -> None:
|
||||||
"""
|
"""
|
||||||
Deactivate statement is sequence of commands, that remove IDF global variables from environment,
|
Deactivate statement is sequence of commands, that remove IDF global variables from environment,
|
||||||
so the environment gets to the state it was before calling export.{sh/fish} script.
|
so the environment gets to the state it was before calling export.{sh/fish} script.
|
||||||
@@ -2063,7 +2049,7 @@ def print_deactivate_statement(args: List[str]) -> None:
|
|||||||
if not env_state_obj.idf_variables:
|
if not env_state_obj.idf_variables:
|
||||||
return
|
return
|
||||||
unset_vars = env_state_obj.idf_variables
|
unset_vars = env_state_obj.idf_variables
|
||||||
env_path: Optional[str] = os.getenv('PATH')
|
env_path: str | None = os.getenv('PATH')
|
||||||
if env_path:
|
if env_path:
|
||||||
cleared_env_path = ':'.join([k for k in env_path.split(':') if k not in unset_vars['PATH']])
|
cleared_env_path = ':'.join([k for k in env_path.split(':') if k not in unset_vars['PATH']])
|
||||||
|
|
||||||
@@ -2083,14 +2069,14 @@ def print_deactivate_statement(args: List[str]) -> None:
|
|||||||
return
|
return
|
||||||
|
|
||||||
|
|
||||||
def get_export_format_and_separator(args: List[str]) -> Tuple[str, str]:
|
def get_export_format_and_separator(args: list[str]) -> tuple[str, str]:
|
||||||
"""
|
"""
|
||||||
Returns export pattern (formatted string) either for exporting in shell or as a key-value pair.
|
Returns export pattern (formatted string) either for exporting in shell or as a key-value pair.
|
||||||
"""
|
"""
|
||||||
return {EXPORT_SHELL: ('export {}="{}"', ';'), EXPORT_KEY_VALUE: ('{}={}', '\n')}[args.format] # type: ignore
|
return {EXPORT_SHELL: ('export {}="{}"', ';'), EXPORT_KEY_VALUE: ('{}={}', '\n')}[args.format] # type: ignore
|
||||||
|
|
||||||
|
|
||||||
def get_unset_format_and_separator(args: List[str]) -> Tuple[str, str]:
|
def get_unset_format_and_separator(args: list[str]) -> tuple[str, str]:
|
||||||
"""
|
"""
|
||||||
Returns pattern to unset a variable (formatted string) either for shell or for key-value pair.
|
Returns pattern to unset a variable (formatted string) either for shell or for key-value pair.
|
||||||
"""
|
"""
|
||||||
@@ -2209,7 +2195,7 @@ def handle_recommended_version_to_use(
|
|||||||
tool_name: str,
|
tool_name: str,
|
||||||
version_to_use: str,
|
version_to_use: str,
|
||||||
prefer_system_hint: str,
|
prefer_system_hint: str,
|
||||||
) -> Tuple[list, dict]:
|
) -> tuple[list, dict]:
|
||||||
"""
|
"""
|
||||||
If there is unsupported tools version in PATH, prints info about that.
|
If there is unsupported tools version in PATH, prints info about that.
|
||||||
"""
|
"""
|
||||||
@@ -2260,7 +2246,7 @@ def handle_missing_versions(tool: IDFTool, tool_name: str, install_cmd: str, pre
|
|||||||
|
|
||||||
def process_tool(
|
def process_tool(
|
||||||
tool: IDFTool, tool_name: str, args: argparse.Namespace, install_cmd: str, prefer_system_hint: str
|
tool: IDFTool, tool_name: str, args: argparse.Namespace, install_cmd: str, prefer_system_hint: str
|
||||||
) -> Tuple[list, dict, bool]:
|
) -> tuple[list, dict, bool]:
|
||||||
"""
|
"""
|
||||||
Helper function used only in action export.
|
Helper function used only in action export.
|
||||||
Returns:
|
Returns:
|
||||||
@@ -2269,8 +2255,8 @@ def process_tool(
|
|||||||
* Flag if any tool was found.
|
* Flag if any tool was found.
|
||||||
"""
|
"""
|
||||||
tool_found: bool = True
|
tool_found: bool = True
|
||||||
tool_export_paths: List[str] = []
|
tool_export_paths: list[str] = []
|
||||||
tool_export_vars: Dict[str, str] = {}
|
tool_export_vars: dict[str, str] = {}
|
||||||
|
|
||||||
recommended_version_to_use = tool.get_preferred_installed_version()
|
recommended_version_to_use = tool.get_preferred_installed_version()
|
||||||
|
|
||||||
@@ -2315,7 +2301,7 @@ def process_tool(
|
|||||||
|
|
||||||
def check_python_venv_compatibility(idf_python_env_path: str, idf_version: str) -> None:
|
def check_python_venv_compatibility(idf_python_env_path: str, idf_version: str) -> None:
|
||||||
try:
|
try:
|
||||||
with open(os.path.join(idf_python_env_path, VENV_VER_FILE), 'r', encoding='utf-8') as f:
|
with open(os.path.join(idf_python_env_path, VENV_VER_FILE), encoding='utf-8') as f:
|
||||||
read_idf_version = f.read().strip()
|
read_idf_version = f.read().strip()
|
||||||
if read_idf_version != idf_version:
|
if read_idf_version != idf_version:
|
||||||
fatal(
|
fatal(
|
||||||
@@ -2346,7 +2332,7 @@ def action_export(args: Any) -> None:
|
|||||||
tools_info = load_tools_info()
|
tools_info = load_tools_info()
|
||||||
tools_info = filter_tools_info(IDFEnv.get_idf_env(), tools_info)
|
tools_info = filter_tools_info(IDFEnv.get_idf_env(), tools_info)
|
||||||
all_tools_found = True
|
all_tools_found = True
|
||||||
export_vars: Dict[str, str] = {}
|
export_vars: dict[str, str] = {}
|
||||||
paths_to_export = []
|
paths_to_export = []
|
||||||
|
|
||||||
self_restart_cmd = f'{sys.executable} {__file__}{(" --tools-json {args.tools_json}") if args.tools_json else ""}'
|
self_restart_cmd = f'{sys.executable} {__file__}{(" --tools-json {args.tools_json}") if args.tools_json else ""}'
|
||||||
@@ -2415,7 +2401,7 @@ def action_export(args: Any) -> None:
|
|||||||
except ValueError:
|
except ValueError:
|
||||||
fatal(
|
fatal(
|
||||||
'Both of the directories (..\\idf-exe\\.. and ..\\tools) '
|
'Both of the directories (..\\idf-exe\\.. and ..\\tools) '
|
||||||
'has to be in the PATH:\n\n{paths_to_check}\n'
|
f'has to be in the PATH:\n\n{paths_to_check}\n'
|
||||||
)
|
)
|
||||||
|
|
||||||
if export_vars:
|
if export_vars:
|
||||||
@@ -2493,8 +2479,8 @@ def apply_github_assets_option(idf_download_url: str) -> str:
|
|||||||
|
|
||||||
|
|
||||||
def get_tools_spec_and_platform_info(
|
def get_tools_spec_and_platform_info(
|
||||||
selected_platform: str, targets: List[str], tools_spec: List[str], quiet: bool = False
|
selected_platform: str, targets: list[str], tools_spec: list[str], quiet: bool = False
|
||||||
) -> Tuple[List[str], Dict[str, IDFTool]]:
|
) -> tuple[list[str], dict[str, IDFTool]]:
|
||||||
"""
|
"""
|
||||||
Returns tools_spec list and dict of tools for selected platform in form tool_name : IDFTool object.
|
Returns tools_spec list and dict of tools for selected platform in form tool_name : IDFTool object.
|
||||||
NOTE: If this function is not called from action_download, but is used just for detecting active tools,
|
NOTE: If this function is not called from action_download, but is used just for detecting active tools,
|
||||||
@@ -2526,7 +2512,7 @@ def action_download(args): # type: ignore
|
|||||||
"""
|
"""
|
||||||
tools_spec = parse_tools_arg(args.tools)
|
tools_spec = parse_tools_arg(args.tools)
|
||||||
|
|
||||||
targets: List[str] = []
|
targets: list[str] = []
|
||||||
# Saving IDFEnv::targets for selected ESP_targets if all tools have been specified
|
# Saving IDFEnv::targets for selected ESP_targets if all tools have been specified
|
||||||
if 'required' in tools_spec or 'all' in tools_spec:
|
if 'required' in tools_spec or 'all' in tools_spec:
|
||||||
idf_env_obj = IDFEnv.get_idf_env()
|
idf_env_obj = IDFEnv.get_idf_env()
|
||||||
@@ -2579,7 +2565,7 @@ def action_install(args): # type: ignore
|
|||||||
"""
|
"""
|
||||||
tools_spec = parse_tools_arg(args.tools)
|
tools_spec = parse_tools_arg(args.tools)
|
||||||
|
|
||||||
targets: List[str] = []
|
targets: list[str] = []
|
||||||
# Saving IDFEnv::targets for selected ESP_targets if all tools have been specified
|
# Saving IDFEnv::targets for selected ESP_targets if all tools have been specified
|
||||||
if 'required' in tools_spec or 'all' in tools_spec:
|
if 'required' in tools_spec or 'all' in tools_spec:
|
||||||
idf_env_obj = IDFEnv.get_idf_env()
|
idf_env_obj = IDFEnv.get_idf_env()
|
||||||
@@ -2635,7 +2621,7 @@ def action_install(args): # type: ignore
|
|||||||
tool_obj.install(tool_version)
|
tool_obj.install(tool_version)
|
||||||
|
|
||||||
|
|
||||||
def get_wheels_dir() -> Optional[str]:
|
def get_wheels_dir() -> str | None:
|
||||||
"""
|
"""
|
||||||
Gets path for idf-python-wheels package.
|
Gets path for idf-python-wheels package.
|
||||||
"""
|
"""
|
||||||
@@ -2653,7 +2639,7 @@ def get_wheels_dir() -> Optional[str]:
|
|||||||
return wheels_dir
|
return wheels_dir
|
||||||
|
|
||||||
|
|
||||||
def get_requirements(new_features: str) -> List[str]:
|
def get_requirements(new_features: str) -> list[str]:
|
||||||
"""
|
"""
|
||||||
Returns list of path for requirements.txt for given feature list.
|
Returns list of path for requirements.txt for given feature list.
|
||||||
"""
|
"""
|
||||||
@@ -2904,10 +2890,10 @@ class ChecksumCalculator:
|
|||||||
A class used to get size/checksum/basename of local artifact files.
|
A class used to get size/checksum/basename of local artifact files.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, files: List[str]) -> None:
|
def __init__(self, files: list[str]) -> None:
|
||||||
self.files = files
|
self.files = files
|
||||||
|
|
||||||
def __iter__(self) -> Iterator[Tuple[int, str, str]]:
|
def __iter__(self) -> Iterator[tuple[int, str, str]]:
|
||||||
for f in self.files:
|
for f in self.files:
|
||||||
yield (*get_file_size_sha256(f), os.path.basename(f))
|
yield (*get_file_size_sha256(f), os.path.basename(f))
|
||||||
|
|
||||||
@@ -2939,7 +2925,7 @@ class ChecksumFileParser:
|
|||||||
sha256_file = sha256_file_tmp
|
sha256_file = sha256_file_tmp
|
||||||
download(url, sha256_file)
|
download(url, sha256_file)
|
||||||
|
|
||||||
with open(sha256_file, 'r', encoding='utf-8') as f:
|
with open(sha256_file, encoding='utf-8') as f:
|
||||||
self.checksum = f.read().splitlines()
|
self.checksum = f.read().splitlines()
|
||||||
|
|
||||||
# remove temp file
|
# remove temp file
|
||||||
@@ -2954,7 +2940,7 @@ class ChecksumFileParser:
|
|||||||
|
|
||||||
# parse checksum file with formatting used by crosstool-ng, gdb, ... releases
|
# parse checksum file with formatting used by crosstool-ng, gdb, ... releases
|
||||||
# e.g. https://github.com/espressif/crosstool-NG/releases/download/esp-2021r2/crosstool-NG-esp-2021r2-checksum.sha256
|
# e.g. https://github.com/espressif/crosstool-NG/releases/download/esp-2021r2/crosstool-NG-esp-2021r2-checksum.sha256
|
||||||
def __iter__(self) -> Iterator[Tuple[int, str, str]]:
|
def __iter__(self) -> Iterator[tuple[int, str, str]]:
|
||||||
try:
|
try:
|
||||||
for bytes_str, hash_str in zip(self.checksum[0::2], self.checksum[1::2]):
|
for bytes_str, hash_str in zip(self.checksum[0::2], self.checksum[1::2]):
|
||||||
bytes_filename = self.parseLine(r'^# (\S*):', bytes_str)
|
bytes_filename = self.parseLine(r'^# (\S*):', bytes_str)
|
||||||
@@ -3153,10 +3139,10 @@ def action_validate(args): # type: ignore
|
|||||||
fatal('You need to install jsonschema package to use validate command')
|
fatal('You need to install jsonschema package to use validate command')
|
||||||
raise SystemExit(1)
|
raise SystemExit(1)
|
||||||
|
|
||||||
with open(os.path.join(g.idf_path, TOOLS_FILE), 'r', encoding='utf-8') as tools_file:
|
with open(os.path.join(g.idf_path, TOOLS_FILE), encoding='utf-8') as tools_file:
|
||||||
tools_json = json.load(tools_file)
|
tools_json = json.load(tools_file)
|
||||||
|
|
||||||
with open(os.path.join(g.idf_path, TOOLS_SCHEMA_FILE), 'r', encoding='utf-8') as schema_file:
|
with open(os.path.join(g.idf_path, TOOLS_SCHEMA_FILE), encoding='utf-8') as schema_file:
|
||||||
schema_json = json.load(schema_file)
|
schema_json = json.load(schema_file)
|
||||||
jsonschema.validate(tools_json, schema_json)
|
jsonschema.validate(tools_json, schema_json)
|
||||||
# on failure, this will raise an exception with a fairly verbose diagnostic message
|
# on failure, this will raise an exception with a fairly verbose diagnostic message
|
||||||
@@ -3286,7 +3272,7 @@ def action_get_tool_supported_versions(args: Any) -> None:
|
|||||||
raise SystemExit(1)
|
raise SystemExit(1)
|
||||||
|
|
||||||
|
|
||||||
def main(argv: List[str]) -> None:
|
def main(argv: list[str]) -> None:
|
||||||
parser = argparse.ArgumentParser()
|
parser = argparse.ArgumentParser()
|
||||||
|
|
||||||
parser.add_argument('--quiet', help="Don't output diagnostic messages to stdout/stderr", action='store_true')
|
parser.add_argument('--quiet', help="Don't output diagnostic messages to stdout/stderr", action='store_true')
|
||||||
|
Reference in New Issue
Block a user