Skip to content

Commit 4c5ba48

Browse files
committed
Merge branch 'tools/use_recommended_tool_priority' into 'release/v5.0'
fix (idf_tools): Opt for the recommended tool in tools.json rather than the supported one (v5.0) See merge request espressif/esp-idf!27794
2 parents ed375f2 + d174336 commit 4c5ba48

File tree

3 files changed

+151
-56
lines changed

3 files changed

+151
-56
lines changed

.gitlab-ci.yml

+2-2
Original file line numberDiff line numberDiff line change
@@ -129,8 +129,8 @@ cache:
129129
export PYTHONPATH="$IDF_PATH/tools:$IDF_PATH/tools/esp_app_trace:$IDF_PATH/components/partition_table:$IDF_PATH/tools/ci/python_packages:$PYTHONPATH"
130130

131131
.setup_tools_and_idf_python_venv: &setup_tools_and_idf_python_venv |
132-
# must use after setup_tools_except_target_test
133-
# otherwise the export.sh won't work properly
132+
# Since the version 3.21 CMake passes source files and include dirs to ninja using absolute paths.
133+
$IDF_PATH/tools/idf_tools.py --non-interactive install cmake
134134

135135
# download constraint file for dev
136136
if [[ -n "$CI_PYTHON_CONSTRAINT_BRANCH" ]]; then

tools/idf_tools.py

+93-53
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
#!/usr/bin/env python
22
# coding=utf-8
33
#
4-
# SPDX-FileCopyrightText: 2019-2022 Espressif Systems (Shanghai) CO LTD
4+
# SPDX-FileCopyrightText: 2019-2023 Espressif Systems (Shanghai) CO LTD
55
#
66
# SPDX-License-Identifier: Apache-2.0
77
#
@@ -1568,6 +1568,94 @@ def action_check(args): # type: ignore
15681568
raise SystemExit(1)
15691569

15701570

