Files
esp-idf/tools/test_apps/system/g1_components/check_dependencies.py
harshal.patil 55e0730a8d change(esp_hw_support): Move security-related modules to the esp_security component
- Also adds support to whitelist target specific expected dependency violations
in check_dependencies.py
2025-08-04 11:43:01 +05:30

141 lines
5.1 KiB
Python

# SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: Unlicense OR CC0-1.0
import argparse
import logging
from typing import Dict
from typing import List
from typing import Optional
from typing import Tuple
g1_g0_components = [
'hal',
'cxx',
'newlib',
'freertos',
'esp_hw_support',
'heap',
'log',
'soc',
'esp_rom',
'esp_common',
'esp_system',
'xtensa',
'riscv',
'spi_flash',
'esp_mm',
]
# Global expected dependency violations that apply to all targets
expected_dep_violations = {
'esp_system': ['esp_timer', 'bootloader_support', 'esp_pm'],
'spi_flash': ['bootloader_support'],
'esp_hw_support': ['efuse', 'bootloader_support', 'esp_driver_gpio', 'esp_timer', 'esp_pm'],
'cxx': ['pthread'],
}
# Target-specific expected dependency violations
target_specific_expected_dep_violations = {
# 'target': {
# Add target-specific violations for target here
# 'component_name': ['dependency1', 'dependency2'],
# },
'esp32s2': {
# ESP32-S2 uses the crypto DMA lock for encrypted writes, thus, spi_flash needs to depend on esp_security
'spi_flash': ['esp_security'],
},
}
def merge_expected_violations(target: Optional[str] = None) -> Dict[str, List[str]]:
"""
Merge global and target-specific expected dependency violations.
Args:
target: The target target name (e.g., 'esp32', 'esp32s3', etc.)
Returns:
Merged dictionary of expected dependency violations
"""
# Start with a deep copy of global violations
merged_violations = {}
for component, deps in expected_dep_violations.items():
merged_violations[component] = deps.copy()
# Add target-specific violations if target is specified
if target and target in target_specific_expected_dep_violations:
target_violations = target_specific_expected_dep_violations[target]
for component, deps in target_violations.items():
if component in merged_violations:
# Extend existing list with target-specific dependencies
merged_violations[component].extend(deps)
else:
# Add new component with its dependencies
merged_violations[component] = deps.copy()
return merged_violations
def parse_dependencies(file_path: str, target: Optional[str] = None) -> Tuple[Dict[str, List[str]], List[str]]:
new_dependency_errors = []
# Get merged expected violations for the specified target
merged_expected_violations = merge_expected_violations(target)
with open(file_path, 'r') as file:
for line in file:
line = line.strip(' ;')
if line:
parts = line.split(' -> ')
if len(parts) >= 2:
source_component = parts[0]
target_component = parts[1].split()[0] # Extracting the target component
logging.debug(f'Parsed dependency: {source_component} -> {target_component}')
# Check that g1/g0 dependencies are either on the list of expected violations
# or dependencies to other g1/g0 components
if source_component in g1_g0_components and target_component not in g1_g0_components:
if (
source_component in merged_expected_violations
and target_component in merged_expected_violations[source_component]
):
logging.debug(
f'Removing dependency {target_component} from {source_component} '
f'in list of expected violations'
)
merged_expected_violations[source_component].remove(target_component)
else:
new_dependency_errors.append(f'{source_component} -> {target_component}')
# Any leftover dependencies in the merged_expected_violations are no longer true dependencies and
# can be removed from the list
false_dependencies = {k: v for k, v in merged_expected_violations.items() if len(v) > 0}
return (false_dependencies, new_dependency_errors)
if __name__ == '__main__':
parser = argparse.ArgumentParser(description='Check G1 dependencies')
parser.add_argument(
'--component_deps_file', required=True, type=str, help='The path to the component_deps.dot file'
)
parser.add_argument('--target', type=str, help='The target name (e.g., esp32, esp32s3, esp32c6, etc.)')
args = parser.parse_args()
(false_dependencies, new_dependency_errors) = parse_dependencies(args.component_deps_file, args.target)
if new_dependency_errors:
print('Found the following new dependency violations:')
print(new_dependency_errors)
exit(1)
if false_dependencies:
print('The following dependencies are list as violations, but were not found in the component_deps.dot file:')
print(false_dependencies)
print('Please remove them from the violation list')
exit(1)
print('No new dependency violations found')