__init__.py 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  1. # Copyright (c) 2022 Project CHIP Authors
  2. #
  3. # Licensed under the Apache License, Version 2.0 (the "License");
  4. # you may not use this file except in compliance with the License.
  5. # You may obtain a copy of the License at
  6. #
  7. # http://www.apache.org/licenses/LICENSE-2.0
  8. #
  9. # Unless required by applicable law or agreed to in writing, software
  10. # distributed under the License is distributed on an "AS IS" BASIS,
  11. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. # See the License for the specific language governing permissions and
  13. # limitations under the License.
  14. import fnmatch
  15. import logging
  16. import os
  17. from dataclasses import dataclass, field
  18. from typing import Iterator, List, Optional
  19. from .types import IdlFileType, InputIdlFile
  20. from .using_codegen import (CodegenCppAppPregenerator, CodegenCppClustersTLVMetaPregenerator,
  21. CodegenCppProtocolsTLVMetaPregenerator, CodegenJavaClassPregenerator, CodegenJavaJNIPregenerator)
  22. from .using_zap import ZapApplicationPregenerator
  23. def _IdlsInDirectory(top_directory_name: str, truncate_length: int):
  24. for root, dirs, files in os.walk(top_directory_name):
  25. for file in files:
  26. if file.endswith('.zap'):
  27. yield InputIdlFile(file_type=IdlFileType.ZAP,
  28. full_path=os.path.join(root, file),
  29. relative_path=os.path.join(root[truncate_length:], file))
  30. if file.endswith('.matter'):
  31. yield InputIdlFile(file_type=IdlFileType.MATTER,
  32. full_path=os.path.join(root, file),
  33. relative_path=os.path.join(root[truncate_length:], file))
  34. def _FindAllIdls(sdk_root: str, external_roots: Optional[List[str]]) -> Iterator[InputIdlFile]:
  35. relevant_subdirs = [
  36. 'examples', # all example apps
  37. 'src', # realistically only controller/data_model
  38. ]
  39. while sdk_root.endswith('/'):
  40. sdk_root = sdk_root[:-1]
  41. sdk_root_length = len(sdk_root)
  42. # first go over SDK items
  43. for subdir_name in relevant_subdirs:
  44. top_directory_name = os.path.join(sdk_root, subdir_name)
  45. logging.debug(f"Searching {top_directory_name}")
  46. for idl in _IdlsInDirectory(top_directory_name, sdk_root_length+1):
  47. yield idl
  48. # next external roots
  49. if external_roots:
  50. for root in external_roots:
  51. root = os.path.normpath(root)
  52. for idl in _IdlsInDirectory(root, len(root) + 1):
  53. yield idl
  54. @dataclass
  55. class TargetFilter:
  56. # If set, only the specified files are accepted for codegen
  57. file_type: Optional[IdlFileType] = None
  58. # If non-empty only the given paths will be code-generated
  59. path_glob: List[str] = field(default_factory=list)
  60. # TODO: the build GlobMatcher is more complete by supporting `{}` grouping
  61. # For now this limited glob seems sufficient.
  62. class GlobMatcher:
  63. def __init__(self, pattern: str):
  64. self.pattern = pattern
  65. def matches(self, s: str):
  66. return fnmatch.fnmatch(s, self.pattern)
  67. def FindPregenerationTargets(sdk_root: str, external_roots: Optional[List[str]], filter: TargetFilter, runner):
  68. """Finds all relevand pre-generation targets in the given
  69. SDK root.
  70. Pre-generation targets are based on zap and matter files with options
  71. on what rules to pregenerate and how.
  72. """
  73. generators = [
  74. # Jinja-based codegen
  75. CodegenJavaJNIPregenerator(sdk_root),
  76. CodegenJavaClassPregenerator(sdk_root),
  77. CodegenCppAppPregenerator(sdk_root),
  78. CodegenCppClustersTLVMetaPregenerator(sdk_root),
  79. CodegenCppProtocolsTLVMetaPregenerator(sdk_root),
  80. # ZAP codegen
  81. ZapApplicationPregenerator(sdk_root),
  82. ]
  83. path_matchers = [GlobMatcher(pattern) for pattern in filter.path_glob]
  84. for idl in _FindAllIdls(sdk_root, external_roots):
  85. if filter.file_type is not None:
  86. if idl.file_type != filter.file_type:
  87. logging.debug(f"Will not process file of type {idl.file_type}: {idl.relative_path}")
  88. continue
  89. if path_matchers:
  90. if all([not matcher.matches(idl.relative_path) for matcher in path_matchers]):
  91. logging.debug(f"Glob not matched for {idl.relative_path}")
  92. continue
  93. for generator in generators:
  94. if generator.Accept(idl):
  95. yield generator.CreateTarget(idl, runner=runner)