From e07529b3843903260bfb6c2967d1e21f3b3579d5 Mon Sep 17 00:00:00 2001 From: Ken Leone Date: Thu, 23 Mar 2023 13:47:29 -0700 Subject: [PATCH 1/6] 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. --- scripts/build/build/target.py | 64 ++++++++++++++++++++++++++++++++- scripts/build/build_examples.py | 34 ++++++++++++------ 2 files changed, 87 insertions(+), 11 deletions(-) diff --git a/scripts/build/build/target.py b/scripts/build/build/target.py index 63c278a233cb57..3e98a20668ffdd 100644 --- a/scripts/build/build/target.py +++ b/scripts/build/build/target.py @@ -95,6 +95,25 @@ 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 + bld_args_keys = list(self.build_arguments.keys()) + for key in bld_args_keys: + result[key] = str(self.build_arguments[key]) + + 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 "-". @@ -177,7 +196,6 @@ def _StringIntoParts(full_input: str, remaining_input: str, fixed_targets: List[ # Remaining input is not empty and we failed to match it return None - class BuildTarget: def __init__(self, name, builder_class, **kwargs): @@ -264,6 +282,50 @@ def HumanString(self): return result + def ToDict(self): + """Outputs a parseable description of the available variants + and modifiers: + + like: + + "foo": { + "builder": "", + "shorthand": "foo-bar-baz[-m1] + "fixed_targets": [ + { + "name": "foo", + "board": "bar" + } + { + "name": "baz", + "app": "foo.baz" + } + ], + "modifiers": [ + { + "name": "modifier1", + "m1": "True" + } + ] + }, + """ + result: Dict[str, Any] = {} + + result['name'] = self.name + result['builder'] = str(self.builder_class) + result['shorthand'] = self.HumanString() + result['parts'] = [] + result['modifiers'] = [] + + for target in self.fixed_targets: + for target_part in target: + result['parts'].append(target_part.ToDict()) + + for target_part in self.modifiers: + result['modifiers'].append(target_part.ToDict()) + + return result + 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..4e40c84adce176 100755 --- a/scripts/build/build_examples.py +++ b/scripts/build/build_examples.py @@ -24,6 +24,7 @@ from runner import PrintOnlyRunner, ShellRunner import build +import json sys.path.append(os.path.abspath(os.path.dirname(__file__))) @@ -177,21 +178,34 @@ 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': + targets = [] + + for target in build.targets.BUILD_TARGETS: + targets.append(target.ToDict()) + + print(json.dumps(targets, indent=4)) + else: + for target in build.targets.BUILD_TARGETS: print(target.HumanString()) From 99c81efb5783f79ed7c515177a63ff2427e7d7fd Mon Sep 17 00:00:00 2001 From: "Restyled.io" Date: Thu, 23 Mar 2023 22:57:29 +0000 Subject: [PATCH 2/6] Restyled by autopep8 --- scripts/build/build/target.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/build/build/target.py b/scripts/build/build/target.py index 3e98a20668ffdd..9ed2bc2b74cdb6 100644 --- a/scripts/build/build/target.py +++ b/scripts/build/build/target.py @@ -114,7 +114,6 @@ def ToDict(self): return result - def _HasVariantPrefix(value: str, prefix: str): """Checks if the given value is or starts with "-". @@ -196,6 +195,7 @@ def _StringIntoParts(full_input: str, remaining_input: str, fixed_targets: List[ # Remaining input is not empty and we failed to match it return None + class BuildTarget: def __init__(self, name, builder_class, **kwargs): From 7ab15e028de916054dfabe0ed32d19b79d37b1dd Mon Sep 17 00:00:00 2001 From: "Restyled.io" Date: Thu, 23 Mar 2023 22:57:30 +0000 Subject: [PATCH 3/6] Restyled by isort --- scripts/build/build_examples.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/build/build_examples.py b/scripts/build/build_examples.py index 4e40c84adce176..5f67db1bdd4df7 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 @@ -24,7 +25,6 @@ from runner import PrintOnlyRunner, ShellRunner import build -import json sys.path.append(os.path.abspath(os.path.dirname(__file__))) From ccf235c96a162c9d865883c1e6d028dc4de9ae9b Mon Sep 17 00:00:00 2001 From: Ken Leone Date: Thu, 23 Mar 2023 20:46:17 -0700 Subject: [PATCH 4/6] 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. --- scripts/build/build/target.py | 35 ++++++++++++++++++--------------- scripts/build/build_examples.py | 7 +------ 2 files changed, 20 insertions(+), 22 deletions(-) diff --git a/scripts/build/build/target.py b/scripts/build/build/target.py index 9ed2bc2b74cdb6..84e490602ae5c4 100644 --- a/scripts/build/build/target.py +++ b/scripts/build/build/target.py @@ -101,9 +101,12 @@ def ToDict(self): result: Dict[str, str] = {} result['name'] = self.name - bld_args_keys = list(self.build_arguments.keys()) - for key in bld_args_keys: - result[key] = str(self.build_arguments[key]) + + 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) @@ -288,17 +291,21 @@ def ToDict(self): like: - "foo": { - "builder": "", + { + "name": "foo" "shorthand": "foo-bar-baz[-m1] - "fixed_targets": [ + "parts": [ { "name": "foo", - "board": "bar" + "build_arguments": { + "board": "bar" + } } { "name": "baz", - "app": "foo.baz" + "build_arguments": { + "app": "foo.baz" + } } ], "modifiers": [ @@ -307,22 +314,18 @@ def ToDict(self): "m1": "True" } ] - }, + } """ result: Dict[str, Any] = {} result['name'] = self.name - result['builder'] = str(self.builder_class) result['shorthand'] = self.HumanString() - result['parts'] = [] - result['modifiers'] = [] + result['parts']: List[str] = [] for target in self.fixed_targets: - for target_part in target: - result['parts'].append(target_part.ToDict()) + result['parts'] = [part.ToDict() for part in target] - for target_part in self.modifiers: - result['modifiers'].append(target_part.ToDict()) + result['modifiers']: List[str] = [part.ToDict() for part in self.modifiers] return result diff --git a/scripts/build/build_examples.py b/scripts/build/build_examples.py index 5f67db1bdd4df7..a52c9aa6f3e131 100755 --- a/scripts/build/build_examples.py +++ b/scripts/build/build_examples.py @@ -198,12 +198,7 @@ def cmd_targets(context, format): for s in target.AllVariants(): print(s) elif format == 'json': - targets = [] - - for target in build.targets.BUILD_TARGETS: - targets.append(target.ToDict()) - - print(json.dumps(targets, indent=4)) + 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()) From 5a8ce8c79a16bbdc95f47a8ff4e6b2791fe25036 Mon Sep 17 00:00:00 2001 From: Ken Leone Date: Fri, 24 Mar 2023 12:29:19 -0700 Subject: [PATCH 5/6] Fixed BuildTarget ToDict method BuildTarget ToDict method was incorrectly converting the fixed_targets list to a dictionary, losing data. --- scripts/build/build/target.py | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/scripts/build/build/target.py b/scripts/build/build/target.py index 84e490602ae5c4..ac67ed38c4c555 100644 --- a/scripts/build/build/target.py +++ b/scripts/build/build/target.py @@ -293,7 +293,7 @@ def ToDict(self): { "name": "foo" - "shorthand": "foo-bar-baz[-m1] + "shorthand": "foo-bar-baz[-m1]" "parts": [ { "name": "foo", @@ -316,18 +316,12 @@ def ToDict(self): ] } """ - result: Dict[str, Any] = {} - - result['name'] = self.name - result['shorthand'] = self.HumanString() - - result['parts']: List[str] = [] - for target in self.fixed_targets: - result['parts'] = [part.ToDict() for part in target] - - result['modifiers']: List[str] = [part.ToDict() for part in self.modifiers] - - return result + return { + 'name': self.name, + 'shorthand': self.HumanString(), + 'parts': [part.ToDict() for target in self.fixed_targets for part in target], + 'modifiers': [part.ToDict() for part in self.modifiers] + } def AllVariants(self) -> Iterable[str]: """Returns all possible accepted variants by this target. From 3f775cf55b79cc4faa3bfaf7eda04c55420ed8b7 Mon Sep 17 00:00:00 2001 From: Ken Leone Date: Fri, 24 Mar 2023 14:41:27 -0700 Subject: [PATCH 6/6] 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. --- scripts/build/build/target.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/build/build/target.py b/scripts/build/build/target.py index ac67ed38c4c555..8411ff9432c2c7 100644 --- a/scripts/build/build/target.py +++ b/scripts/build/build/target.py @@ -319,7 +319,7 @@ def ToDict(self): return { 'name': self.name, 'shorthand': self.HumanString(), - 'parts': [part.ToDict() for target in self.fixed_targets for part in target], + 'parts': [[part.ToDict() for part in target] for target in self.fixed_targets], 'modifiers': [part.ToDict() for part in self.modifiers] }