| 
									
										
										
										
											2019-11-28 17:08:25 +08:00
										 |  |  | #!/usr/bin/env python | 
					
						
							| 
									
										
										
										
											2022-06-15 16:46:55 +02:00
										 |  |  | # SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD | 
					
						
							|  |  |  | # SPDX-License-Identifier: Apache-2.0 | 
					
						
							| 
									
										
										
										
											2019-11-28 17:08:25 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | # internal use only for CI | 
					
						
							|  |  |  | # download archive of one commit instead of cloning entire submodule repo | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import argparse | 
					
						
							| 
									
										
										
										
											2021-01-26 10:49:01 +08:00
										 |  |  | import os | 
					
						
							|  |  |  | import re | 
					
						
							| 
									
										
										
										
											2019-11-28 17:08:25 +08:00
										 |  |  | import shutil | 
					
						
							| 
									
										
										
										
											2021-01-26 10:49:01 +08:00
										 |  |  | import subprocess | 
					
						
							| 
									
										
										
										
											2019-11-28 17:08:25 +08:00
										 |  |  | import time | 
					
						
							| 
									
										
										
										
											2022-06-28 19:00:12 +02:00
										 |  |  | from typing import Any, List | 
					
						
							| 
									
										
										
										
											2019-11-28 17:08:25 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | import gitlab_api | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | SUBMODULE_PATTERN = re.compile(r"\[submodule \"([^\"]+)\"]") | 
					
						
							| 
									
										
										
										
											2021-01-26 10:49:01 +08:00
										 |  |  | PATH_PATTERN = re.compile(r'path\s+=\s+(\S+)') | 
					
						
							|  |  |  | URL_PATTERN = re.compile(r'url\s+=\s+(\S+)') | 
					
						
							| 
									
										
										
										
											2019-11-28 17:08:25 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-26 10:49:01 +08:00
										 |  |  | SUBMODULE_ARCHIVE_TEMP_FOLDER = 'submodule_archive' | 
					
						
							| 
									
										
										
										
											2022-07-12 16:48:54 +08:00
										 |  |  | # need to match the one defined in CI yaml files for caching purpose | 
					
						
							|  |  |  | SUBMODULE_ARCHIVE_CACHE_DIR = '.cache/submodule_archives' | 
					
						
							| 
									
										
										
										
											2019-11-28 17:08:25 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class SubModule(object): | 
					
						
							|  |  |  |     # We don't need to support recursive submodule clone now | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-26 10:49:01 +08:00
										 |  |  |     GIT_LS_TREE_OUTPUT_PATTERN = re.compile(r'\d+\s+commit\s+([0-9a-f]+)\s+') | 
					
						
							| 
									
										
										
										
											2019-11-28 17:08:25 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-06-28 19:00:12 +02:00
										 |  |  |     def __init__(self, gitlab_inst: gitlab_api.Gitlab, path: str, url: str) -> None: | 
					
						
							| 
									
										
										
										
											2019-11-28 17:08:25 +08:00
										 |  |  |         self.path = path | 
					
						
							| 
									
										
										
										
											2022-07-12 16:48:54 +08:00
										 |  |  |         self.url = url | 
					
						
							| 
									
										
										
										
											2019-11-28 17:08:25 +08:00
										 |  |  |         self.gitlab_inst = gitlab_inst | 
					
						
							|  |  |  |         self.project_id = self._get_project_id(url) | 
					
						
							|  |  |  |         self.commit_id = self._get_commit_id(path) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-06-28 19:00:12 +02:00
										 |  |  |     def _get_commit_id(self, path: str) -> str: | 
					
						
							|  |  |  |         output = subprocess.check_output(['git', 'ls-tree', 'HEAD', path]).decode() | 
					
						
							| 
									
										
										
										
											2019-11-28 17:08:25 +08:00
										 |  |  |         # example output: 160000 commit d88a262fbdf35e5abb372280eb08008749c3faa0	components/esp_wifi/lib | 
					
						
							|  |  |  |         match = self.GIT_LS_TREE_OUTPUT_PATTERN.search(output) | 
					
						
							| 
									
										
										
										
											2022-06-28 19:00:12 +02:00
										 |  |  |         return match.group(1) if match is not None else '' | 
					
						
							| 
									
										
										
										
											2019-11-28 17:08:25 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-06-28 19:00:12 +02:00
										 |  |  |     def _get_project_id(self, url: str) -> Any: | 
					
						
							| 
									
										
										
										
											2019-11-28 17:08:25 +08:00
										 |  |  |         base_name = os.path.basename(url) | 
					
						
							|  |  |  |         project_id = self.gitlab_inst.get_project_id(os.path.splitext(base_name)[0],  # remove .git | 
					
						
							| 
									
										
										
										
											2021-01-26 10:49:01 +08:00
										 |  |  |                                                      namespace='espressif') | 
					
						
							| 
									
										
										
										
											2019-11-28 17:08:25 +08:00
										 |  |  |         return project_id | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-06-28 19:00:12 +02:00
										 |  |  |     def download_archive(self) -> None: | 
					
						
							| 
									
										
										
										
											2021-01-26 10:49:01 +08:00
										 |  |  |         print('Update submodule: {}: {}'.format(self.path, self.commit_id)) | 
					
						
							| 
									
										
										
										
											2019-11-28 17:08:25 +08:00
										 |  |  |         path_name = self.gitlab_inst.download_archive(self.commit_id, SUBMODULE_ARCHIVE_TEMP_FOLDER, | 
					
						
							| 
									
										
										
										
											2022-07-12 16:48:54 +08:00
										 |  |  |                                                       self.project_id, SUBMODULE_ARCHIVE_CACHE_DIR) | 
					
						
							| 
									
										
										
										
											2019-11-28 17:08:25 +08:00
										 |  |  |         renamed_path = os.path.join(os.path.dirname(path_name), os.path.basename(self.path)) | 
					
						
							|  |  |  |         os.rename(path_name, renamed_path) | 
					
						
							|  |  |  |         shutil.rmtree(self.path, ignore_errors=True) | 
					
						
							|  |  |  |         shutil.move(renamed_path, os.path.dirname(self.path)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-06-28 19:00:12 +02:00
										 |  |  | def update_submodule(git_module_file: str, submodules_to_update: List) -> None: | 
					
						
							| 
									
										
										
										
											2019-11-28 17:08:25 +08:00
										 |  |  |     gitlab_inst = gitlab_api.Gitlab() | 
					
						
							|  |  |  |     submodules = [] | 
					
						
							| 
									
										
										
										
											2021-01-26 10:49:01 +08:00
										 |  |  |     with open(git_module_file, 'r') as f: | 
					
						
							| 
									
										
										
										
											2019-11-28 17:08:25 +08:00
										 |  |  |         data = f.read() | 
					
						
							|  |  |  |     match = SUBMODULE_PATTERN.search(data) | 
					
						
							| 
									
										
										
										
											2022-06-28 19:00:12 +02:00
										 |  |  |     if match is not None: | 
					
						
							|  |  |  |         while True: | 
					
						
							|  |  |  |             next_match = SUBMODULE_PATTERN.search(data, pos=match.end()) | 
					
						
							|  |  |  |             if next_match: | 
					
						
							|  |  |  |                 end_pos = next_match.start() | 
					
						
							|  |  |  |             else: | 
					
						
							|  |  |  |                 end_pos = len(data) | 
					
						
							|  |  |  |             path_match = PATH_PATTERN.search(data, pos=match.end(), endpos=end_pos) | 
					
						
							|  |  |  |             url_match = URL_PATTERN.search(data, pos=match.end(), endpos=end_pos) | 
					
						
							|  |  |  |             path = path_match.group(1) if path_match is not None else '' | 
					
						
							|  |  |  |             url = url_match.group(1) if url_match is not None else '' | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             filter_result = True | 
					
						
							|  |  |  |             if submodules_to_update: | 
					
						
							|  |  |  |                 if path not in submodules_to_update: | 
					
						
							|  |  |  |                     filter_result = False | 
					
						
							|  |  |  |             if filter_result: | 
					
						
							|  |  |  |                 submodules.append(SubModule(gitlab_inst, path, url)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             match = next_match | 
					
						
							|  |  |  |             if not match: | 
					
						
							|  |  |  |                 break | 
					
						
							| 
									
										
										
										
											2019-11-28 17:08:25 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     shutil.rmtree(SUBMODULE_ARCHIVE_TEMP_FOLDER, ignore_errors=True) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     for submodule in submodules: | 
					
						
							|  |  |  |         submodule.download_archive() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | if __name__ == '__main__': | 
					
						
							|  |  |  |     start_time = time.time() | 
					
						
							|  |  |  |     parser = argparse.ArgumentParser() | 
					
						
							| 
									
										
										
										
											2021-01-26 10:49:01 +08:00
										 |  |  |     parser.add_argument('--repo_path', '-p', default='.', help='repo path') | 
					
						
							|  |  |  |     parser.add_argument('--submodule', '-s', default='all', | 
					
						
							|  |  |  |                         help='Submodules to update. By default update all submodules. ' | 
					
						
							|  |  |  |                              'For multiple submodules, separate them with `;`. ' | 
					
						
							|  |  |  |                              '`all` and `none` are special values that indicates we fetch all / none submodules') | 
					
						
							| 
									
										
										
										
											2019-11-28 17:08:25 +08:00
										 |  |  |     args = parser.parse_args() | 
					
						
							| 
									
										
										
										
											2021-01-26 10:49:01 +08:00
										 |  |  |     if args.submodule == 'none': | 
					
						
							| 
									
										
										
										
											2019-11-28 17:08:25 +08:00
										 |  |  |         print("don't need to update submodules") | 
					
						
							|  |  |  |         exit(0) | 
					
						
							| 
									
										
										
										
											2021-01-26 10:49:01 +08:00
										 |  |  |     if args.submodule == 'all': | 
					
						
							| 
									
										
										
										
											2019-11-28 17:08:25 +08:00
										 |  |  |         _submodules = [] | 
					
						
							|  |  |  |     else: | 
					
						
							| 
									
										
										
										
											2021-01-26 10:49:01 +08:00
										 |  |  |         _submodules = args.submodule.split(';') | 
					
						
							|  |  |  |     update_submodule(os.path.join(args.repo_path, '.gitmodules'), _submodules) | 
					
						
							|  |  |  |     print('total time spent on update submodule: {:.02f}s'.format(time.time() - start_time)) |