Explorar el Código

Tools: Export selected target actions

Added option --json to action help, for export selected target actions
Marek Fiala hace 3 años
padre
commit
9c0969b512

+ 8 - 16
tools/idf.py

@@ -37,8 +37,8 @@ import python_version_checker  # noqa: E402
 
 try:
     from idf_py_actions.errors import FatalError  # noqa: E402
-    from idf_py_actions.tools import (PropertyDict, executable_exists, idf_version, merge_action_lists,  # noqa: E402
-                                      realpath)
+    from idf_py_actions.tools import (PropertyDict, executable_exists, get_target, idf_version,  # noqa: E402
+                                      merge_action_lists, realpath)
 except ImportError:
     # For example, importing click could cause this.
     print('Please use idf.py only in an ESP-IDF shell environment.', file=sys.stderr)
@@ -376,6 +376,7 @@ def init_cli(verbose_output: List=None) -> Any:
                 chain=True,
                 invoke_without_command=True,
                 result_callback=self.execute_tasks,
+                no_args_is_help=True,
                 context_settings={'max_content_width': 140},
                 help=help,
             )
@@ -530,10 +531,6 @@ def init_cli(verbose_output: List=None) -> Any:
             ctx = click.get_current_context()
             global_args = PropertyDict(kwargs)
 
-            def _help_and_exit() -> None:
-                print(ctx.get_help())
-                ctx.exit()
-
             # Show warning if some tasks are present several times in the list
             dupplicated_tasks = sorted(
                 [item for item, count in Counter(task.name for task in tasks).items() if count > 1])
@@ -546,10 +543,6 @@ def init_cli(verbose_output: List=None) -> Any:
                     'Only first occurrence will be executed.')
 
             for task in tasks:
-                # Show help and exit if help is in the list of commands
-                if task.name == 'help':
-                    _help_and_exit()
-
                 # Set propagated global options.
                 # These options may be set on one subcommand, but available in the list of global arguments
                 for key in list(task.action_args):
@@ -577,10 +570,6 @@ def init_cli(verbose_output: List=None) -> Any:
             for action_callback in ctx.command.global_action_callbacks:
                 action_callback(ctx, global_args, tasks)
 
-            # Always show help when command is not provided
-            if not tasks:
-                _help_and_exit()
-
             # Build full list of tasks to and deal with dependencies and order dependencies
             tasks_to_run: OrderedDict = OrderedDict()
             while tasks:
@@ -634,7 +623,9 @@ def init_cli(verbose_output: List=None) -> Any:
                     if task.aliases:
                         name_with_aliases += ' (aliases: %s)' % ', '.join(task.aliases)
 
-                    print('Executing action: %s' % name_with_aliases)
+                    # When machine-readable json format for help is printed, don't show info about executing action so the output is deserializable
+                    if name_with_aliases != 'help' or not task.action_args.get('json_option', False):
+                        print('Executing action: %s' % name_with_aliases)
                     task(ctx, global_args, task.action_args)
 
                 self._print_closing_message(global_args, tasks_to_run.keys())
@@ -715,7 +706,8 @@ def init_cli(verbose_output: List=None) -> Any:
 
     cli_help = (
         'ESP-IDF CLI build management tool. '
-        'For commands that are not known to idf.py an attempt to execute it as a build system target will be made.')
+        'For commands that are not known to idf.py an attempt to execute it as a build system target will be made. '
+        'Selected target: {}'.format(get_target(project_dir)))
 
     return CLI(help=cli_help, verbose_output=verbose_output, all_actions=all_actions)
 

+ 44 - 2
tools/idf_py_actions/core_ext.py

@@ -1,6 +1,7 @@
 # SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
 # SPDX-License-Identifier: Apache-2.0
 import fnmatch
+import json
 import locale
 import os
 import re
@@ -193,7 +194,7 @@ def action_extensions(base_actions: Dict, project_path: str) -> Any:
         for target in SUPPORTED_TARGETS:
             print(target)
 
-        if 'preview' in ctx.params:
+        if ctx.params.get('preview'):
             for target in PREVIEW_TARGETS:
                 print(target)
 
@@ -238,6 +239,24 @@ def action_extensions(base_actions: Dict, project_path: str) -> Any:
             language = 'en'
         return language
 
