From 4334108cc72a8a5c39b01b048975b0e4a7c3856b Mon Sep 17 00:00:00 2001 From: nekleo <96453741+nekleo@users.noreply.github.com> Date: Sat, 25 Mar 2023 06:51:56 -0700 Subject: [PATCH] Add JSON as a format option for `targets` command in `build_examples.py` (#25810) * Add JSON as a format option for `targets` command The `targets` command outputs the targets that are available for the `build` and `gen` commands in a string format that is easy to read but hard to parse. This change adds a option for the `targets` command to output JSON so that the available targets can be more easily parsed. To do this, ToDict methods were added to BuildTarget and TargetPart classes. When the `--format json` option is used with the `targets` command `build_examples.py` calls the ToDict method of each BuildTarget object and outputs to stdout a list of Dicts in JSON, one for each BuildTarget. * Restyled by autopep8 * Restyled by isort * Simplfy code (loops) for creating Dicts and Lists Simplied the code that ceates dictionaries and lists from data contained within the BuildTarget and TargetPart objects. Also, corrected some comments, and put List and Dict types where appropriate. * Fixed BuildTarget ToDict method BuildTarget ToDict method was incorrectly converting the fixed_targets list to a dictionary, losing data. * Changed ToDict of BuildTarget to use a list of lists. Each time AppendFixedTargets method of BuildTarget is called, a list of TargetPart objects is appended to the fixed_targets list. This change perserves the developer's intent by keeping the list of lists structure intact rather than flatting it out into one list. --------- Co-authored-by: Restyled.io --- scripts/build/build/target.py | 59 +++++++++++++++++++++++++++++++++ scripts/build/build_examples.py | 29 ++++++++++------ 2 files changed, 78 insertions(+), 10 deletions(-) diff --git a/scripts/build/build/target.py b/scripts/build/build/target.py index 63c278a233cb57..8411ff9432c2c7 100644 --- a/scripts/build/build/target.py +++ b/scripts/build/build/target.py @@ -95,6 +95,27 @@ def Accept(self, full_input: str): return True + def ToDict(self): + """Converts a TargetPart into a dictionary + """ + + result: Dict[str, str] = {} + result['name'] = self.name + + build_arguments: Dict[str, str] = {} + for key, value in self.build_arguments.items(): + build_arguments[key] = str(value) + + result['build_arguments'] = build_arguments + + if self.only_if_re is not None: + result['only_if_re'] = str(self.only_if_re.pattern) + + if self.except_if_re is not None: + result['except_if_re'] = str(self.except_if_re.pattern) + + return result + def _HasVariantPrefix(value: str, prefix: str): """Checks if the given value is or starts with "-". @@ -264,6 +285,44 @@ def HumanString(self): return result + def ToDict(self): + """Outputs a parseable description of the available variants + and modifiers: + + like: + + { + "name": "foo" + "shorthand": "foo-bar-baz[-m1]" + "parts": [ + { + "name": "foo", + "build_arguments": { + "board": "bar" + } + } + { + "name": "baz", + "build_arguments": { + "app": "foo.baz" + } + } + ], + "modifiers": [ + { + "name": "modifier1", + "m1": "True" + } + ] + } + """ + return { + 'name': self.name, + 'shorthand': self.HumanString(), + 'parts': [[part.ToDict() for part in target] for target in self.fixed_targets], + 'modifiers': [part.ToDict() for part in self.modifiers] + } + def AllVariants(self) -> Iterable[str]: """Returns all possible accepted variants by this target. diff --git a/scripts/build/build_examples.py b/scripts/build/build_examples.py index c70a5da7981d49..a52c9aa6f3e131 100755 --- a/scripts/build/build_examples.py +++ b/scripts/build/build_examples.py @@ -14,6 +14,7 @@ # See the License for the specific language governing permissions and # limitations under the License. +import json import logging import os import sys @@ -177,21 +178,29 @@ def cmd_generate(context): @main.command( 'targets', - help=('List the targets that would be generated/built given ' - 'the input arguments')) + help=('Lists the targets that can be used with the build and gen commands')) @click.option( - '--expand', - default=False, - is_flag=True, - help='Expand all possible targets rather than the shorthand string') + '--format', + default='summary', + type=click.Choice(['summary', 'expanded', 'json'], case_sensitive=False), + help=""" + summary - list of shorthand strings summarzing the available targets; + + expanded - list all possible targets rather than the shorthand string; + + json - a JSON representation of the available targets + """) @click.pass_context -def cmd_targets(context, expand): - for target in build.targets.BUILD_TARGETS: - if expand: +def cmd_targets(context, format): + if format == 'expanded': + for target in build.targets.BUILD_TARGETS: build.target.report_rejected_parts = False for s in target.AllVariants(): print(s) - else: + elif format == 'json': + print(json.dumps([target.ToDict() for target in build.targets.BUILD_TARGETS], indent=4)) + else: + for target in build.targets.BUILD_TARGETS: print(target.HumanString())