summaryrefslogtreecommitdiffstats
path: root/git_superproject.py
diff options
context:
space:
mode:
Diffstat (limited to 'git_superproject.py')
-rw-r--r--git_superproject.py118
1 files changed, 87 insertions, 31 deletions
diff --git a/git_superproject.py b/git_superproject.py
index 3c4144dd..8f1e04d6 100644
--- a/git_superproject.py
+++ b/git_superproject.py
@@ -19,12 +19,13 @@ https://en.wikibooks.org/wiki/Git/Submodules_and_Superprojects
19 19
20Examples: 20Examples:
21 superproject = Superproject() 21 superproject = Superproject()
22 project_commit_ids = superproject.UpdateProjectsRevisionId(projects) 22 UpdateProjectsResult = superproject.UpdateProjectsRevisionId(projects)
23""" 23"""
24 24
25import hashlib 25import hashlib
26import os 26import os
27import sys 27import sys
28from typing import NamedTuple
28 29
29from git_command import git_require, GitCommand 30from git_command import git_require, GitCommand
30from git_refs import R_HEADS 31from git_refs import R_HEADS
@@ -34,6 +35,33 @@ _SUPERPROJECT_GIT_NAME = 'superproject.git'
34_SUPERPROJECT_MANIFEST_NAME = 'superproject_override.xml' 35_SUPERPROJECT_MANIFEST_NAME = 'superproject_override.xml'
35 36
36 37
38class SyncResult(NamedTuple):
39 """Return the status of sync and whether caller should exit."""
40
41 # Whether the superproject sync was successful.
42 success: bool
43 # Whether the caller should exit.
44 fatal: bool
45
46
47class CommitIdsResult(NamedTuple):
48 """Return the commit ids and whether caller should exit."""
49
50 # A dictionary with the projects/commit ids on success, otherwise None.
51 commit_ids: dict
52 # Whether the caller should exit.
53 fatal: bool
54
55
56class UpdateProjectsResult(NamedTuple):
57 """Return the overriding manifest file and whether caller should exit."""
58
59 # Path name of the overriding manfiest file if successful, otherwise None.
60 manifest_path: str
61 # Whether the caller should exit.
62 fatal: bool
63
64
37class Superproject(object): 65class Superproject(object):
38 """Get commit ids from superproject. 66 """Get commit ids from superproject.
39 67
@@ -41,19 +69,21 @@ class Superproject(object):
41 lookup of commit ids for all projects. It contains _project_commit_ids which 69 lookup of commit ids for all projects. It contains _project_commit_ids which
42 is a dictionary with project/commit id entries. 70 is a dictionary with project/commit id entries.
43 """ 71 """
44 def __init__(self, manifest, repodir, superproject_dir='exp-superproject', 72 def __init__(self, manifest, repodir, git_event_log,
45 quiet=False): 73 superproject_dir='exp-superproject', quiet=False):
46 """Initializes superproject. 74 """Initializes superproject.
47 75
48 Args: 76 Args:
49 manifest: A Manifest object that is to be written to a file. 77 manifest: A Manifest object that is to be written to a file.
50 repodir: Path to the .repo/ dir for holding all internal checkout state. 78 repodir: Path to the .repo/ dir for holding all internal checkout state.
51 It must be in the top directory of the repo client checkout. 79 It must be in the top directory of the repo client checkout.
80 git_event_log: A git trace2 event log to log events.
52 superproject_dir: Relative path under |repodir| to checkout superproject. 81 superproject_dir: Relative path under |repodir| to checkout superproject.
53 quiet: If True then only print the progress messages. 82 quiet: If True then only print the progress messages.
54 """ 83 """
55 self._project_commit_ids = None 84 self._project_commit_ids = None
56 self._manifest = manifest 85 self._manifest = manifest
86 self._git_event_log = git_event_log
57 self._quiet = quiet 87 self._quiet = quiet
58 self._branch = self._GetBranch() 88 self._branch = self._GetBranch()
59 self._repodir = os.path.abspath(repodir) 89 self._repodir = os.path.abspath(repodir)
@@ -172,44 +202,48 @@ class Superproject(object):
172 """Gets a local copy of a superproject for the manifest. 202 """Gets a local copy of a superproject for the manifest.
173 203
174 Returns: 204 Returns:
175 True if sync of superproject is successful, or False. 205 SyncResult
176 """ 206 """
177 print('NOTICE: --use-superproject is in beta; report any issues to the ' 207 print('NOTICE: --use-superproject is in beta; report any issues to the '
178 'address described in `repo version`', file=sys.stderr) 208 'address described in `repo version`', file=sys.stderr)
179 209
180 if not self._manifest.superproject: 210 if not self._manifest.superproject:
181 print('error: superproject tag is not defined in manifest', 211 msg = (f'repo error: superproject tag is not defined in manifest: '
182 file=sys.stderr) 212 f'{self._manifest.manifestFile}')
183 return False 213 print(msg, file=sys.stderr)
214 self._git_event_log.ErrorEvent(msg, '')
215 return SyncResult(False, False)
184 216
217 should_exit = True
185 url = self._manifest.superproject['remote'].url 218 url = self._manifest.superproject['remote'].url
186 if not url: 219 if not url:
187 print('error: superproject URL is not defined in manifest', 220 print('error: superproject URL is not defined in manifest',
188 file=sys.stderr) 221 file=sys.stderr)
189 return False 222 return SyncResult(False, should_exit)
190 223
191 if not self._Init(): 224 if not self._Init():
192 return False 225 return SyncResult(False, should_exit)
193 if not self._Fetch(url): 226 if not self._Fetch(url):
194 return False 227 return SyncResult(False, should_exit)
195 if not self._quiet: 228 if not self._quiet:
196 print('%s: Initial setup for superproject completed.' % self._work_git) 229 print('%s: Initial setup for superproject completed.' % self._work_git)
197 return True 230 return SyncResult(True, False)
198 231
199 def _GetAllProjectsCommitIds(self): 232 def _GetAllProjectsCommitIds(self):
200 """Get commit ids for all projects from superproject and save them in _project_commit_ids. 233 """Get commit ids for all projects from superproject and save them in _project_commit_ids.
201 234
202 Returns: 235 Returns:
203 A dictionary with the projects/commit ids on success, otherwise None. 236 CommitIdsResult
204 """ 237 """
205 if not self.Sync(): 238 sync_result = self.Sync()
206 return None 239 if not sync_result.success:
240 return CommitIdsResult(None, sync_result.fatal)
207 241
208 data = self._LsTree() 242 data = self._LsTree()
209 if not data: 243 if not data:
210 print('error: git ls-tree failed to return data for superproject', 244 print('error: git ls-tree failed to return data for superproject',
211 file=sys.stderr) 245 file=sys.stderr)
212 return None 246 return CommitIdsResult(None, True)
213 247
214 # Parse lines like the following to select lines starting with '160000' and 248 # Parse lines like the following to select lines starting with '160000' and
215 # build a dictionary with project path (last element) and its commit id (3rd element). 249 # build a dictionary with project path (last element) and its commit id (3rd element).
@@ -225,7 +259,7 @@ class Superproject(object):
225 commit_ids[ls_data[3]] = ls_data[2] 259 commit_ids[ls_data[3]] = ls_data[2]
226 260
227 self._project_commit_ids = commit_ids 261 self._project_commit_ids = commit_ids
228 return commit_ids 262 return CommitIdsResult(commit_ids, False)
229 263
230 def _WriteManfiestFile(self): 264 def _WriteManfiestFile(self):
231 """Writes manifest to a file. 265 """Writes manifest to a file.
@@ -250,6 +284,23 @@ class Superproject(object):
250 return None 284 return None
251 return manifest_path 285 return manifest_path
252 286
287 def _SkipUpdatingProjectRevisionId(self, project):
288 """Checks if a project's revision id needs to be updated or not.
289
290 Revision id for projects from local manifest will not be updated.
291
292 Args:
293 project: project whose revision id is being updated.
294
295 Returns:
296 True if a project's revision id should not be updated, or False,
297 """
298 path = project.relpath
299 if not path:
300 return True
301 # Skip the project if it comes from the local manifest.
302 return any(s.startswith(LOCAL_MANIFEST_GROUP_PREFIX) for s in project.groups)
303
253 def UpdateProjectsRevisionId(self, projects): 304 def UpdateProjectsRevisionId(self, projects):
254 """Update revisionId of every project in projects with the commit id. 305 """Update revisionId of every project in projects with the commit id.
255 306
@@ -257,30 +308,35 @@ class Superproject(object):
257 projects: List of projects whose revisionId needs to be updated. 308 projects: List of projects whose revisionId needs to be updated.
258 309
259 Returns: 310 Returns:
260 manifest_path: Path name of the overriding manfiest file instead of None. 311 UpdateProjectsResult
261 """ 312 """
262 commit_ids = self._GetAllProjectsCommitIds() 313 commit_ids_result = self._GetAllProjectsCommitIds()
314 commit_ids = commit_ids_result.commit_ids
263 if not commit_ids: 315 if not commit_ids:
264 print('error: Cannot get project commit ids from manifest', file=sys.stderr) 316 print('error: Cannot get project commit ids from manifest', file=sys.stderr)
265 return None 317 return UpdateProjectsResult(None, commit_ids_result.fatal)
266 318
267 projects_missing_commit_ids = [] 319 projects_missing_commit_ids = []
268 for project in projects: 320 for project in projects:
269 path = project.relpath 321 if self._SkipUpdatingProjectRevisionId(project):
270 if not path:
271 continue
272 # Skip the project if it comes from local manifest.
273 if any(s.startswith(LOCAL_MANIFEST_GROUP_PREFIX) for s in project.groups):
274 continue 322 continue
323 path = project.relpath
275 commit_id = commit_ids.get(path) 324 commit_id = commit_ids.get(path)
276 if commit_id: 325 if not commit_id:
277 project.SetRevisionId(commit_id)
278 else:
279 projects_missing_commit_ids.append(path) 326 projects_missing_commit_ids.append(path)
327
328 # If superproject doesn't have a commit id for a project, then report an
329 # error event and continue as if do not use superproject is specified.
280 if projects_missing_commit_ids: 330 if projects_missing_commit_ids:
281 print('error: please file a bug using %s to report missing commit_ids for: %s' % 331 msg = (f'error: please file a bug using {self._manifest.contactinfo.bugurl} '
282 (self._manifest.contactinfo.bugurl, projects_missing_commit_ids), file=sys.stderr) 332 f'to report missing commit_ids for: {projects_missing_commit_ids}')
283 return None 333 print(msg, file=sys.stderr)
334 self._git_event_log.ErrorEvent(msg, '')
335 return UpdateProjectsResult(None, False)
336
337 for project in projects:
338 if not self._SkipUpdatingProjectRevisionId(project):
339 project.SetRevisionId(commit_ids.get(project.relpath))
284 340
285 manifest_path = self._WriteManfiestFile() 341 manifest_path = self._WriteManfiestFile()
286 return manifest_path 342 return UpdateProjectsResult(manifest_path, False)