mirror of https://github.com/ARMmbed/mbed-os.git
137 lines
5.4 KiB
Python
137 lines
5.4 KiB
Python
#
|
|
# Copyright (c) 2020-2021 Arm Limited and Contributors. All rights reserved.
|
|
# SPDX-License-Identifier: Apache-2.0
|
|
#
|
|
"""Internal helper to retrieve target attribute information.
|
|
|
|
This information is parsed from the targets.json configuration file
|
|
found in the mbed-os repo.
|
|
"""
|
|
import logging
|
|
import pathlib
|
|
from typing import Dict, Any, Set, Optional
|
|
|
|
from mbed_tools.lib.exceptions import ToolsError
|
|
from mbed_tools.lib.json_helpers import decode_json_file
|
|
|
|
from mbed_tools.targets._internal.targets_json_parsers.accumulating_attribute_parser import (
|
|
get_accumulating_attributes_for_target,
|
|
)
|
|
from mbed_tools.targets._internal.targets_json_parsers.overriding_attribute_parser import (
|
|
get_overriding_attributes_for_target,
|
|
get_labels_for_target,
|
|
)
|
|
|
|
INTERNAL_PACKAGE_DIR = pathlib.Path(__file__).parent
|
|
MBED_OS_METADATA_FILE = pathlib.Path(INTERNAL_PACKAGE_DIR, "data", "targets_metadata.json")
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
class TargetAttributesError(ToolsError):
|
|
"""Target attributes error."""
|
|
|
|
|
|
class ParsingTargetsJSONError(TargetAttributesError):
|
|
"""targets.json parsing failed."""
|
|
|
|
|
|
class TargetNotFoundError(TargetAttributesError):
|
|
"""Target definition not found in targets.json."""
|
|
|
|
|
|
def get_target_attributes(targets_json_data: dict, target_name: str, allow_non_public_targets: bool = False) -> dict:
|
|
"""Retrieves attribute data taken from targets.json for a single target.
|
|
|
|
Args:
|
|
targets_json_data: target definitions from targets.json
|
|
target_name: the name of the target (often a Board's board_type).
|
|
allow_non_public_targets: If set to True, attributes can be gotten even for non-public targets
|
|
|
|
Returns:
|
|
A dictionary representation of the attributes for the target.
|
|
|
|
Raises:
|
|
ParsingTargetJSONError: error parsing targets.json
|
|
TargetNotFoundError: there is no target attribute data found for that target.
|
|
"""
|
|
target_attributes = _extract_target_attributes(targets_json_data, target_name, allow_non_public_targets)
|
|
target_attributes["labels"] = get_labels_for_target(targets_json_data, target_name).union(
|
|
_extract_core_labels(target_attributes.get("core", None))
|
|
)
|
|
target_attributes["extra_labels"] = set(target_attributes.get("extra_labels", []))
|
|
target_attributes["features"] = set(target_attributes.get("features", []))
|
|
target_attributes["components"] = set(target_attributes.get("components", []))
|
|
target_attributes["macros"] = set(target_attributes.get("macros", []))
|
|
target_attributes["config"] = _apply_config_overrides(
|
|
target_attributes.get("config", {}), target_attributes.get("overrides", {})
|
|
)
|
|
return target_attributes
|
|
|
|
|
|
def _extract_target_attributes(all_targets_data: Dict[str, Any], target_name: str, allow_non_public_targets: bool) -> dict:
|
|
"""Extracts the definition for a particular target from all the targets in targets.json.
|
|
|
|
Args:
|
|
all_targets_data: a dictionary representation of the raw targets.json data.
|
|
target_name: the name of the target.
|
|
allow_non_public_targets: If set to True, attributes can be gotten even for non-public targets
|
|
|
|
Returns:
|
|
A dictionary representation the target definition.
|
|
|
|
Raises:
|
|
TargetNotFoundError: no target definition found in targets.json.
|
|
"""
|
|
if target_name not in all_targets_data:
|
|
raise TargetNotFoundError(f"Target attributes for {target_name} not found.")
|
|
|
|
# All target definitions are assumed to be public unless specifically set as public=false
|
|
if not all_targets_data[target_name].get("public", True) and not allow_non_public_targets:
|
|
raise TargetNotFoundError(f"Cannot get attributes for {target_name} because it is marked non-public in targets JSON. This likely means you set MBED_TARGET to the name of the MCU rather than the name of the board.")
|
|
|
|
target_attributes = get_overriding_attributes_for_target(all_targets_data, target_name)
|
|
accumulated_attributes = get_accumulating_attributes_for_target(all_targets_data, target_name)
|
|
target_attributes.update(accumulated_attributes)
|
|
return target_attributes
|
|
|
|
|
|
def _extract_core_labels(target_core: Optional[str]) -> Set[str]:
|
|
"""Find the labels associated with the target's core.
|
|
|
|
Args:
|
|
target_core: the target core, set as a build attribute
|
|
|
|
Returns:
|
|
A list of labels associated with the target's core, or an empty set
|
|
if either core is undefined or no labels found for the core.
|
|
"""
|
|
if target_core:
|
|
mbed_os_metadata = decode_json_file(MBED_OS_METADATA_FILE)
|
|
return set(mbed_os_metadata["CORE_LABELS"].get(target_core, []))
|
|
return set()
|
|
|
|
|
|
def _apply_config_overrides(config: Dict[str, Any], overrides: Dict[str, Any]) -> Dict[str, Any]:
|
|
"""Returns the config attribute with any overrides applied.
|
|
|
|
Args:
|
|
config: the cumulative config settings defined for a target
|
|
overrides: the values that need to be changed in the config settings for this target
|
|
|
|
Returns:
|
|
The config settings with the overrides applied.
|
|
|
|
Raises:
|
|
TargetsJsonConfigurationError: overrides can't be applied to config settings that aren't already defined
|
|
"""
|
|
config = config.copy()
|
|
for key in overrides:
|
|
try:
|
|
config[key]["value"] = overrides[key]
|
|
except KeyError:
|
|
logger.warning(
|
|
f"Cannot apply override {key}={overrides[key]}, there is no config setting defined matching that name."
|
|
)
|
|
return config
|