diff --git a/docs/en/get-started/index.rst b/docs/en/get-started/index.rst index 8365b5093a..fc5c4005d2 100644 --- a/docs/en/get-started/index.rst +++ b/docs/en/get-started/index.rst @@ -140,7 +140,7 @@ If you have one of {IDF_TARGET_NAME} development boards listed below, you can cl ESP32-S3-DevKitC-1 <../hw-reference/esp32s3/user-guide-devkitc-1> - + .. _get-started-step-by-step: @@ -251,14 +251,14 @@ If you want to install the tools without the help of ESP-IDF Tools Installer, op .. code-block:: batch cd %userprofile%\esp\esp-idf - install.bat + install.bat {IDF_TARGET_PATH_NAME} or with Windows PowerShell .. code-block:: powershell cd ~/esp/esp-idf - ./install.ps1 + ./install.ps1 {IDF_TARGET_PATH_NAME} Linux and macOS ~~~~~~~~~~~~~~~ @@ -266,7 +266,18 @@ Linux and macOS .. code-block:: bash cd ~/esp/esp-idf - ./install.sh + ./install.sh {IDF_TARGET_PATH_NAME} + +or with Fish shell + +.. code-block:: fish + + cd ~/esp/esp-idf + ./install.fish {IDF_TARGET_PATH_NAME} + +.. note:: + To install tools for multiple targets you can specify those targets at once. For example: ``./install.sh esp32,esp32c3,esp32s3``. + To install tools for all supported targets, run the script without specifying targets ``./install.sh`` or use ``./install.sh all``. Alternative File Downloads ~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/install.bat b/install.bat index 8b0958d8f4..8ca5ae0d16 100644 --- a/install.bat +++ b/install.bat @@ -18,8 +18,11 @@ if not "%MISSING_REQUIREMENTS%" == "" goto :error_missing_requirements set IDF_PATH=%~dp0 set IDF_PATH=%IDF_PATH:~0,-1% +set TARGETS="all" +if NOT "%1"=="" set TARGETS=%* + echo Installing ESP-IDF tools -python.exe %IDF_PATH%\tools\idf_tools.py install +python.exe %IDF_PATH%\tools\idf_tools.py install --targets=%TARGETS% if %errorlevel% neq 0 goto :end echo Setting up Python environment diff --git a/install.fish b/install.fish index 6d84017ba6..ead8adb222 100755 --- a/install.fish +++ b/install.fish @@ -7,8 +7,15 @@ set -x IDF_PATH $basedir echo "Detecting the Python interpreter" source "$IDF_PATH"/tools/detect_python.fish +if not set -q argv[1] + set TARGETS "all" +else + set TARGETS $argv[1] +end echo "Installing ESP-IDF tools" -"$ESP_PYTHON" "$IDF_PATH"/tools/idf_tools.py install +"$ESP_PYTHON" "$IDF_PATH"/tools/idf_tools.py install --targets=$TARGETS + exit 1 +end echo "Installing Python environment and packages" "$ESP_PYTHON" "$IDF_PATH"/tools/idf_tools.py install-python-env diff --git a/install.ps1 b/install.ps1 index df55bd3e2d..bcd020b95c 100644 --- a/install.ps1 +++ b/install.ps1 @@ -1,9 +1,14 @@ #!/usr/bin/env pwsh $IDF_PATH = $PSScriptRoot - +if($args.count -eq 0){ + $TARGETS = "all" +}else +{ + $TARGETS = $args[0] -join ',' +} Write-Output "Installing ESP-IDF tools" -Start-Process -Wait -NoNewWindow -FilePath "python" -Args "$IDF_PATH/tools/idf_tools.py install" +Start-Process -Wait -NoNewWindow -FilePath "python" -Args "$IDF_PATH/tools/idf_tools.py install --targets=${TARGETS}" if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } # if error Write-Output "Setting up Python environment" diff --git a/install.sh b/install.sh index 55d6feb009..ab37e78db7 100755 --- a/install.sh +++ b/install.sh @@ -8,8 +8,13 @@ export IDF_PATH=$(cd $(dirname $0); pwd) echo "Detecting the Python interpreter" . ${IDF_PATH}/tools/detect_python.sh +if [ "$#" -eq 0 ]; then + TARGETS="all" +else + TARGETS=$1 +fi echo "Installing ESP-IDF tools" -${ESP_PYTHON} ${IDF_PATH}/tools/idf_tools.py install +${ESP_PYTHON} ${IDF_PATH}/tools/idf_tools.py install --targets=${TARGETS} echo "Installing Python environment and packages" ${ESP_PYTHON} ${IDF_PATH}/tools/idf_tools.py install-python-env diff --git a/tools/idf_tools.py b/tools/idf_tools.py index 8aa013fcdf..a56591e2e1 100755 --- a/tools/idf_tools.py +++ b/tools/idf_tools.py @@ -59,7 +59,7 @@ except RuntimeError as e: print(e) raise SystemExit(1) -from typing import IO, Callable, Optional, Tuple, Union # noqa: F401 +from typing import IO, Any, Callable, Optional, Tuple, Union # noqa: F401 from urllib.error import ContentTooShortError from urllib.request import urlopen # the following is only for typing annotation @@ -76,6 +76,7 @@ except ImportError: TOOLS_FILE = 'tools/tools.json' TOOLS_SCHEMA_FILE = 'tools/tools_schema.json' TOOLS_FILE_NEW = 'tools/tools.new.json' +IDF_ENV_FILE = 'idf-env.json' TOOLS_FILE_VERSION = 1 IDF_TOOLS_PATH_DEFAULT = os.path.join('~', '.espressif') UNKNOWN_VERSION = 'unknown' @@ -482,7 +483,8 @@ OPTIONS_LIST = ['version_cmd', 'install', 'info_url', 'license', - 'strip_container_dirs'] + 'strip_container_dirs', + 'supported_targets'] IDFToolOptions = namedtuple('IDFToolOptions', OPTIONS_LIST) # type: ignore @@ -493,9 +495,9 @@ class IDFTool(object): INSTALL_ON_REQUEST = 'on_request' INSTALL_NEVER = 'never' - def __init__(self, name, description, install, info_url, license, version_cmd, version_regex, version_regex_replace=None, + def __init__(self, name, description, install, info_url, license, version_cmd, version_regex, supported_targets, version_regex_replace=None, strip_container_dirs=0): - # type: (str, str, str, str, str, list[str], str, Optional[str], int) -> None + # type: (str, str, str, str, str, list[str], str, list[str], Optional[str], int) -> None self.name = name self.description = description self.versions = OrderedDict() # type: dict[str, IDFToolVersion] @@ -504,7 +506,7 @@ class IDFTool(object): if version_regex_replace is None: version_regex_replace = VERSION_REGEX_REPLACE_DEFAULT self.options = IDFToolOptions(version_cmd, version_regex, version_regex_replace, - [], OrderedDict(), install, info_url, license, strip_container_dirs) # type: ignore + [], OrderedDict(), install, info_url, license, strip_container_dirs, supported_targets) # type: ignore self.platform_overrides = [] # type: list[dict[str, str]] self._platform = CURRENT_PLATFORM self._update_current_options() @@ -584,6 +586,9 @@ class IDFTool(object): def get_install_type(self): # type: () -> Callable[[str], None] return self._current_options.install # type: ignore + def get_supported_targets(self): # type: () -> list[str] + return self._current_options.supported_targets # type: ignore + def compatible_with_platform(self): # type: () -> bool return any([v.compatible_with_platform() for v in self.versions.values()]) @@ -797,9 +802,13 @@ class IDFTool(object): if type(overrides_list) is not list: raise RuntimeError('platform_overrides for tool %s is not a list' % tool_name) + supported_targets = tool_dict.get('supported_targets') + if not isinstance(supported_targets, list): + raise RuntimeError('supported_targets for tool %s is not a list of strings' % tool_name) + # Create the object tool_obj = cls(tool_name, description, install, info_url, license, # type: ignore - version_cmd, version_regex, version_regex_replace, # type: ignore + version_cmd, version_regex, supported_targets, version_regex_replace, # type: ignore strip_container_dirs) # type: ignore for path in export_paths: # type: ignore @@ -906,6 +915,7 @@ class IDFTool(object): 'license': self.options.license, 'version_cmd': self.options.version_cmd, 'version_regex': self.options.version_regex, + 'supported_targets': self.options.supported_targets, 'versions': versions_array, } if self.options.version_regex_replace != VERSION_REGEX_REPLACE_DEFAULT: @@ -1013,6 +1023,98 @@ def get_python_env_path(): # type: () -> Tuple[str, str, str] return idf_python_env_path, idf_python_export_path, virtualenv_python +def get_idf_env(): # type: () -> Any + try: + idf_env_file_path = os.path.join(global_idf_tools_path, IDF_ENV_FILE) # type: ignore + with open(idf_env_file_path, 'r') as idf_env_file: + return json.load(idf_env_file) + except (IOError, OSError): + if not os.path.exists(idf_env_file_path): + warn('File {} was not found. '.format(idf_env_file_path)) + else: + filename, ending = os.path.splitext(os.path.basename(idf_env_file_path)) + warn('File {} can not be opened, renaming to {}'.format(idf_env_file_path,filename + '_failed' + ending)) + os.rename(idf_env_file_path, os.path.join(os.path.dirname(idf_env_file_path), (filename + '_failed' + ending))) + + info('Creating {}' .format(idf_env_file_path)) + return {'idfSelectedId': 'sha', 'idfInstalled': {'sha': {'targets': {}}}} + + +def export_targets_to_idf_env_json(targets): # type: (list[str]) -> None + idf_env_json = get_idf_env() + targets = list(set(targets + get_user_defined_targets())) + + for env in idf_env_json['idfInstalled']: + if env == idf_env_json['idfSelectedId']: + idf_env_json['idfInstalled'][env]['targets'] = targets + break + + try: + with open(os.path.join(global_idf_tools_path, IDF_ENV_FILE), 'w') as w: # type: ignore + json.dump(idf_env_json, w, indent=4) + except (IOError, OSError): + warn('File {} can not be created. '.format(os.path.join(global_idf_tools_path, IDF_ENV_FILE))) # type: ignore + + +def clean_targets(targets_str): # type: (str) -> list[str] + targets_from_tools_json = get_all_targets_from_tools_json() + invalid_targets = [] + + targets_str = targets_str.lower() + targets = targets_str.replace('-', '').split(',') + if targets != ['all']: + invalid_targets = [t for t in targets if t not in targets_from_tools_json] + if invalid_targets: + warn('Targets: "{}" are not supported. Only allowed options are: {}.'.format(', '.join(invalid_targets), ', '.join(targets_from_tools_json))) + raise SystemExit(1) + # removing duplicates + targets = list(set(targets)) + export_targets_to_idf_env_json(targets) + else: + export_targets_to_idf_env_json(targets_from_tools_json) + return targets + + +def get_user_defined_targets(): # type: () -> list[str] + try: + with open(os.path.join(global_idf_tools_path, IDF_ENV_FILE), 'r') as idf_env_file: # type: ignore + idf_env_json = json.load(idf_env_file) + except OSError: + # warn('File {} was not found. Installing tools for all esp targets.'.format(os.path.join(global_idf_tools_path, IDF_ENV_FILE))) # type: ignore + return [] + + targets = [] + for env in idf_env_json['idfInstalled']: + if env == idf_env_json['idfSelectedId']: + targets = idf_env_json['idfInstalled'][env]['targets'] + break + return targets + + +def get_all_targets_from_tools_json(): # type: () -> list[str] + tools_info = load_tools_info() + targets_from_tools_json = [] # type: list[str] + + for _, v in tools_info.items(): + targets_from_tools_json.extend(v.get_supported_targets()) + # remove duplicates + targets_from_tools_json = list(set(targets_from_tools_json)) + if 'all' in targets_from_tools_json: + targets_from_tools_json.remove('all') + return sorted(targets_from_tools_json) + + +def filter_tools_info(tools_info): # type: (OrderedDict[str, IDFTool]) -> OrderedDict[str,IDFTool] + targets = get_user_defined_targets() + if not targets: + return tools_info + else: + filtered_tools_spec = {k:v for k, v in tools_info.items() if + (v.get_install_type() == IDFTool.INSTALL_ALWAYS or v.get_install_type() == IDFTool.INSTALL_ON_REQUEST) and + (any(item in targets for item in v.get_supported_targets()) or v.get_supported_targets() == ['all'])} + return OrderedDict(filtered_tools_spec) + + def action_list(args): # type: ignore tools_info = load_tools_info() for name, tool in tools_info.items(): @@ -1034,6 +1136,7 @@ def action_list(args): # type: ignore def action_check(args): # type: ignore tools_info = load_tools_info() + tools_info = filter_tools_info(tools_info) not_found_list = [] info('Checking for installed tools...') for name, tool in tools_info.items(): @@ -1060,6 +1163,7 @@ def action_check(args): # type: ignore def action_export(args): # type: ignore tools_info = load_tools_info() + tools_info = filter_tools_info(tools_info) all_tools_found = True export_vars = {} paths_to_export = [] @@ -1241,6 +1345,10 @@ def apply_github_assets_option(tool_download_obj): # type: ignore def action_download(args): # type: ignore tools_info = load_tools_info() tools_spec = args.tools + targets = [] # type: list[str] + # Installing only single tools, no targets are specified. + if 'required' in tools_spec: + targets = clean_targets(args.targets) if args.platform not in PLATFORM_FROM_NAME: fatal('unknown platform: {}' % args.platform) @@ -1253,8 +1361,17 @@ def action_download(args): # type: ignore tools_info_for_platform[name] = tool_for_platform if not tools_spec or 'required' in tools_spec: + # Downloading tools for all ESP_targets required by the operating system. tools_spec = [k for k, v in tools_info_for_platform.items() if v.get_install_type() == IDFTool.INSTALL_ALWAYS] + # Filtering tools user defined list of ESP_targets + if 'all' not in targets: + def is_tool_selected(tool): # type: (IDFTool) -> bool + supported_targets = tool.get_supported_targets() + return (any(item in targets for item in supported_targets) or supported_targets == ['all']) + tools_spec = [k for k in tools_spec if is_tool_selected(tools_info[k])] info('Downloading tools for {}: {}'.format(platform, ', '.join(tools_spec))) + + # Downloading tools for all ESP_targets (MacOS, Windows, Linux) elif 'all' in tools_spec: tools_spec = [k for k, v in tools_info_for_platform.items() if v.get_install_type() != IDFTool.INSTALL_NEVER] info('Downloading tools for {}: {}'.format(platform, ', '.join(tools_spec))) @@ -1288,9 +1405,24 @@ def action_download(args): # type: ignore def action_install(args): # type: ignore tools_info = load_tools_info() tools_spec = args.tools # type: ignore + targets = [] # type: list[str] + # Installing only single tools, no targets are specified. + if 'required' in tools_spec: + targets = clean_targets(args.targets) + info('Selected targets are: {}' .format(', '.join(get_user_defined_targets()))) + if not tools_spec or 'required' in tools_spec: + # Installing tools for all ESP_targets required by the operating system. tools_spec = [k for k, v in tools_info.items() if v.get_install_type() == IDFTool.INSTALL_ALWAYS] + # Filtering tools user defined list of ESP_targets + if 'all' not in targets: + def is_tool_selected(tool): # type: (IDFTool) -> bool + supported_targets = tool.get_supported_targets() + return (any(item in targets for item in supported_targets) or supported_targets == ['all']) + tools_spec = [k for k in tools_spec if is_tool_selected(tools_info[k])] info('Installing tools: {}'.format(', '.join(tools_spec))) + + # Installing tools for all ESP_targets (MacOS, Windows, Linux) elif 'all' in tools_spec: tools_spec = [k for k, v in tools_info.items() if v.get_install_type() != IDFTool.INSTALL_NEVER] info('Installing tools: {}'.format(', '.join(tools_spec))) @@ -1577,6 +1709,8 @@ def main(argv): # type: (list[str]) -> None 'To install a specific version use @ syntax. ' + 'Use empty or \'required\' to install required tools, not optional ones. ' + 'Use \'all\' to install all tools, including the optional ones.') + install.add_argument('--targets', default='all', help='A comma separated list of desired chip targets for installing.' + + ' It defaults to installing all supported targets.') download = subparsers.add_parser('download', help='Download the tools into the dist directory') download.add_argument('--platform', help='Platform to download the tools for') @@ -1585,6 +1719,8 @@ def main(argv): # type: (list[str]) -> None 'To download a specific version use @ syntax. ' + 'Use empty or \'required\' to download required tools, not optional ones. ' + 'Use \'all\' to download all tools, including the optional ones.') + download.add_argument('--targets', default='all', help='A comma separated list of desired chip targets for installing.' + + ' It defaults to installing all supported targets.') if IDF_MAINTAINER: for subparser in [download, install]: diff --git a/tools/test_idf_tools/test_idf_tools.py b/tools/test_idf_tools/test_idf_tools.py index c6b3e56ff1..f91bd3e152 100755 --- a/tools/test_idf_tools/test_idf_tools.py +++ b/tools/test_idf_tools/test_idf_tools.py @@ -46,10 +46,27 @@ except ImportError: sys.path.append('..') import idf_tools +ESP32ULP = 'esp32ulp-elf' +ESP32S2ULP = 'esp32s2ulp-elf' +OPENOCD = 'openocd-esp32' +RISC = 'riscv32-esp-elf' +XTENSA_ESP32_ELF = 'xtensa-esp32-elf' +XTENSA_ESP32S2_ELF = 'xtensa-esp32s2-elf' +XTENSA_ESP32S3_ELF = 'xtensa-esp32s3-elf' + +ESP32ULP_VERSION = '2.28.51-esp-20191205' +ESP32S2ULP_VERSION = '2.28.51-esp-20191205' +OPENOCD_VERSION = 'v0.10.0-esp32-20210401' +RISC_VERSION = 'esp-2021r1-8.4.0' +XTENSA_ESP32_ELF_VERSION = 'esp-2021r1-8.4.0' +XTENSA_ESP32S2_ELF_VERSION = 'esp-2021r1-8.4.0' +XTENSA_ESP32S3_ELF_VERSION = 'esp-2021r1-8.4.0' + class TestUsage(unittest.TestCase): - def test_usage_basic(self): + @classmethod + def setUpClass(cls): old_tools_dir = os.environ.get('IDF_TOOLS_PATH') or os.path.expanduser(idf_tools.IDF_TOOLS_PATH_DEFAULT) mirror_prefix_map = None @@ -61,53 +78,243 @@ class TestUsage(unittest.TestCase): print('Using IDF_MIRROR_PREFIX_MAP={}'.format(mirror_prefix_map)) os.environ['IDF_MIRROR_PREFIX_MAP'] = mirror_prefix_map - temp_tools_dir = tempfile.mkdtemp(prefix='idf_tools_tmp') - print('Using IDF_TOOLS_PATH={}'.format(temp_tools_dir)) - os.environ['IDF_TOOLS_PATH'] = temp_tools_dir + cls.temp_tools_dir = tempfile.mkdtemp(prefix='idf_tools_tmp') - self.addCleanup(shutil.rmtree, temp_tools_dir) + print('Using IDF_TOOLS_PATH={}'.format(cls.temp_tools_dir)) + os.environ['IDF_TOOLS_PATH'] = cls.temp_tools_dir + @classmethod + def tearDownClass(cls): + shutil.rmtree(cls.temp_tools_dir) + + def tearDown(self): + if os.path.isdir(os.path.join(self.temp_tools_dir, 'dist')): + shutil.rmtree(os.path.join(self.temp_tools_dir, 'dist')) + + if os.path.isdir(os.path.join(self.temp_tools_dir, 'tools')): + shutil.rmtree(os.path.join(self.temp_tools_dir, 'tools')) + + if os.path.isfile(os.path.join(self.temp_tools_dir, 'idf-env.json')): + os.remove(os.path.join(self.temp_tools_dir, 'idf-env.json')) + + def check_install_tool(self,tool,tool_version,output,assertIn=True): + if assertIn: + self.assertIn('Installing %s@' % tool + tool_version, output) + self.assertIn('Downloading %s' % tool, output) + else: + self.assertNotIn('Installing %s@' % tool + tool_version, output) + self.assertNotIn('Downloading %s' % tool, output) + + def check_install_esp32_ulp(self,output,assertIn=True): + if assertIn: + self.assertIn('Installing esp32ulp-elf@' + ESP32ULP_VERSION, output) + self.assertIn('Downloading binutils-esp32ulp', output) + else: + self.assertNotIn('Installing esp32ulp-elf@' + ESP32ULP_VERSION, output) + self.assertNotIn('Downloading binutils-esp32ulp', output) + + def check_install_esp32s2_ulp(self,output,assertIn=True): + if assertIn: + self.assertIn('Installing esp32s2ulp-elf@' + ESP32S2ULP_VERSION, output) + self.assertIn('Downloading binutils-esp32s2ulp', output) + else: + self.assertNotIn('Installing esp32s2ulp-elf@' + ESP32S2ULP_VERSION, output) + self.assertNotIn('Downloading binutils-esp32s2ulp', output) + + def run_idf_tools_with_action(self,action): output_stream = StringIO() with redirect_stdout(output_stream): - idf_tools.main(['list']) + idf_tools.main(action) output = output_stream.getvalue() + return output - xtensa_esp32_elf_version = 'esp-2021r1-8.4.0' - esp32ulp_version = '2.28.51-esp-20191205' + def test_usage_basic(self): + output = self.run_idf_tools_with_action(['list']) + self.assertIn('* %s:' % ESP32ULP, output) + self.assertIn('- %s (recommended)' % ESP32ULP_VERSION, output) + self.assertIn('* %s:' % ESP32S2ULP, output) + self.assertIn('- %s (recommended)' % ESP32S2ULP_VERSION, output) + self.assertIn('* %s:' % OPENOCD, output) + self.assertIn('- %s (recommended)' % OPENOCD_VERSION, output) + self.assertIn('* %s:' % RISC, output) + self.assertIn('- %s (recommended)' % RISC_VERSION, output) + self.assertIn('* %s:' % XTENSA_ESP32_ELF, output) + self.assertIn('- %s (recommended)' % XTENSA_ESP32_ELF_VERSION, output) + self.assertIn('* %s:' % XTENSA_ESP32S2_ELF, output) + self.assertIn('- %s (recommended)' % XTENSA_ESP32S2_ELF_VERSION, output) + self.assertIn('* %s:' % XTENSA_ESP32S3_ELF, output) + self.assertIn('- %s (recommended)' % XTENSA_ESP32S3_ELF_VERSION, output) - self.assertIn('* xtensa-esp32-elf:', output) - self.assertIn('- %s (recommended)' % xtensa_esp32_elf_version, output) - self.assertIn('* esp32ulp-elf', output) - self.assertIn('- %s (recommended)' % esp32ulp_version, output) + required_tools_installed = 7 + output = self.run_idf_tools_with_action(['install']) + self.check_install_tool(OPENOCD,OPENOCD_VERSION,output) + self.check_install_tool(RISC,RISC_VERSION,output) + self.check_install_tool(XTENSA_ESP32_ELF,XTENSA_ESP32_ELF_VERSION,output) + self.check_install_tool(XTENSA_ESP32S2_ELF,XTENSA_ESP32S2_ELF_VERSION,output) + self.check_install_tool(XTENSA_ESP32S3_ELF,XTENSA_ESP32S3_ELF_VERSION,output) + self.check_install_esp32_ulp(output) + self.check_install_esp32s2_ulp(output) + self.assertIn('to ' + os.path.join(self.temp_tools_dir, 'dist'), output) + self.assertEqual(required_tools_installed,output.count('Done')) - output_stream = StringIO() - with redirect_stdout(output_stream): - idf_tools.main(['install']) - output = output_stream.getvalue() - - self.assertIn('Installing esp32ulp-elf@' + esp32ulp_version, output) - self.assertIn('Downloading binutils-esp32ulp', output) - self.assertIn('Installing xtensa-esp32-elf@' + xtensa_esp32_elf_version, output) - self.assertIn('Downloading xtensa-esp32-elf', output) - self.assertIn('to ' + os.path.join(temp_tools_dir, 'dist'), output) - - output_stream = StringIO() - with redirect_stdout(output_stream): - idf_tools.main(['check']) - output = output_stream.getvalue() - - self.assertIn('version installed in tools directory: ' + esp32ulp_version, output) - self.assertIn('version installed in tools directory: ' + xtensa_esp32_elf_version, output) - - output_stream = StringIO() - with redirect_stdout(output_stream): - idf_tools.main(['export']) - output = output_stream.getvalue() + output = self.run_idf_tools_with_action(['check']) + self.assertIn('version installed in tools directory: ' + ESP32ULP_VERSION, output) + self.assertIn('version installed in tools directory: ' + ESP32S2ULP_VERSION, output) + self.assertIn('version installed in tools directory: ' + OPENOCD_VERSION, output) + self.assertIn('version installed in tools directory: ' + RISC_VERSION, output) + self.assertIn('version installed in tools directory: ' + XTENSA_ESP32_ELF_VERSION, output) + self.assertIn('version installed in tools directory: ' + XTENSA_ESP32S2_ELF_VERSION, output) + self.assertIn('version installed in tools directory: ' + XTENSA_ESP32S3_ELF_VERSION, output) + output = self.run_idf_tools_with_action(['export']) self.assertIn('%s/tools/esp32ulp-elf/%s/esp32ulp-elf-binutils/bin' % - (temp_tools_dir, esp32ulp_version), output) + (self.temp_tools_dir, ESP32ULP_VERSION), output) self.assertIn('%s/tools/xtensa-esp32-elf/%s/xtensa-esp32-elf/bin' % - (temp_tools_dir, xtensa_esp32_elf_version), output) + (self.temp_tools_dir, XTENSA_ESP32_ELF_VERSION), output) + self.assertIn('%s/tools/openocd-esp32/%s/openocd-esp32/bin' % + (self.temp_tools_dir, OPENOCD_VERSION), output) + self.assertIn('%s/tools/riscv32-esp-elf/%s/riscv32-esp-elf/bin' % + (self.temp_tools_dir, RISC_VERSION), output) + self.assertIn('%s/tools/esp32s2ulp-elf/%s/esp32s2ulp-elf-binutils/bin' % + (self.temp_tools_dir, ESP32S2ULP_VERSION), output) + self.assertIn('%s/tools/xtensa-esp32s2-elf/%s/xtensa-esp32s2-elf/bin' % + (self.temp_tools_dir, XTENSA_ESP32S2_ELF_VERSION), output) + self.assertIn('%s/tools/xtensa-esp32s3-elf/%s/xtensa-esp32s3-elf/bin' % + (self.temp_tools_dir, XTENSA_ESP32S3_ELF_VERSION), output) + + def test_tools_for_esp32(self): + required_tools_installed = 3 + output = self.run_idf_tools_with_action(['install', '--targets=esp32']) + self.check_install_tool(XTENSA_ESP32_ELF,XTENSA_ESP32_ELF_VERSION,output) + self.check_install_tool(OPENOCD,OPENOCD_VERSION,output) + self.check_install_esp32_ulp(output) + self.check_install_tool(RISC,RISC_VERSION,output,assertIn=False) + self.check_install_tool(XTENSA_ESP32S2_ELF,XTENSA_ESP32S2_ELF_VERSION,output,assertIn=False) + self.check_install_tool(XTENSA_ESP32S3_ELF,XTENSA_ESP32S3_ELF_VERSION,output,assertIn=False) + self.check_install_esp32s2_ulp(output,assertIn=False) + self.assertIn('to ' + os.path.join(self.temp_tools_dir, 'dist'), output) + self.assertEqual(required_tools_installed,output.count('Done')) + + output = self.run_idf_tools_with_action(['check']) + self.assertIn('version installed in tools directory: ' + ESP32ULP_VERSION, output) + self.assertIn('version installed in tools directory: ' + XTENSA_ESP32_ELF_VERSION, output) + self.assertIn('version installed in tools directory: ' + OPENOCD_VERSION, output) + + output = self.run_idf_tools_with_action(['export']) + self.assertIn('%s/tools/esp32ulp-elf/%s/esp32ulp-elf-binutils/bin' % + (self.temp_tools_dir, ESP32ULP_VERSION), output) + self.assertIn('%s/tools/xtensa-esp32-elf/%s/xtensa-esp32-elf/bin' % + (self.temp_tools_dir, XTENSA_ESP32_ELF_VERSION), output) + self.assertIn('%s/tools/openocd-esp32/%s/openocd-esp32/bin' % + (self.temp_tools_dir, OPENOCD_VERSION), output) + self.assertNotIn('%s/tools/riscv32-esp-elf/%s/riscv32-esp-elf/bin' % + (self.temp_tools_dir, RISC_VERSION), output) + self.assertNotIn('%s/tools/esp32s2ulp-elf/%s/esp32s2ulp-elf-binutils/bin' % + (self.temp_tools_dir, ESP32S2ULP_VERSION), output) + self.assertNotIn('%s/tools/xtensa-esp32s2-elf/%s/xtensa-esp32s2-elf/bin' % + (self.temp_tools_dir, XTENSA_ESP32S2_ELF_VERSION), output) + self.assertNotIn('%s/tools/xtensa-esp32s3-elf/%s/xtensa-esp32s3-elf/bin' % + (self.temp_tools_dir, XTENSA_ESP32S3_ELF_VERSION), output) + + def test_tools_for_esp32c3(self): + required_tools_installed = 2 + output = self.run_idf_tools_with_action(['install', '--targets=esp32c3']) + self.check_install_tool(OPENOCD,OPENOCD_VERSION,output) + self.check_install_tool(RISC,RISC_VERSION,output) + self.check_install_tool(XTENSA_ESP32_ELF,XTENSA_ESP32_ELF_VERSION,output,assertIn=False) + self.check_install_tool(XTENSA_ESP32S2_ELF,XTENSA_ESP32S2_ELF_VERSION,output,assertIn=False) + self.check_install_tool(XTENSA_ESP32S3_ELF,XTENSA_ESP32S3_ELF_VERSION,output,assertIn=False) + self.check_install_esp32_ulp(output,assertIn=False) + self.check_install_esp32s2_ulp(output,assertIn=False) + self.assertIn('to ' + os.path.join(self.temp_tools_dir, 'dist'), output) + self.assertEqual(required_tools_installed,output.count('Done')) + + output = self.run_idf_tools_with_action(['check']) + self.assertIn('version installed in tools directory: ' + OPENOCD_VERSION, output) + self.assertIn('version installed in tools directory: ' + RISC_VERSION, output) + + output = self.run_idf_tools_with_action(['export']) + self.assertIn('%s/tools/openocd-esp32/%s/openocd-esp32/bin' % + (self.temp_tools_dir, OPENOCD_VERSION), output) + self.assertIn('%s/tools/riscv32-esp-elf/%s/riscv32-esp-elf/bin' % + (self.temp_tools_dir, RISC_VERSION), output) + self.assertNotIn('%s/tools/esp32ulp-elf/%s/esp32ulp-elf-binutils/bin' % + (self.temp_tools_dir, ESP32ULP_VERSION), output) + self.assertNotIn('%s/tools/xtensa-esp32-elf/%s/xtensa-esp32-elf/bin' % + (self.temp_tools_dir, XTENSA_ESP32_ELF_VERSION), output) + self.assertNotIn('%s/tools/esp32s2ulp-elf/%s/esp32s2ulp-elf-binutils/bin' % + (self.temp_tools_dir, ESP32S2ULP_VERSION), output) + self.assertNotIn('%s/tools/xtensa-esp32s2-elf/%s/xtensa-esp32s2-elf/bin' % + (self.temp_tools_dir, XTENSA_ESP32S2_ELF_VERSION), output) + self.assertNotIn('%s/tools/xtensa-esp32s3-elf/%s/xtensa-esp32s3-elf/bin' % + (self.temp_tools_dir, XTENSA_ESP32S3_ELF_VERSION), output) + + def test_tools_for_esp32s2(self): + required_tools_installed = 3 + output = self.run_idf_tools_with_action(['install', '--targets=esp32s2']) + self.check_install_tool(XTENSA_ESP32S2_ELF,XTENSA_ESP32S2_ELF_VERSION,output) + self.check_install_tool(OPENOCD,OPENOCD_VERSION,output) + self.check_install_esp32s2_ulp(output) + self.check_install_tool(RISC,RISC_VERSION,output,assertIn=False) + self.check_install_tool(XTENSA_ESP32_ELF,XTENSA_ESP32_ELF_VERSION,output,assertIn=False) + self.check_install_tool(XTENSA_ESP32S3_ELF,XTENSA_ESP32S3_ELF_VERSION,output,assertIn=False) + self.check_install_esp32_ulp(output,assertIn=False) + self.assertIn('to ' + os.path.join(self.temp_tools_dir, 'dist'), output) + self.assertEqual(required_tools_installed,output.count('Done')) + + output = self.run_idf_tools_with_action(['check']) + self.assertIn('version installed in tools directory: ' + ESP32S2ULP_VERSION, output) + self.assertIn('version installed in tools directory: ' + OPENOCD_VERSION, output) + self.assertIn('version installed in tools directory: ' + XTENSA_ESP32S2_ELF_VERSION, output) + + output = self.run_idf_tools_with_action(['export']) + self.assertIn('%s/tools/esp32s2ulp-elf/%s/esp32s2ulp-elf-binutils/bin' % + (self.temp_tools_dir, ESP32S2ULP_VERSION), output) + self.assertIn('%s/tools/xtensa-esp32s2-elf/%s/xtensa-esp32s2-elf/bin' % + (self.temp_tools_dir, XTENSA_ESP32S2_ELF_VERSION), output) + self.assertIn('%s/tools/openocd-esp32/%s/openocd-esp32/bin' % + (self.temp_tools_dir, OPENOCD_VERSION), output) + self.assertNotIn('%s/tools/esp32ulp-elf/%s/esp32ulp-elf-binutils/bin' % + (self.temp_tools_dir, ESP32ULP_VERSION), output) + self.assertNotIn('%s/tools/xtensa-esp32-elf/%s/xtensa-esp32-elf/bin' % + (self.temp_tools_dir, XTENSA_ESP32_ELF_VERSION), output) + self.assertNotIn('%s/tools/riscv32-esp-elf/%s/riscv32-esp-elf/bin' % + (self.temp_tools_dir, RISC_VERSION), output) + self.assertNotIn('%s/tools/xtensa-esp32s3-elf/%s/xtensa-esp32s3-elf/bin' % + (self.temp_tools_dir, XTENSA_ESP32S3_ELF_VERSION), output) + + def test_tools_for_esp32s3(self): + required_tools_installed = 2 + output = self.run_idf_tools_with_action(['install', '--targets=esp32s3']) + self.check_install_tool(OPENOCD,OPENOCD_VERSION,output) + self.check_install_tool(XTENSA_ESP32S3_ELF,XTENSA_ESP32S3_ELF_VERSION,output) + self.check_install_tool(RISC,RISC_VERSION,output,assertIn=False) + self.check_install_tool(XTENSA_ESP32_ELF,XTENSA_ESP32_ELF_VERSION,output,assertIn=False) + self.check_install_tool(XTENSA_ESP32S2_ELF,XTENSA_ESP32S2_ELF_VERSION,output,assertIn=False) + self.check_install_esp32_ulp(output,assertIn=False) + self.check_install_esp32s2_ulp(output,assertIn=False) + self.assertIn('to ' + os.path.join(self.temp_tools_dir, 'dist'), output) + self.assertEqual(required_tools_installed,output.count('Done')) + + output = self.run_idf_tools_with_action(['check']) + self.assertIn('version installed in tools directory: ' + OPENOCD_VERSION, output) + self.assertIn('version installed in tools directory: ' + XTENSA_ESP32S3_ELF_VERSION, output) + + output = self.run_idf_tools_with_action(['export']) + self.assertIn('%s/tools/openocd-esp32/%s/openocd-esp32/bin' % + (self.temp_tools_dir, OPENOCD_VERSION), output) + self.assertIn('%s/tools/xtensa-esp32s3-elf/%s/xtensa-esp32s3-elf/bin' % + (self.temp_tools_dir, XTENSA_ESP32S3_ELF_VERSION), output) + self.assertNotIn('%s/tools/esp32ulp-elf/%s/esp32ulp-elf-binutils/bin' % + (self.temp_tools_dir, ESP32ULP_VERSION), output) + self.assertNotIn('%s/tools/xtensa-esp32-elf/%s/xtensa-esp32-elf/bin' % + (self.temp_tools_dir, XTENSA_ESP32_ELF_VERSION), output) + self.assertNotIn('%s/tools/riscv32-esp-elf/%s/riscv32-esp-elf/bin' % + (self.temp_tools_dir, RISC_VERSION), output) + self.assertNotIn('%s/tools/esp32s2ulp-elf/%s/esp32s2ulp-elf-binutils/bin' % + (self.temp_tools_dir, ESP32S2ULP_VERSION), output) + self.assertNotIn('%s/tools/xtensa-esp32s2-elf/%s/xtensa-esp32s2-elf/bin' % + (self.temp_tools_dir, XTENSA_ESP32S2_ELF_VERSION), output) class TestMaintainer(unittest.TestCase): diff --git a/tools/tools.json b/tools/tools.json index c94457d6a8..f369b52370 100644 --- a/tools/tools.json +++ b/tools/tools.json @@ -13,6 +13,9 @@ "install": "always", "license": "GPL-3.0-with-GCC-exception", "name": "xtensa-esp32-elf", + "supported_targets": [ + "esp32" + ], "version_cmd": [ "xtensa-esp32-elf-gcc", "--version" @@ -69,6 +72,9 @@ "install": "always", "license": "GPL-3.0-with-GCC-exception", "name": "xtensa-esp32s2-elf", + "supported_targets": [ + "esp32s2" + ], "version_cmd": [ "xtensa-esp32s2-elf-gcc", "--version" @@ -125,6 +131,9 @@ "install": "always", "license": "GPL-3.0-with-GCC-exception", "name": "xtensa-esp32s3-elf", + "supported_targets": [ + "esp32s3" + ], "version_cmd": [ "xtensa-esp32s3-elf-gcc", "--version" @@ -181,6 +190,9 @@ "install": "always", "license": "GPL-3.0-with-GCC-exception", "name": "riscv32-esp-elf", + "supported_targets": [ + "esp32c3" + ], "version_cmd": [ "riscv32-esp-elf-gcc", "--version" @@ -245,6 +257,9 @@ ] } ], + "supported_targets": [ + "esp32" + ], "version_cmd": [ "esp32ulp-elf-as", "--version" @@ -303,6 +318,9 @@ ] } ], + "supported_targets": [ + "esp32s2" + ], "version_cmd": [ "esp32s2ulp-elf-as", "--version" @@ -374,6 +392,9 @@ } ], "strip_container_dirs": 1, + "supported_targets": [ + "all" + ], "version_cmd": [ "cmake", "--version" @@ -429,6 +450,9 @@ ] } ], + "supported_targets": [ + "all" + ], "version_cmd": [ "openocd", "--version" @@ -487,6 +511,9 @@ ] } ], + "supported_targets": [ + "all" + ], "version_cmd": [ "ninja", "--version" @@ -535,6 +562,9 @@ ] } ], + "supported_targets": [ + "all" + ], "version_cmd": [ "idf.py.exe", "-v" @@ -579,6 +609,9 @@ ] } ], + "supported_targets": [ + "all" + ], "version_cmd": [ "ccache.exe", "--version" @@ -616,6 +649,10 @@ ] } ], + "supported_targets": [ + "esp32s2", + "esp32s3" + ], "version_cmd": [ "dfu-util", "--version" diff --git a/tools/tools_schema.json b/tools/tools_schema.json index 6f11215483..cd6be7dd4d 100644 --- a/tools/tools_schema.json +++ b/tools/tools_schema.json @@ -55,6 +55,10 @@ "$ref": "#/definitions/arrayOfStrings", "description": "Command to be executed (along with any extra arguments). The executable be present in one of the export_paths." }, + "supported_targets": { + "$ref": "#/definitions/arrayOfStrings", + "description": "Array of esp_targets that this tool is needed for." + }, "version_regex": { "description": "Regex which is to be applied to version_cmd output to extract the version. By default, the version will be the first capture group of the expression. If version_regex_replace is specified, version will be obtained by doing a substitution using version_regex_replace instead.", "$ref": "#/definitions/regex" @@ -215,6 +219,10 @@ "description": "Platform-specific replacement for toolInfo/version_cmd", "$ref": "#/definitions/arrayOfStrings" }, + "supported_targets": { + "description": "Platform-specific replacement for toolInfo/supported_targets", + "$ref": "#/definitions/arrayOfStrings" + }, "version_regex": { "description": "Platform-specific replacement for toolInfo/version_regex", "$ref": "#/definitions/regex"