1571+
# The following functions are used in process_tool which is a part of the action_export.
1572+
def handle_recommended_version_to_use(
1573+
tool,
1574+
tool_name,
1575+
version_to_use,
1576+
prefer_system_hint,
1577+
): # type: (IDFTool, str, str, str) -> Tuple[list, dict]
1578+
tool_export_paths = tool.get_export_paths(version_to_use)
1579+
tool_export_vars = tool.get_export_vars(version_to_use)
1580+
if tool.version_in_path and tool.version_in_path not in tool.versions:
1581+
info('Not using an unsupported version of tool {} found in PATH: {}.'.format(
1582+
tool.name, tool.version_in_path) + prefer_system_hint, f=sys.stderr)
1583+
return tool_export_paths, tool_export_vars
1584+
1585+
1586+
def handle_supported_or_deprecated_version(tool, tool_name): # type: (IDFTool, str) -> None
1587+
version_obj: IDFToolVersion = tool.versions[tool.version_in_path] # type: ignore
1588+
if version_obj.status == IDFToolVersion.STATUS_SUPPORTED:
1589+
info('Using a supported version of tool {} found in PATH: {}.'.format(tool_name, tool.version_in_path),
1590+
f=sys.stderr)
1591+
info('However the recommended version is {}.'.format(tool.get_recommended_version()),
1592+
f=sys.stderr)
1593+
elif version_obj.status == IDFToolVersion.STATUS_DEPRECATED:
1594+
warn('using a deprecated version of tool {} found in PATH: {}'.format(tool_name, tool.version_in_path))
1595+
1596+
1597+
def handle_missing_versions(
1598+
tool,
1599+
tool_name,
1600+
install_cmd,
1601+
prefer_system_hint
1602+
): # type: (IDFTool, str, str, str) -> None
1603+
fatal('tool {} has no installed versions. Please run \'{}\' to install it.'.format(
1604+
tool.name, install_cmd))
1605+
if tool.version_in_path and tool.version_in_path not in tool.versions:
1606+
info('An unsupported version of tool {} was found in PATH: {}. '.format(tool_name, tool.version_in_path) +
1607+
prefer_system_hint, f=sys.stderr)
1608+
1609+
1610+
def process_tool(
1611+
tool,
1612+
tool_name,
1613+
args,
1614+
install_cmd,
1615+
prefer_system_hint
1616+
): # type: (IDFTool, str, argparse.Namespace, str, str) -> Tuple[list, dict, bool]
1617+
tool_found: bool = True
1618+
tool_export_paths: List[str] = []
1619+
tool_export_vars: Dict[str, str] = {}
1620+
1621+
tool.find_installed_versions()
1622+
recommended_version_to_use = tool.get_preferred_installed_version()
1623+
1624+
if not tool.is_executable and recommended_version_to_use:
1625+
tool_export_vars = tool.get_export_vars(recommended_version_to_use)
1626+
return tool_export_paths, tool_export_vars, tool_found
1627+
1628+
if recommended_version_to_use and not args.prefer_system:
1629+
tool_export_paths, tool_export_vars = handle_recommended_version_to_use(
1630+
tool, tool_name, recommended_version_to_use, prefer_system_hint
1631+
)
1632+
return tool_export_paths, tool_export_vars, tool_found
1633+
1634+
if tool.version_in_path:
1635+
if tool.version_in_path not in tool.versions:
1636+
# unsupported version
1637+
if args.prefer_system: # type: ignore
1638+
warn('using an unsupported version of tool {} found in PATH: {}'.format(
1639+
tool.name, tool.version_in_path))
1640+
return tool_export_paths, tool_export_vars, tool_found
1641+
else:
1642+
# unsupported version in path
1643+
pass
1644+
else:
1645+
# supported/deprecated version in PATH, use it
1646+
handle_supported_or_deprecated_version(tool, tool_name)
1647+
return tool_export_paths, tool_export_vars, tool_found
1648+
1649+
if not tool.versions_installed:
1650+
if tool.get_install_type() == IDFTool.INSTALL_ALWAYS:
1651+
handle_missing_versions(tool, tool_name, install_cmd, prefer_system_hint)
1652+
tool_found = False
1653+
# If a tool found, but it is optional and does not have versions installed, use whatever is in PATH.
1654+
return tool_export_paths, tool_export_vars, tool_found
1655+
1656+
return tool_export_paths, tool_export_vars, tool_found
1657+
1658+
15711659
def action_export(args): # type: ignore
15721660
if args.deactivate and different_idf_detected():
15731661
deactivate_statement(args)
@@ -1587,58 +1675,10 @@ def action_export(args): # type: ignore
15871675
for name, tool in tools_info.items():
15881676
if tool.get_install_type() == IDFTool.INSTALL_NEVER:
15891677
continue
1590-
tool.find_installed_versions()
1591-
version_to_use = tool.get_preferred_installed_version()
1592-
1593-
if not tool.is_executable and version_to_use:
1594-
tool_export_vars = tool.get_export_vars(version_to_use)
1595-
export_vars = {**export_vars, **tool_export_vars}
1596-
continue
1597-
1598-
if tool.version_in_path:
1599-
if tool.version_in_path not in tool.versions:
1600-
# unsupported version
1601-
if args.prefer_system: # type: ignore
1602-
warn('using an unsupported version of tool {} found in PATH: {}'.format(
1603-
tool.name, tool.version_in_path))
1604-
continue
1605-
else:
1606-
# unsupported version in path
1607-
pass
1608-
else:
1609-
# supported/deprecated version in PATH, use it
1610-
version_obj = tool.versions[tool.version_in_path]
1611-
if version_obj.status == IDFToolVersion.STATUS_SUPPORTED:
1612-
info('Using a supported version of tool {} found in PATH: {}.'.format(name, tool.version_in_path),
1613-
f=sys.stderr)
1614-
info('However the recommended version is {}.'.format(tool.get_recommended_version()),
1615-
f=sys.stderr)
1616-
elif version_obj.status == IDFToolVersion.STATUS_DEPRECATED:
1617-
warn('using a deprecated version of tool {} found in PATH: {}'.format(name, tool.version_in_path))
1618-
continue
1619-
1620-
if not tool.versions_installed:
1621-
if tool.get_install_type() == IDFTool.INSTALL_ALWAYS:
1622-
all_tools_found = False
1623-
fatal('tool {} has no installed versions. Please run \'{}\' to install it.'.format(
1624-
tool.name, install_cmd))
1625-
if tool.version_in_path and tool.version_in_path not in tool.versions:
1626-
info('An unsupported version of tool {} was found in PATH: {}. '.format(name, tool.version_in_path) +
1627-
prefer_system_hint, f=sys.stderr)
1628-
continue
1629-
else:
1630-
# tool is optional, and does not have versions installed
1631-
# use whatever is available in PATH
1632-
continue
1633-
1634-
if tool.version_in_path and tool.version_in_path not in tool.versions:
1635-
info('Not using an unsupported version of tool {} found in PATH: {}.'.format(
1636-
tool.name, tool.version_in_path) + prefer_system_hint, f=sys.stderr)
1637-
1638-
export_paths = tool.get_export_paths(version_to_use)
1639-
if export_paths:
1640-
paths_to_export += export_paths
1641-
tool_export_vars = tool.get_export_vars(version_to_use)
1678+
tool_export_paths, tool_export_vars, tool_found = process_tool(tool, name, args, install_cmd, prefer_system_hint)
1679+
if not tool_found:
1680+
all_tools_found = False
1681+
paths_to_export += tool_export_paths
16421682
export_vars = {**export_vars, **tool_export_vars}
16431683

