tools: Installing tools for given IDF_TARGET

Allow user to select specific ESP_TARGET while setting up ESD_IDF.
Only necessary tools for given target will be downloaded and installed.

Closes https://github.com/espressif/esp-idf/issues/5113
This commit is contained in:
Marek Fiala 2021-04-26 21:34:48 +02:00
parent 48ae2309fd
commit 5639b6888d
9 changed files with 477 additions and 56 deletions

View File

@ -119,7 +119,7 @@ If you have one of {IDF_TARGET_NAME} development boards listed below, you can cl
ESP32-C3-DevKitM-1 <../hw-reference/esp32c3/user-guide-devkitm-1> ESP32-C3-DevKitM-1 <../hw-reference/esp32c3/user-guide-devkitm-1>
ESP32-C3-DevKitC-02 <../hw-reference/esp32c3/user-guide-devkitc-02> ESP32-C3-DevKitC-02 <../hw-reference/esp32c3/user-guide-devkitc-02>
.. _get-started-step-by-step: .. _get-started-step-by-step:
Installation Step by Step Installation Step by Step
@ -229,14 +229,14 @@ If you want to install the tools without the help of ESP-IDF Tools Installer, op
.. code-block:: batch .. code-block:: batch
cd %userprofile%\esp\esp-idf cd %userprofile%\esp\esp-idf
install.bat install.bat {IDF_TARGET_PATH_NAME}
or with Windows PowerShell or with Windows PowerShell
.. code-block:: powershell .. code-block:: powershell
cd ~/esp/esp-idf cd ~/esp/esp-idf
./install.ps1 ./install.ps1 {IDF_TARGET_PATH_NAME}
Linux and macOS Linux and macOS
~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~
@ -244,7 +244,18 @@ Linux and macOS
.. code-block:: bash .. code-block:: bash
cd ~/esp/esp-idf 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 Alternative File Downloads
~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~

View File

@ -18,8 +18,11 @@ if not "%MISSING_REQUIREMENTS%" == "" goto :error_missing_requirements
set IDF_PATH=%~dp0 set IDF_PATH=%~dp0
set IDF_PATH=%IDF_PATH:~0,-1% set IDF_PATH=%IDF_PATH:~0,-1%
set TARGETS="all"
if NOT "%1"=="" set TARGETS=%*
echo Installing ESP-IDF tools 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 if %errorlevel% neq 0 goto :end
echo Setting up Python environment echo Setting up Python environment

View File

@ -7,8 +7,15 @@ set -x IDF_PATH $basedir
echo "Detecting the Python interpreter" echo "Detecting the Python interpreter"
source "$IDF_PATH"/tools/detect_python.fish 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" 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" echo "Installing Python environment and packages"
"$ESP_PYTHON" "$IDF_PATH"/tools/idf_tools.py install-python-env "$ESP_PYTHON" "$IDF_PATH"/tools/idf_tools.py install-python-env

View File

@ -1,9 +1,14 @@
#!/usr/bin/env pwsh #!/usr/bin/env pwsh
$IDF_PATH = $PSScriptRoot $IDF_PATH = $PSScriptRoot
if($args.count -eq 0){
$TARGETS = "all"
}else
{
$TARGETS = $args[0] -join ','
}
Write-Output "Installing ESP-IDF tools" 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 if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } # if error
Write-Output "Setting up Python environment" Write-Output "Setting up Python environment"

View File

@ -8,8 +8,13 @@ export IDF_PATH=$(cd $(dirname $0); pwd)
echo "Detecting the Python interpreter" echo "Detecting the Python interpreter"
. ${IDF_PATH}/tools/detect_python.sh . ${IDF_PATH}/tools/detect_python.sh
if [ "$#" -eq 0 ]; then
TARGETS="all"
else
TARGETS=$1
fi
echo "Installing ESP-IDF tools" 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" echo "Installing Python environment and packages"
${ESP_PYTHON} ${IDF_PATH}/tools/idf_tools.py install-python-env ${ESP_PYTHON} ${IDF_PATH}/tools/idf_tools.py install-python-env

