checkout_submodules.py 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. #!/usr/bin/env python3
  2. #
  3. # Copyright (c) 2022 Project CHIP Authors
  4. #
  5. # Licensed under the Apache License, Version 2.0 (the "License");
  6. # you may not use this file except in compliance with the License.
  7. # You may obtain a copy of the License at
  8. #
  9. # http://www.apache.org/licenses/LICENSE-2.0
  10. #
  11. # Unless required by applicable law or agreed to in writing, software
  12. # distributed under the License is distributed on an "AS IS" BASIS,
  13. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. # See the License for the specific language governing permissions and
  15. # limitations under the License.
  16. #
  17. import argparse
  18. from collections import namedtuple
  19. import configparser
  20. import logging
  21. import subprocess
  22. import os
  23. CHIP_ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))
  24. ALL_PLATFORMS = set([
  25. 'ameba',
  26. 'android',
  27. 'bl602',
  28. 'cc13x2_26x2',
  29. 'cc32xx',
  30. 'cyw30739',
  31. 'darwin',
  32. 'efr32',
  33. 'esp32',
  34. 'k32w0',
  35. 'linux',
  36. 'mbed',
  37. 'nrfconnect',
  38. 'p6',
  39. 'qpg',
  40. 'telink',
  41. 'tizen',
  42. 'webos',
  43. 'mw320',
  44. ])
  45. Module = namedtuple('Module', 'name path platforms')
  46. def load_module_info() -> None:
  47. config = configparser.ConfigParser()
  48. config.read(os.path.join(CHIP_ROOT, '.gitmodules'))
  49. for name, module in config.items():
  50. if name != 'DEFAULT':
  51. platforms = module.get('platforms', '').split(',')
  52. platforms = set(filter(None, platforms))
  53. assert not (platforms - ALL_PLATFORMS), "Submodule's platform not contained in ALL_PLATFORMS"
  54. yield Module(name=name, path=module['path'], platforms=platforms)
  55. def module_matches_platforms(module: Module, platforms: set) -> bool:
  56. # If no platforms have been selected, or the module is not associated with any specific
  57. # platforms, treat it as a match.
  58. if not platforms or not module.platforms:
  59. return True
  60. return bool(platforms & module.platforms)
  61. def make_chip_root_safe_directory() -> None:
  62. # ensure no errors regarding ownership in the directory. Newer GIT seems to require this:
  63. subprocess.check_call(['git', 'config', '--global', '--add', 'safe.directory', CHIP_ROOT])
  64. def checkout_modules(modules: list, shallow: bool, force: bool) -> None:
  65. names = [module.name.replace('submodule "', '').replace('"', '') for module in modules]
  66. names = ', '.join(names)
  67. logging.info(f'Checking out: {names}')
  68. cmd = ['git', '-C', CHIP_ROOT, 'submodule', 'update', '--init']
  69. cmd += ['--depth', '1'] if shallow else []
  70. cmd += ['--force'] if force else []
  71. cmd += [module.path for module in modules]
  72. subprocess.check_call(cmd)
  73. def deinit_modules(modules: list, force: bool) -> None:
  74. names = [module.name.replace('submodule "', '').replace('"', '') for module in modules]
  75. names = ', '.join(names)
  76. logging.info(f'Deinitializing: {names}')
  77. cmd = ['git', '-C', CHIP_ROOT, 'submodule', 'deinit']
  78. cmd += ['--force'] if force else []
  79. cmd += [module.path for module in modules]
  80. subprocess.check_call(cmd)
  81. def main():
  82. logging.basicConfig(format='%(message)s', level=logging.INFO)
  83. parser = argparse.ArgumentParser(description='Checkout or update relevant git submodules')
  84. parser.add_argument('--shallow', action='store_true', help='Fetch submodules without history')
  85. parser.add_argument('--platform', nargs='+', choices=ALL_PLATFORMS, default=[],
  86. help='Process submodules for specific platforms only')
  87. parser.add_argument('--force', action='store_true', help='Perform action despite of warnings')
  88. parser.add_argument('--deinit-unmatched', action='store_true',
  89. help='Deinitialize submodules for non-matching platforms')
  90. args = parser.parse_args()
  91. modules = list(load_module_info())
  92. selected_platforms = set(args.platform)
  93. selected_modules = [m for m in modules if module_matches_platforms(m, selected_platforms)]
  94. unmatched_modules = [m for m in modules if not module_matches_platforms(m, selected_platforms)]
  95. make_chip_root_safe_directory()
  96. checkout_modules(selected_modules, args.shallow, args.force)
  97. if args.deinit_unmatched:
  98. deinit_modules(unmatched_modules, args.force)
  99. if __name__ == '__main__':
  100. main()