icore_module.py 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183
  1. # Copyright 2023 Google LLC
  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 os
  15. import logging
  16. import json
  17. import subprocess
  18. SWIFT = 'Swift'
  19. OBJECTIVE_C = 'Objective-C'
  20. # List of Swift and Objective-C modules
  21. MODULE_LIST = [
  22. 'FirebaseABTesting',
  23. 'FirebaseAnalytics', # Not buildable from source
  24. 'FirebaseAnalyticsOnDeviceConversion', # Not buildable.
  25. 'FirebaseAnalyticsSwift',
  26. 'FirebaseAppCheck',
  27. 'FirebaseAppDistribution',
  28. 'FirebaseAuth',
  29. 'FirebaseCore',
  30. 'FirebaseCrashlytics',
  31. 'FirebaseDatabase',
  32. 'FirebaseDatabaseSwift',
  33. 'FirebaseDynamicLinks',
  34. 'FirebaseFirestore',
  35. 'FirebaseFirestoreSwift',
  36. 'FirebaseFunctions',
  37. 'FirebaseInAppMessaging'
  38. 'FirebaseInAppMessagingSwift',
  39. 'FirebaseInstallations',
  40. 'FirebaseMessaging',
  41. 'FirebaseMLModelDownloader',
  42. 'FirebasePerformance',
  43. 'FirebaseRemoteConfig',
  44. 'FirebaseRemoteConfigSwift',
  45. # Not buildable. No scheme named "FirebaseSharedSwift"
  46. 'FirebaseSharedSwift',
  47. 'FirebaseStorage',
  48. # Not buildable. NO "source_files"
  49. 'GoogleAppMeasurement',
  50. # Not buildable. NO "source_files"
  51. 'GoogleAppMeasurementOnDeviceConversion'
  52. ]
  53. def main():
  54. module_info()
  55. def detect_changed_modules(changed_api_files):
  56. """Detect changed modules based on changed API files."""
  57. all_modules = module_info()
  58. changed_modules = {}
  59. for file_path in changed_api_files:
  60. for k, v in all_modules.items():
  61. if v['root_dir'] and v['root_dir'] in file_path:
  62. changed_modules[k] = v
  63. break
  64. logging.info(f'changed_modules:\n{json.dumps(changed_modules, indent=4)}')
  65. return changed_modules
  66. def module_info():
  67. """retrieve module info in MODULE_LIST from `.podspecs`
  68. The module info helps to build Jazzy
  69. includes: module name, source_files, public_header_files,
  70. language, umbrella_header, framework_root
  71. """
  72. module_from_podspecs = module_info_from_podspecs()
  73. module_list = {}
  74. for k, v in module_from_podspecs.items():
  75. if k in MODULE_LIST:
  76. if k not in module_list:
  77. module_list[k] = v
  78. module_list[k]['language'] = OBJECTIVE_C if v.get(
  79. 'public_header_files') else SWIFT
  80. module_list[k]['scheme'] = get_scheme(k)
  81. module_list[k]['umbrella_header'] = get_umbrella_header(
  82. k, v.get('public_header_files'))
  83. module_list[k]['root_dir'] = get_root_dir(k, v.get('source_files'))
  84. logging.info(f'all_module:\n{json.dumps(module_list, indent=4)}')
  85. return module_list
  86. def get_scheme(module_name):
  87. """Jazzy documentation Info SWIFT only.
  88. Get scheme from module name in .podspecs Assume the scheme is the
  89. same as the module name:
  90. """
  91. MODULE_SCHEME_PATCH = {
  92. 'FirebaseInAppMessagingSwift': 'FirebaseInAppMessagingSwift-Beta',
  93. }
  94. if module_name in MODULE_SCHEME_PATCH:
  95. return MODULE_SCHEME_PATCH[module_name]
  96. return module_name
  97. def get_umbrella_header(module_name, public_header_files):
  98. """Jazzy documentation Info OBJC only Get umbrella_header from
  99. public_header_files in .podspecs Assume the umbrella_header is with the
  100. format:
  101. {module_name}/Sources/Public/{module_name}/{module_name}.h
  102. """
  103. if public_header_files:
  104. if isinstance(public_header_files, list):
  105. return public_header_files[0].replace('*', module_name)
  106. elif isinstance(public_header_files, str):
  107. return public_header_files.replace('*', module_name)
  108. return ''
  109. def get_root_dir(module_name, source_files):
  110. """Get source code root_dir from source_files in .podspecs Assume the
  111. root_dir is with the format:
  112. {module_name}/Sources or {module_name}/Source
  113. """
  114. MODULE_ROOT_PATCH = {
  115. 'FirebaseFirestore': 'Firestore/Source',
  116. 'FirebaseFirestoreSwift': 'Firestore/Swift/Source',
  117. 'FirebaseCrashlytics': 'Crashlytics/Crashlytics',
  118. 'FirebaseInAppMessagingSwift': 'FirebaseInAppMessaging/Swift/Source',
  119. }
  120. if module_name in MODULE_ROOT_PATCH:
  121. return MODULE_ROOT_PATCH[module_name]
  122. if source_files:
  123. for source_file in source_files:
  124. if f'{module_name}/Sources' in source_file:
  125. return f'{module_name}/Sources'
  126. if f'{module_name}/Source' in source_file:
  127. return f'{module_name}/Source'
  128. return ''
  129. def module_info_from_podspecs(root_dir=os.getcwd()):
  130. result = {}
  131. for filename in os.listdir(root_dir):
  132. if filename.endswith('.podspec'):
  133. podspec_data = parse_podspec(filename)
  134. source_files = podspec_data.get('source_files')
  135. if not podspec_data.get('source_files') and podspec_data.get('ios'):
  136. source_files = podspec_data.get('ios').get('source_files')
  137. result[podspec_data['name']] = {
  138. 'name': podspec_data['name'],
  139. 'source_files': source_files,
  140. 'public_header_files': podspec_data.get('public_header_files')
  141. }
  142. return result
  143. def parse_podspec(podspec_file):
  144. result = subprocess.run(f'pod ipc spec {podspec_file}',
  145. stdout=subprocess.PIPE,
  146. stderr=subprocess.PIPE,
  147. text=True,
  148. shell=True)
  149. if result.returncode != 0:
  150. logging.info(f'Error: {result.stderr}')
  151. return None
  152. # Parse the JSON output
  153. podspec_data = json.loads(result.stdout)
  154. return podspec_data
  155. if __name__ == '__main__':
  156. main()