View File

@ -60,6 +60,7 @@ from collections import OrderedDict, namedtuple
try: try:
import typing # noqa: F401 import typing # noqa: F401
from typing import IO, Any, Callable, Optional, Tuple, Union # noqa: F401
except ImportError: except ImportError:
pass pass
@ -79,6 +80,7 @@ except ImportError:
TOOLS_FILE = 'tools/tools.json' TOOLS_FILE = 'tools/tools.json'
TOOLS_SCHEMA_FILE = 'tools/tools_schema.json' TOOLS_SCHEMA_FILE = 'tools/tools_schema.json'
TOOLS_FILE_NEW = 'tools/tools.new.json' TOOLS_FILE_NEW = 'tools/tools.new.json'
IDF_ENV_FILE = 'idf-env.json'
TOOLS_FILE_VERSION = 1 TOOLS_FILE_VERSION = 1
IDF_TOOLS_PATH_DEFAULT = os.path.join('~', '.espressif') IDF_TOOLS_PATH_DEFAULT = os.path.join('~', '.espressif')
UNKNOWN_VERSION = 'unknown' UNKNOWN_VERSION = 'unknown'
@ -479,7 +481,8 @@ OPTIONS_LIST = ['version_cmd',
'install', 'install',
'info_url', 'info_url',
'license', 'license',
'strip_container_dirs'] 'strip_container_dirs',
'supported_targets']
IDFToolOptions = namedtuple('IDFToolOptions', OPTIONS_LIST) IDFToolOptions = namedtuple('IDFToolOptions', OPTIONS_LIST)
@ -490,8 +493,9 @@ class IDFTool(object):
INSTALL_ON_REQUEST = 'on_request' INSTALL_ON_REQUEST = 'on_request'
INSTALL_NEVER = 'never' 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): strip_container_dirs=0):
# type: (str, str, str, str, str, list[str], str, list[str], Optional[str], int) -> None
self.name = name self.name = name
self.description = description self.description = description
self.versions = OrderedDict() # type: typing.Dict[str, IDFToolVersion] self.versions = OrderedDict() # type: typing.Dict[str, IDFToolVersion]
@ -500,8 +504,8 @@ class IDFTool(object):
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(version_cmd, version_regex, version_regex_replace, self.options = IDFToolOptions(version_cmd, version_regex, version_regex_replace,
[], OrderedDict(), install, info_url, license, strip_container_dirs) [], OrderedDict(), install, info_url, license, strip_container_dirs, supported_targets) # type: ignore
self.platform_overrides = [] self.platform_overrides = [] # type: list[dict[str, str]]
self._platform = CURRENT_PLATFORM self._platform = CURRENT_PLATFORM
self._update_current_options() self._update_current_options()
@ -580,7 +584,10 @@ class IDFTool(object):
def get_install_type(self): def get_install_type(self):
return self._current_options.install return self._current_options.install
def compatible_with_platform(self): 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()]) return any([v.compatible_with_platform() for v in self.versions.values()])
def get_supported_platforms(self): # type: () -> typing.Set[str] def get_supported_platforms(self): # type: () -> typing.Set[str]
@ -793,10 +800,14 @@ class IDFTool(object):
if type(overrides_list) is not list: if type(overrides_list) is not list:
raise RuntimeError('platform_overrides for tool %s is not a list' % tool_name) 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 # Create the object
tool_obj = cls(tool_name, description, install, info_url, license, tool_obj = cls(tool_name, description, install, info_url, license, # type: ignore
version_cmd, version_regex, version_regex_replace, version_cmd, version_regex, supported_targets, version_regex_replace, # type: ignore
strip_container_dirs) strip_container_dirs) # type: ignore
for path in export_paths: for path in export_paths:
tool_obj.options.export_paths.append(path) tool_obj.options.export_paths.append(path)
@ -902,6 +913,7 @@ class IDFTool(object):
'license': self.options.license, 'license': self.options.license,
'version_cmd': self.options.version_cmd, 'version_cmd': self.options.version_cmd,
'version_regex': self.options.version_regex, 'version_regex': self.options.version_regex,
'supported_targets': self.options.supported_targets,
'versions': versions_array, 'versions': versions_array,
} }
if self.options.version_regex_replace != VERSION_REGEX_REPLACE_DEFAULT: if self.options.version_regex_replace != VERSION_REGEX_REPLACE_DEFAULT:
@ -1009,7 +1021,99 @@ def get_python_env_path():
return idf_python_env_path, idf_python_export_path, virtualenv_python return idf_python_env_path, idf_python_export_path, virtualenv_python
def action_list(args): 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, IOError):
# 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() tools_info = load_tools_info()
for name, tool in tools_info.items(): for name, tool in tools_info.items():
if tool.get_install_type() == IDFTool.INSTALL_NEVER: if tool.get_install_type() == IDFTool.INSTALL_NEVER:
@ -1030,6 +1134,7 @@ def action_list(args):
def action_check(args): def action_check(args):
tools_info = load_tools_info() tools_info = load_tools_info()
tools_info = filter_tools_info(tools_info)
not_found_list = [] not_found_list = []
info('Checking for installed tools...') info('Checking for installed tools...')
for name, tool in tools_info.items(): for name, tool in tools_info.items():
@ -1056,6 +1161,7 @@ def action_check(args):
def action_export(args): def action_export(args):
tools_info = load_tools_info() tools_info = load_tools_info()
tools_info = filter_tools_info(tools_info)
all_tools_found = True all_tools_found = True
export_vars = {} export_vars = {}
paths_to_export = [] paths_to_export = []
@ -1237,6 +1343,10 @@ def apply_github_assets_option(tool_download_obj):
def action_download(args): def action_download(args):
tools_info = load_tools_info() tools_info = load_tools_info()
tools_spec = args.tools 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: if args.platform not in PLATFORM_FROM_NAME:
fatal('unknown platform: {}' % args.platform) fatal('unknown platform: {}' % args.platform)
@ -1249,8 +1359,17 @@ def action_download(args):
tools_info_for_platform[name] = tool_for_platform tools_info_for_platform[name] = tool_for_platform
if not tools_spec or 'required' in tools_spec: 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] 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))) info('Downloading tools for {}: {}'.format(platform, ', '.join(tools_spec)))
# Downloading tools for all ESP_targets (MacOS, Windows, Linux)
elif 'all' in tools_spec: 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] 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))) info('Downloading tools for {}: {}'.format(platform, ', '.join(tools_spec)))
@ -1283,10 +1402,25 @@ def action_download(args):
def action_install(args): def action_install(args):
tools_info = load_tools_info() tools_info = load_tools_info()
tools_spec = args.tools 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: 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] 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))) info('Installing tools: {}'.format(', '.join(tools_spec)))
# Installing tools for all ESP_targets (MacOS, Windows, Linux)
elif 'all' in tools_spec: elif 'all' in tools_spec:
tools_spec = [k for k, v in tools_info.items() if v.get_install_type() != IDFTool.INSTALL_NEVER] 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))) info('Installing tools: {}'.format(', '.join(tools_spec)))
@ -1573,6 +1707,8 @@ def main(argv):
'To install a specific version use <tool_name>@<version> syntax. ' + 'To install a specific version use <tool_name>@<version> syntax. ' +
'Use empty or \'required\' to install required tools, not optional ones. ' + 'Use empty or \'required\' to install required tools, not optional ones. ' +
'Use \'all\' to install all tools, including the 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 = subparsers.add_parser('download', help='Download the tools into the dist directory')
download.add_argument('--platform', help='Platform to download the tools for') download.add_argument('--platform', help='Platform to download the tools for')
@ -1581,6 +1717,8 @@ def main(argv):
'To download a specific version use <tool_name>@<version> syntax. ' + 'To download a specific version use <tool_name>@<version> syntax. ' +
'Use empty or \'required\' to download required tools, not optional ones. ' + 'Use empty or \'required\' to download required tools, not optional ones. ' +
'Use \'all\' to download all tools, including the 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: if IDF_MAINTAINER:
for subparser in [download, install]: for subparser in [download, install]:

