blob: a6f759bab67cf8f05e5eb5b5e7cc65eb67693b8b [file] [log] [blame]
# Copyright (c) 2022 Project CHIP Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import fnmatch
import logging
import os
from dataclasses import dataclass, field
from typing import Iterator, List, Optional
from .types import IdlFileType, InputIdlFile
from .using_codegen import (CodegenCppAppPregenerator, CodegenCppClustersTLVMetaPregenerator,
CodegenCppProtocolsTLVMetaPregenerator, CodegenJavaClassPregenerator, CodegenJavaJNIPregenerator)
from .using_zap import ZapApplicationPregenerator
def _IdlsInDirectory(top_directory_name: str, truncate_length: int):
for root, dirs, files in os.walk(top_directory_name):
for file in files:
if file.endswith('.zap'):
yield InputIdlFile(file_type=IdlFileType.ZAP,
full_path=os.path.join(root, file),
relative_path=os.path.join(root[truncate_length:], file))
if file.endswith('.matter'):
yield InputIdlFile(file_type=IdlFileType.MATTER,
full_path=os.path.join(root, file),
relative_path=os.path.join(root[truncate_length:], file))
def _FindAllIdls(sdk_root: str, external_roots: Optional[List[str]]) -> Iterator[InputIdlFile]:
relevant_subdirs = [
'examples', # all example apps
'src', # realistically only controller/data_model
]
while sdk_root.endswith('/'):
sdk_root = sdk_root[:-1]
sdk_root_length = len(sdk_root)
# first go over SDK items
for subdir_name in relevant_subdirs:
top_directory_name = os.path.join(sdk_root, subdir_name)
logging.debug(f"Searching {top_directory_name}")
for idl in _IdlsInDirectory(top_directory_name, sdk_root_length+1):
yield idl
# next external roots
if external_roots:
for root in external_roots:
root = os.path.normpath(root)
for idl in _IdlsInDirectory(root, len(root) + 1):
yield idl
@dataclass
class TargetFilter:
# If set, only the specified files are accepted for codegen
file_type: Optional[IdlFileType] = None
# If non-empty only the given paths will be code-generated
path_glob: List[str] = field(default_factory=list)
# TODO: the build GlobMatcher is more complete by supporting `{}` grouping
# For now this limited glob seems sufficient.
class GlobMatcher:
def __init__(self, pattern: str):
self.pattern = pattern
def matches(self, s: str):
return fnmatch.fnmatch(s, self.pattern)
def FindPregenerationTargets(sdk_root: str, external_roots: Optional[List[str]], filter: TargetFilter, runner):
"""Finds all relevand pre-generation targets in the given
SDK root.
Pre-generation targets are based on zap and matter files with options
on what rules to pregenerate and how.
"""
generators = [
# Jinja-based codegen
CodegenJavaJNIPregenerator(sdk_root),
CodegenJavaClassPregenerator(sdk_root),
CodegenCppAppPregenerator(sdk_root),
CodegenCppClustersTLVMetaPregenerator(sdk_root),
CodegenCppProtocolsTLVMetaPregenerator(sdk_root),
# ZAP codegen
ZapApplicationPregenerator(sdk_root),
]
path_matchers = [GlobMatcher(pattern) for pattern in filter.path_glob]
for idl in _FindAllIdls(sdk_root, external_roots):
if filter.file_type is not None:
if idl.file_type != filter.file_type:
logging.debug(f"Will not process file of type {idl.file_type}: {idl.relative_path}")
continue
if path_matchers:
if all([not matcher.matches(idl.relative_path) for matcher in path_matchers]):
logging.debug(f"Glob not matched for {idl.relative_path}")
continue
for generator in generators:
if generator.Accept(idl):
yield generator.CreateTarget(idl, runner=runner)