16441684
current_path = os.getenv('PATH')

tools/test_idf_tools/test_idf_tools.py

+56-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#!/usr/bin/env python
22
#
3-
# SPDX-FileCopyrightText: 2019-2021 Espressif Systems (Shanghai) CO LTD
3+
# SPDX-FileCopyrightText: 2019-2023 Espressif Systems (Shanghai) CO LTD
44
# SPDX-License-Identifier: Apache-2.0
55

66
import json
@@ -78,6 +78,10 @@ class TestUsage(unittest.TestCase):
7878

7979
@classmethod
8080
def setUpClass(cls):
81+
with open(os.path.join(os.getenv('IDF_PATH'), 'tools/tools.json'), 'r') as json_file:
82+
tools_dict = json.load(json_file)
83+
cls.tools_dict = tools_dict
84+
8185
old_tools_dir = os.environ.get('IDF_TOOLS_PATH') or os.path.expanduser(idf_tools.IDF_TOOLS_PATH_DEFAULT)
8286

8387
mirror_prefix_map = None
@@ -390,6 +394,57 @@ def test_deactivate(self):
390394
self.assertTrue(os.path.isfile(deactivate_file), 'File {} was not found. '.format(deactivate_file))
391395
self.assertNotEqual(os.stat(self.idf_env_json).st_size, 0, 'File {} is empty. '.format(deactivate_file))
392396

397+
def test_export_recommended_version(self):
398+
always_install_and_recommended_tools = []
399+
for tool in self.tools_dict['tools']:
400+
if tool['install'] != 'always':
401+
continue
402+
for version in tool['versions']:
403+
if version['status'] != 'recommended':
404+
continue
405+
always_install_and_recommended_tools.append({
406+
'name': tool['name'],
407+
'version': version['name']
408+
})
409+
self.run_idf_tools_with_action(['install'])
410+
output = self.run_idf_tools_with_action(['export'])
411+
412+
for tool in always_install_and_recommended_tools:
413+
self.assertIn(f"{tool['name']}/{tool['version']}", output)
414+
415+
def test_export_recommended_version_cmake(self):
416+
tool_to_test = 'cmake'
417+
tool_version = ''
418+
for tool in self.tools_dict['tools']:
419+
if tool['name'] != tool_to_test:
420+
continue
421+
for version in tool['versions']:
422+
if version['status'] == 'recommended':
423+
tool_version = version['name']
424+
break
425+
426+
self.run_idf_tools_with_action(['install'])
427+
self.run_idf_tools_with_action(['install', tool_to_test])
428+
output = self.run_idf_tools_with_action(['export'])
429+
430+
self.assertIn(f'{tool_to_test}/{tool_version}', output)
431+
432+
def test_export_prefer_system_cmake(self):
433+
tool_to_test = 'cmake'
434+
self.run_idf_tools_with_action(['install'])
435+
self.run_idf_tools_with_action(['install', tool_to_test])
436+
# cmake is installed via apt
437+
output = self.run_idf_tools_with_action(['export', '--prefer-system'])
438+
439+
self.assertNotIn(tool_to_test, output)
440+
441+
def test_export_supported_version_cmake(self):
442+
tool_to_test = 'cmake'
443+
self.run_idf_tools_with_action(['install'])
444+
output = self.run_idf_tools_with_action(['export'])
445+
446+
self.assertNotIn(tool_to_test, output)
447+
393448

394449
class TestMaintainer(unittest.TestCase):
395450

0 commit comments

Comments
 (0)