View File

@ -46,10 +46,27 @@ except ImportError:
sys.path.append('..') sys.path.append('..')
import idf_tools 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): 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) old_tools_dir = os.environ.get('IDF_TOOLS_PATH') or os.path.expanduser(idf_tools.IDF_TOOLS_PATH_DEFAULT)
mirror_prefix_map = None mirror_prefix_map = None
@ -61,53 +78,243 @@ class TestUsage(unittest.TestCase):
print('Using IDF_MIRROR_PREFIX_MAP={}'.format(mirror_prefix_map)) print('Using IDF_MIRROR_PREFIX_MAP={}'.format(mirror_prefix_map))
os.environ['IDF_MIRROR_PREFIX_MAP'] = mirror_prefix_map os.environ['IDF_MIRROR_PREFIX_MAP'] = mirror_prefix_map
temp_tools_dir = tempfile.mkdtemp(prefix='idf_tools_tmp') cls.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
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() output_stream = StringIO()
with redirect_stdout(output_stream): with redirect_stdout(output_stream):
idf_tools.main(['list']) idf_tools.main(action)
output = output_stream.getvalue() output = output_stream.getvalue()
return output
xtensa_esp32_elf_version = 'esp-2021r1-8.4.0' def test_usage_basic(self):
esp32ulp_version = '2.28.51-esp-20191205' 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) required_tools_installed = 7
self.assertIn('- %s (recommended)' % xtensa_esp32_elf_version, output) output = self.run_idf_tools_with_action(['install'])
self.assertIn('* esp32ulp-elf', output) self.check_install_tool(OPENOCD,OPENOCD_VERSION,output)
self.assertIn('- %s (recommended)' % esp32ulp_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() output = self.run_idf_tools_with_action(['check'])
with redirect_stdout(output_stream): self.assertIn('version installed in tools directory: ' + ESP32ULP_VERSION, output)
idf_tools.main(['install']) self.assertIn('version installed in tools directory: ' + ESP32S2ULP_VERSION, output)
output = output_stream.getvalue() self.assertIn('version installed in tools directory: ' + OPENOCD_VERSION, output)
self.assertIn('version installed in tools directory: ' + RISC_VERSION, output)
self.assertIn('Installing esp32ulp-elf@' + esp32ulp_version, output) self.assertIn('version installed in tools directory: ' + XTENSA_ESP32_ELF_VERSION, output)
self.assertIn('Downloading binutils-esp32ulp', output) self.assertIn('version installed in tools directory: ' + XTENSA_ESP32S2_ELF_VERSION, output)
self.assertIn('Installing xtensa-esp32-elf@' + xtensa_esp32_elf_version, output) self.assertIn('version installed in tools directory: ' + XTENSA_ESP32S3_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(['export'])
self.assertIn('%s/tools/esp32ulp-elf/%s/esp32ulp-elf-binutils/bin' % 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' % 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): class TestMaintainer(unittest.TestCase):

View File

@ -13,6 +13,9 @@
"install": "always", "install": "always",
"license": "GPL-3.0-with-GCC-exception", "license": "GPL-3.0-with-GCC-exception",
"name": "xtensa-esp32-elf", "name": "xtensa-esp32-elf",
"supported_targets": [
"esp32"
],
"version_cmd": [ "version_cmd": [
"xtensa-esp32-elf-gcc", "xtensa-esp32-elf-gcc",
"--version" "--version"
@ -69,6 +72,9 @@
"install": "always", "install": "always",
"license": "GPL-3.0-with-GCC-exception", "license": "GPL-3.0-with-GCC-exception",
"name": "xtensa-esp32s2-elf", "name": "xtensa-esp32s2-elf",
"supported_targets": [
"esp32s2"
],
"version_cmd": [ "version_cmd": [
"xtensa-esp32s2-elf-gcc", "xtensa-esp32s2-elf-gcc",
"--version" "--version"
@ -125,6 +131,9 @@
"install": "always", "install": "always",
"license": "GPL-3.0-with-GCC-exception", "license": "GPL-3.0-with-GCC-exception",
"name": "xtensa-esp32s3-elf", "name": "xtensa-esp32s3-elf",
"supported_targets": [
"esp32s3"
],
"version_cmd": [ "version_cmd": [
"xtensa-esp32s3-elf-gcc", "xtensa-esp32s3-elf-gcc",
"--version" "--version"
@ -181,6 +190,9 @@
"install": "always", "install": "always",
"license": "GPL-3.0-with-GCC-exception", "license": "GPL-3.0-with-GCC-exception",
"name": "riscv32-esp-elf", "name": "riscv32-esp-elf",
"supported_targets": [
"esp32c3"
],
"version_cmd": [ "version_cmd": [
"riscv32-esp-elf-gcc", "riscv32-esp-elf-gcc",
"--version" "--version"
@ -245,6 +257,9 @@
] ]
} }
], ],
"supported_targets": [
"esp32"
],
"version_cmd": [ "version_cmd": [
"esp32ulp-elf-as", "esp32ulp-elf-as",
"--version" "--version"
@ -303,6 +318,9 @@
] ]
} }
], ],
"supported_targets": [
"esp32s2"
],
"version_cmd": [ "version_cmd": [
"esp32s2ulp-elf-as", "esp32s2ulp-elf-as",
"--version" "--version"
@ -374,6 +392,9 @@
} }
], ],
"strip_container_dirs": 1, "strip_container_dirs": 1,
"supported_targets": [
"all"
],
"version_cmd": [ "version_cmd": [
"cmake", "cmake",
"--version" "--version"
@ -429,6 +450,9 @@
] ]
} }
], ],
"supported_targets": [
"all"
],
"version_cmd": [ "version_cmd": [
"openocd", "openocd",
"--version" "--version"
@ -487,6 +511,9 @@
] ]
} }
], ],
"supported_targets": [
"all"
],
"version_cmd": [ "version_cmd": [
"ninja", "ninja",
"--version" "--version"
@ -535,6 +562,9 @@
] ]
} }
], ],
"supported_targets": [
"all"
],
"version_cmd": [ "version_cmd": [
"idf.py.exe", "idf.py.exe",
"-v" "-v"
@ -579,6 +609,9 @@
] ]
} }
], ],
"supported_targets": [
"all"
],
"version_cmd": [ "version_cmd": [
"ccache.exe", "ccache.exe",
"--version" "--version"
@ -616,6 +649,10 @@
] ]
} }
], ],
"supported_targets": [
"esp32s2",
"esp32s3"
],
"version_cmd": [ "version_cmd": [
"dfu-util", "dfu-util",
"--version" "--version"

View File

@ -55,6 +55,10 @@
"$ref": "#/definitions/arrayOfStrings", "$ref": "#/definitions/arrayOfStrings",
"description": "Command to be executed (along with any extra arguments). The executable be present in one of the export_paths." "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": { "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.", "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" "$ref": "#/definitions/regex"
@ -215,6 +219,10 @@
"description": "Platform-specific replacement for toolInfo/version_cmd", "description": "Platform-specific replacement for toolInfo/version_cmd",
"$ref": "#/definitions/arrayOfStrings" "$ref": "#/definitions/arrayOfStrings"
}, },
"supported_targets": {
"description": "Platform-specific replacement for toolInfo/supported_targets",
"$ref": "#/definitions/arrayOfStrings"
},
"version_regex": { "version_regex": {
"description": "Platform-specific replacement for toolInfo/version_regex", "description": "Platform-specific replacement for toolInfo/version_regex",
"$ref": "#/definitions/regex" "$ref": "#/definitions/regex"