mirror of
https://github.com/espressif/esp-idf.git
synced 2026-09-22 13:01:16 +03:00
feat(tools): Add 'check' field to idf.py actions
This commit is contained in:
16
tools/idf.py
16
tools/idf.py
@@ -255,6 +255,7 @@ def init_cli(verbose_output: list | None = None) -> Any:
|
|||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
callback: Callable,
|
callback: Callable,
|
||||||
|
check: Callable | None,
|
||||||
name: str,
|
name: str,
|
||||||
aliases: list,
|
aliases: list,
|
||||||
dependencies: list | None,
|
dependencies: list | None,
|
||||||
@@ -262,6 +263,7 @@ def init_cli(verbose_output: list | None = None) -> Any:
|
|||||||
action_args: dict,
|
action_args: dict,
|
||||||
) -> None:
|
) -> None:
|
||||||
self.callback = callback
|
self.callback = callback
|
||||||
|
self.check = check
|
||||||
self.name = name
|
self.name = name
|
||||||
self.dependencies = dependencies
|
self.dependencies = dependencies
|
||||||
self.order_dependencies = order_dependencies
|
self.order_dependencies = order_dependencies
|
||||||
@@ -274,6 +276,15 @@ def init_cli(verbose_output: list | None = None) -> Any:
|
|||||||
|
|
||||||
self.callback(self.name, context, global_args, **action_args)
|
self.callback(self.name, context, global_args, **action_args)
|
||||||
|
|
||||||
|
def check_requirements(
|
||||||
|
self, context: click.core.Context, global_args: PropertyDict, action_args: dict | None = None
|
||||||
|
) -> bool:
|
||||||
|
if self.check is None:
|
||||||
|
return True
|
||||||
|
if action_args is None:
|
||||||
|
action_args = self.action_args
|
||||||
|
return bool(self.check(self.name, context, global_args, **action_args))
|
||||||
|
|
||||||
class Action(click.RichCommand):
|
class Action(click.RichCommand):
|
||||||
callback: Callable
|
callback: Callable
|
||||||
|
|
||||||
@@ -284,6 +295,7 @@ def init_cli(verbose_output: list | None = None) -> Any:
|
|||||||
deprecated: dict | str | bool = False,
|
deprecated: dict | str | bool = False,
|
||||||
dependencies: list | None = None,
|
dependencies: list | None = None,
|
||||||
order_dependencies: list | None = None,
|
order_dependencies: list | None = None,
|
||||||
|
check: Callable | None = None,
|
||||||
hidden: bool = False,
|
hidden: bool = False,
|
||||||
**kwargs: Any,
|
**kwargs: Any,
|
||||||
) -> None:
|
) -> None:
|
||||||
@@ -326,6 +338,7 @@ def init_cli(verbose_output: list | None = None) -> Any:
|
|||||||
def wrapped_callback(**action_args: Any) -> Task:
|
def wrapped_callback(**action_args: Any) -> Task:
|
||||||
return Task(
|
return Task(
|
||||||
callback=self.unwrapped_callback,
|
callback=self.unwrapped_callback,
|
||||||
|
check=check,
|
||||||
name=self.name,
|
name=self.name,
|
||||||
dependencies=dependencies,
|
dependencies=dependencies,
|
||||||
order_dependencies=order_dependencies,
|
order_dependencies=order_dependencies,
|
||||||
@@ -796,6 +809,9 @@ def init_cli(verbose_output: list | None = None) -> Any:
|
|||||||
|
|
||||||
dependecies_processed = True
|
dependecies_processed = True
|
||||||
|
|
||||||
|
if not task.check_requirements(ctx, global_args, task.action_args):
|
||||||
|
raise FatalError(f'Action "{task.name}" cannot run in the current project configuration.')
|
||||||
|
|
||||||
# If task have some dependencies they have to be executed before the task.
|
# If task have some dependencies they have to be executed before the task.
|
||||||
for dep in task.dependencies:
|
for dep in task.dependencies:
|
||||||
if dep not in tasks_to_run.keys():
|
if dep not in tasks_to_run.keys():
|
||||||
|
|||||||
@@ -1,24 +1,29 @@
|
|||||||
# SPDX-FileCopyrightText: 2022-2026 Espressif Systems (Shanghai) CO LTD
|
# SPDX-FileCopyrightText: 2022-2026 Espressif Systems (Shanghai) CO LTD
|
||||||
# SPDX-License-Identifier: Apache-2.0
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
import os
|
|
||||||
|
|
||||||
from rich_click import Context
|
from rich_click import Context
|
||||||
|
|
||||||
from idf_py_actions.errors import FatalError
|
from idf_py_actions.errors import FatalError
|
||||||
from idf_py_actions.tools import PropertyDict
|
from idf_py_actions.tools import PropertyDict
|
||||||
from idf_py_actions.tools import ensure_build_directory
|
from idf_py_actions.tools import ensure_build_directory
|
||||||
|
from idf_py_actions.tools import get_sdkconfig_filename
|
||||||
from idf_py_actions.tools import get_sdkconfig_value
|
from idf_py_actions.tools import get_sdkconfig_value
|
||||||
|
from idf_py_actions.tools import red_print
|
||||||
from idf_py_actions.tools import run_target
|
from idf_py_actions.tools import run_target
|
||||||
|
|
||||||
SOC_USB_DFU_SUPPORTED = 'CONFIG_SOC_USB_DFU_SUPPORTED'
|
SOC_USB_DFU_SUPPORTED = 'CONFIG_SOC_USB_DFU_SUPPORTED'
|
||||||
|
|
||||||
|
|
||||||
def _soc_usb_dfu_supported(project_path: str) -> bool:
|
|
||||||
return bool(get_sdkconfig_value(os.path.join(project_path, 'sdkconfig'), SOC_USB_DFU_SUPPORTED) == 'y')
|
|
||||||
|
|
||||||
|
|
||||||
def action_extensions(base_actions: dict, project_path: str) -> dict:
|
def action_extensions(base_actions: dict, project_path: str) -> dict:
|
||||||
|
def check_dfu_supported(target_name: str, ctx: Context, args: PropertyDict, **kwargs: str) -> bool:
|
||||||
|
sdkconfig_path = get_sdkconfig_filename(args)
|
||||||
|
if get_sdkconfig_value(sdkconfig_path, SOC_USB_DFU_SUPPORTED) == 'y':
|
||||||
|
return True
|
||||||
|
|
||||||
|
target = get_sdkconfig_value(sdkconfig_path, 'CONFIG_IDF_TARGET') or 'unknown'
|
||||||
|
red_print(f'DFU is not supported for this target: {target}')
|
||||||
|
return False
|
||||||
|
|
||||||
def dfu_target(target_name: str, ctx: Context, args: PropertyDict, part_size: str) -> None:
|
def dfu_target(target_name: str, ctx: Context, args: PropertyDict, part_size: str) -> None:
|
||||||
ensure_build_directory(args, ctx.info_name)
|
ensure_build_directory(args, ctx.info_name)
|
||||||
run_target(target_name, args, {'ESP_DFU_PART_SIZE': part_size} if part_size else {})
|
run_target(target_name, args, {'ESP_DFU_PART_SIZE': part_size} if part_size else {})
|
||||||
@@ -44,6 +49,7 @@ def action_extensions(base_actions: dict, project_path: str) -> dict:
|
|||||||
'actions': {
|
'actions': {
|
||||||
'dfu': {
|
'dfu': {
|
||||||
'callback': dfu_target,
|
'callback': dfu_target,
|
||||||
|
'check': check_dfu_supported,
|
||||||
'short_help': 'Build the DFU binary',
|
'short_help': 'Build the DFU binary',
|
||||||
'dependencies': ['all'],
|
'dependencies': ['all'],
|
||||||
'options': [
|
'options': [
|
||||||
@@ -57,11 +63,13 @@ def action_extensions(base_actions: dict, project_path: str) -> dict:
|
|||||||
},
|
},
|
||||||
'dfu-list': {
|
'dfu-list': {
|
||||||
'callback': dfu_list_target,
|
'callback': dfu_list_target,
|
||||||
|
'check': check_dfu_supported,
|
||||||
'short_help': 'List DFU capable devices',
|
'short_help': 'List DFU capable devices',
|
||||||
'dependencies': [],
|
'dependencies': [],
|
||||||
},
|
},
|
||||||
'dfu-flash': {
|
'dfu-flash': {
|
||||||
'callback': dfu_flash_target,
|
'callback': dfu_flash_target,
|
||||||
|
'check': check_dfu_supported,
|
||||||
'short_help': 'Flash the DFU binary',
|
'short_help': 'Flash the DFU binary',
|
||||||
'order_dependencies': ['dfu'],
|
'order_dependencies': ['dfu'],
|
||||||
'options': [
|
'options': [
|
||||||
@@ -77,4 +85,4 @@ def action_extensions(base_actions: dict, project_path: str) -> dict:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return dfu_actions if _soc_usb_dfu_supported(project_path) else {}
|
return dfu_actions
|
||||||
|
|||||||
@@ -988,19 +988,12 @@ def get_sdkconfig_value(sdkconfig_file: str, key: str) -> str | None:
|
|||||||
pattern = re.compile(rf'^{key}=\"?([^\"]*)\"?$')
|
pattern = re.compile(rf'^{key}=\"?([^\"]*)\"?$')
|
||||||
with open(sdkconfig_file, encoding='utf-8') as f:
|
with open(sdkconfig_file, encoding='utf-8') as f:
|
||||||
for line in f:
|
for line in f:
|
||||||
match = re.match(pattern, line)
|
match = re.match(pattern, line.strip())
|
||||||
if match:
|
if match:
|
||||||
value = match.group(1)
|
value = match.group(1)
|
||||||
return value
|
return value
|
||||||
|
|
||||||
|
|
||||||
def is_target_supported(project_path: str, supported_targets: list) -> bool:
|
|
||||||
"""
|
|
||||||
Returns True if the active target is supported, or False otherwise.
|
|
||||||
"""
|
|
||||||
return get_target(project_path) in supported_targets
|
|
||||||
|
|
||||||
|
|
||||||
def _check_idf_target(
|
def _check_idf_target(
|
||||||
args: 'PropertyDict', prog_name: str, cache: dict, cache_cmdl: dict, env: dict | None = None
|
args: 'PropertyDict', prog_name: str, cache: dict, cache_cmdl: dict, env: dict | None = None
|
||||||
) -> None:
|
) -> None:
|
||||||
|
|||||||
@@ -175,11 +175,17 @@ def test_build_fail_on_build_time(idf_py: IdfPyFunc, test_app_copy: Path) -> Non
|
|||||||
|
|
||||||
@pytest.mark.usefixtures('test_app_copy')
|
@pytest.mark.usefixtures('test_app_copy')
|
||||||
def test_build_dfu(idf_py: IdfPyFunc) -> None:
|
def test_build_dfu(idf_py: IdfPyFunc) -> None:
|
||||||
logging.info('DFU build works')
|
logging.info('DFU is rejected for targets without USB DFU support')
|
||||||
|
idf_py('set-target', 'esp32')
|
||||||
ret = idf_py('dfu', check=False)
|
ret = idf_py('dfu', check=False)
|
||||||
assert 'command "dfu" is not known to idf.py and is not a Ninja target' in ret.stderr, (
|
assert ret.returncode != 0
|
||||||
'DFU build should fail for default chip target'
|
assert 'DFU is not supported for this target: esp32' in ret.stderr
|
||||||
|
assert 'Action "dfu" cannot run in the current project configuration.' in ret.stderr
|
||||||
|
assert 'Adding "dfu"\'s dependency "all"' not in ret.stdout, (
|
||||||
|
'DFU check must fail before the "all" dependency is scheduled'
|
||||||
)
|
)
|
||||||
|
|
||||||
|
logging.info('DFU build works for esp32s2')
|
||||||
idf_py('set-target', 'esp32s2')
|
idf_py('set-target', 'esp32s2')
|
||||||
ret = idf_py('dfu')
|
ret = idf_py('dfu')
|
||||||
assert 'build/dfu.bin" has been written. You may proceed with DFU flashing.' in ret.stdout, (
|
assert 'build/dfu.bin" has been written. You may proceed with DFU flashing.' in ret.stdout, (
|
||||||
|
|||||||
Reference in New Issue
Block a user