+    def help_and_exit(action: str, ctx: Context, param: List, json_option: bool, add_options: bool) -> None:
+        if json_option:
+            output_dict = {}
+            output_dict['target'] = get_target(param.project_dir)  # type: ignore
+            output_dict['actions'] = []
+            actions = ctx.to_info_dict().get('command').get('commands')
+            for a in actions:
+                action_info = {}
+                action_info['name'] = a
+                action_info['description'] = actions[a].get('help')
+                if add_options:
+                    action_info['options'] = actions[a].get('params')
+                output_dict['actions'].append(action_info)
+            print(json.dumps(output_dict, sort_keys=True, indent=4))
+        else:
+            print(ctx.get_help())
+        ctx.exit()
+
     root_options = {
         'global_options': [
             {
@@ -286,6 +305,7 @@ def action_extensions(base_actions: Dict, project_path: str) -> Any:
             {
                 'names': ['--preview'],
                 'help': 'Enable IDF features that are still in preview.',
+                'is_eager': True,
                 'is_flag': True,
                 'default': False,
             },
@@ -530,4 +550,26 @@ def action_extensions(base_actions: Dict, project_path: str) -> Any:
         }
     }
 
-    return merge_action_lists(root_options, build_actions, clean_actions)
+    help_action = {
+        'actions': {
+            'help': {
+                'callback': help_and_exit,
+                'help': 'Show help message and exit.',
+                'hidden': True,
+                'options': [
+                    {
+                        'names': ['--json', 'json_option'],
+                        'is_flag': True,
+                        'help': 'Print out actions in machine-readable format for selected target.'
+                    },
+                    {
+                        'names': ['--add-options'],
+                        'is_flag': True,
+                        'help': 'Add options about actions to machine-readable format.'
+                    }
+                ],
+            }
+        }
+    }
+
+    return merge_action_lists(root_options, build_actions, clean_actions, help_action)

+ 46 - 0
tools/test_idf_py/idf_py_help_schema.json

@@ -0,0 +1,46 @@
+{
+    "$schema": "http://json-schema.org/draft-07/schema#",
+    "$id": "https://github.com/espressif/esp-idf/blob/master/tools/test_idf_py/idf_py_help_schema.json",
+    "type": "object",
+    "properties": {
+        "target": {
+            "type": ["string", "null"],
+            "description": "Selected target"
+        },
+        "actions": {
+            "type": "array",
+            "description": "List of supported actions",
+            "items": {
+                "$ref": "#/definitions/actionInfo"
+            }
+        }
+    },
+    "required": [
+        "target",
+        "actions"
+    ],
+    "definitions": {
+        "actionInfo": {
+            "type": "object",
+            "description": "Information about one action",
+            "properties": {
+                "name" : {
+                    "description": "Action name",
+                    "type": "string"
+                },
+                "description" : {
+                    "description": "Description of the action",
+                    "type": "string"
+                },
+                "options": {
+                    "description": "Additional info about action's options",
+                    "type": "array"
+                }
+            },
+            "required": [
+                "name",
+                "description"
+            ]
+        }
+    }
+}

+ 19 - 0
tools/test_idf_py/test_idf_py.py

@@ -3,11 +3,14 @@
 # SPDX-FileCopyrightText: 2019-2022 Espressif Systems (Shanghai) CO LTD
 # SPDX-License-Identifier: Apache-2.0
 
+import json
 import os
 import subprocess
 import sys
 from unittest import TestCase, main, mock
 
+import jsonschema
+
 try:
     from StringIO import StringIO
 except ImportError:
@@ -227,5 +230,21 @@ class TestDeprecations(TestWithoutExtensions):
         self.assertNotIn('"test_0" is deprecated', output)
 
 
+class TestHelpOutput(TestWithoutExtensions):
+    def test_output(self):
+        def action_test(commands, schema):
+            output_file = 'idf_py_help_output.json'
+            with open(output_file, 'w') as outfile:
+                subprocess.run(commands, env=os.environ, stdout=outfile)
+            with open(output_file, 'r') as outfile:
+                help_obj = json.load(outfile)
+            self.assertIsNone(jsonschema.validate(help_obj, schema))
+
+        with open(os.path.join(current_dir, 'idf_py_help_schema.json'), 'r') as schema_file:
+            schema_json = json.load(schema_file)
+        action_test(['idf.py', 'help', '--json'], schema_json)
+        action_test(['idf.py', 'help', '--json', '--add-options'], schema_json)
+
+
 if __name__ == '__main__':
     main()