blob: 5d8c0d4ea9cbcdc6f6f82a4cfa78a9632dec1966 [file] [log] [blame]
Raman Tenneti6a872c92021-01-14 19:17:50 -08001# Copyright (C) 2021 The Android Open Source Project
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
Gavin Makea2e3302023-03-11 06:46:20 +000015"""Provide functionality to get projects and their commit ids from Superproject.
Raman Tenneti6a872c92021-01-14 19:17:50 -080016
17For more information on superproject, check out:
18https://en.wikibooks.org/wiki/Git/Submodules_and_Superprojects
19
20Examples:
LaMont Jonesff6b1da2022-06-01 21:03:34 +000021 superproject = Superproject(manifest, name, remote, revision)
Raman Tenneti784e16f2021-06-11 17:29:45 -070022 UpdateProjectsResult = superproject.UpdateProjectsRevisionId(projects)
Raman Tenneti6a872c92021-01-14 19:17:50 -080023"""
24
Xin Li0cb6e922021-06-16 10:19:00 -070025import functools
Mike Frysinger64477332023-08-21 21:20:32 -040026import hashlib
Raman Tenneti6a872c92021-01-14 19:17:50 -080027import os
28import sys
Xin Li0cb6e922021-06-16 10:19:00 -070029import time
Raman Tenneti784e16f2021-06-11 17:29:45 -070030from typing import NamedTuple
Raman Tenneti6a872c92021-01-14 19:17:50 -080031
Mike Frysinger64477332023-08-21 21:20:32 -040032from git_command import git_require
33from git_command import GitCommand
Xin Li0cb6e922021-06-16 10:19:00 -070034from git_config import RepoConfig
Daniel Kutik035f22a2022-12-13 12:34:23 +010035from git_refs import GitRefs
Raman Tenneti6a872c92021-01-14 19:17:50 -080036
Mike Frysinger64477332023-08-21 21:20:32 -040037
Gavin Makea2e3302023-03-11 06:46:20 +000038_SUPERPROJECT_GIT_NAME = "superproject.git"
39_SUPERPROJECT_MANIFEST_NAME = "superproject_override.xml"
Raman Tenneti8d43dea2021-02-07 16:30:27 -080040
Raman Tenneti6a872c92021-01-14 19:17:50 -080041
Raman Tenneti784e16f2021-06-11 17:29:45 -070042class SyncResult(NamedTuple):
Gavin Makea2e3302023-03-11 06:46:20 +000043 """Return the status of sync and whether caller should exit."""
Raman Tenneti784e16f2021-06-11 17:29:45 -070044
Gavin Makea2e3302023-03-11 06:46:20 +000045 # Whether the superproject sync was successful.
46 success: bool
47 # Whether the caller should exit.
48 fatal: bool
Raman Tenneti784e16f2021-06-11 17:29:45 -070049
50
51class CommitIdsResult(NamedTuple):
Gavin Makea2e3302023-03-11 06:46:20 +000052 """Return the commit ids and whether caller should exit."""
Raman Tenneti784e16f2021-06-11 17:29:45 -070053
Gavin Makea2e3302023-03-11 06:46:20 +000054 # A dictionary with the projects/commit ids on success, otherwise None.
55 commit_ids: dict
56 # Whether the caller should exit.
57 fatal: bool
Raman Tenneti784e16f2021-06-11 17:29:45 -070058
59
60class UpdateProjectsResult(NamedTuple):
Gavin Makea2e3302023-03-11 06:46:20 +000061 """Return the overriding manifest file and whether caller should exit."""
Raman Tenneti784e16f2021-06-11 17:29:45 -070062
Gavin Makea2e3302023-03-11 06:46:20 +000063 # Path name of the overriding manifest file if successful, otherwise None.
64 manifest_path: str
65 # Whether the caller should exit.
66 fatal: bool
Raman Tenneti784e16f2021-06-11 17:29:45 -070067
68
Raman Tenneti6a872c92021-01-14 19:17:50 -080069class Superproject(object):
Gavin Makea2e3302023-03-11 06:46:20 +000070 """Get commit ids from superproject.
Raman Tenneti6a872c92021-01-14 19:17:50 -080071
Gavin Makea2e3302023-03-11 06:46:20 +000072 Initializes a local copy of a superproject for the manifest. This allows
73 lookup of commit ids for all projects. It contains _project_commit_ids which
74 is a dictionary with project/commit id entries.
Raman Tenneti6a872c92021-01-14 19:17:50 -080075 """
Raman Tenneti6a872c92021-01-14 19:17:50 -080076
Gavin Makea2e3302023-03-11 06:46:20 +000077 def __init__(
78 self,
79 manifest,
80 name,
81 remote,
82 revision,
83 superproject_dir="exp-superproject",
84 ):
85 """Initializes superproject.
LaMont Jonesd56e2eb2022-04-07 18:14:46 +000086
Gavin Makea2e3302023-03-11 06:46:20 +000087 Args:
88 manifest: A Manifest object that is to be written to a file.
89 name: The unique name of the superproject
90 remote: The RemoteSpec for the remote.
91 revision: The name of the git branch to track.
92 superproject_dir: Relative path under |manifest.subdir| to checkout
93 superproject.
94 """
95 self._project_commit_ids = None
96 self._manifest = manifest
97 self.name = name
98 self.remote = remote
99 self.revision = self._branch = revision
100 self._repodir = manifest.repodir
101 self._superproject_dir = superproject_dir
102 self._superproject_path = manifest.SubmanifestInfoDir(
103 manifest.path_prefix, superproject_dir
104 )
105 self._manifest_path = os.path.join(
106 self._superproject_path, _SUPERPROJECT_MANIFEST_NAME
107 )
108 git_name = hashlib.md5(remote.name.encode("utf8")).hexdigest() + "-"
109 self._remote_url = remote.url
110 self._work_git_name = git_name + _SUPERPROJECT_GIT_NAME
111 self._work_git = os.path.join(
112 self._superproject_path, self._work_git_name
113 )
LaMont Jonesd56e2eb2022-04-07 18:14:46 +0000114
Gavin Makea2e3302023-03-11 06:46:20 +0000115 # The following are command arguemnts, rather than superproject
116 # attributes, and were included here originally. They should eventually
117 # become arguments that are passed down from the public methods, instead
118 # of being treated as attributes.
119 self._git_event_log = None
120 self._quiet = False
121 self._print_messages = False
LaMont Jonesd56e2eb2022-04-07 18:14:46 +0000122
Gavin Makea2e3302023-03-11 06:46:20 +0000123 def SetQuiet(self, value):
124 """Set the _quiet attribute."""
125 self._quiet = value
Raman Tenneti6a872c92021-01-14 19:17:50 -0800126
Gavin Makea2e3302023-03-11 06:46:20 +0000127 def SetPrintMessages(self, value):
128 """Set the _print_messages attribute."""
129 self._print_messages = value
Raman Tennetiae86a462021-07-27 08:54:59 -0700130
Gavin Makea2e3302023-03-11 06:46:20 +0000131 @property
132 def project_commit_ids(self):
133 """Returns a dictionary of projects and their commit ids."""
134 return self._project_commit_ids
Raman Tenneti8db30d62021-07-06 21:30:06 -0700135
Gavin Makea2e3302023-03-11 06:46:20 +0000136 @property
137 def manifest_path(self):
138 """Returns the manifest path if the path exists or None."""
139 return (
140 self._manifest_path if os.path.exists(self._manifest_path) else None
141 )
Raman Tennetid8e8ae82021-09-15 16:32:33 -0700142
Gavin Makea2e3302023-03-11 06:46:20 +0000143 def _LogMessage(self, fmt, *inputs):
144 """Logs message to stderr and _git_event_log."""
145 message = f"{self._LogMessagePrefix()} {fmt.format(*inputs)}"
146 if self._print_messages:
147 print(message, file=sys.stderr)
148 self._git_event_log.ErrorEvent(message, fmt)
Raman Tenneti5637afc2021-08-11 09:26:30 -0700149
Gavin Makea2e3302023-03-11 06:46:20 +0000150 def _LogMessagePrefix(self):
151 """Returns the prefix string to be logged in each log message"""
152 return (
153 f"repo superproject branch: {self._branch} url: {self._remote_url}"
154 )
Raman Tenneti5637afc2021-08-11 09:26:30 -0700155
Gavin Makea2e3302023-03-11 06:46:20 +0000156 def _LogError(self, fmt, *inputs):
157 """Logs error message to stderr and _git_event_log."""
158 self._LogMessage(f"error: {fmt}", *inputs)
Raman Tenneti6a872c92021-01-14 19:17:50 -0800159
Gavin Makea2e3302023-03-11 06:46:20 +0000160 def _LogWarning(self, fmt, *inputs):
161 """Logs warning message to stderr and _git_event_log."""
162 self._LogMessage(f"warning: {fmt}", *inputs)
Raman Tenneti6a872c92021-01-14 19:17:50 -0800163
Gavin Makea2e3302023-03-11 06:46:20 +0000164 def _Init(self):
165 """Sets up a local Git repository to get a copy of a superproject.
Raman Tenneti9e787532021-02-01 11:47:06 -0800166
Gavin Makea2e3302023-03-11 06:46:20 +0000167 Returns:
168 True if initialization is successful, or False.
169 """
170 if not os.path.exists(self._superproject_path):
171 os.mkdir(self._superproject_path)
172 if not self._quiet and not os.path.exists(self._work_git):
173 print(
174 "%s: Performing initial setup for superproject; this might "
175 "take several minutes." % self._work_git
176 )
177 cmd = ["init", "--bare", self._work_git_name]
178 p = GitCommand(
179 None,
180 cmd,
181 cwd=self._superproject_path,
182 capture_stdout=True,
183 capture_stderr=True,
184 )
185 retval = p.Wait()
186 if retval:
187 self._LogWarning(
188 "git init call failed, command: git {}, "
189 "return code: {}, stderr: {}",
190 cmd,
191 retval,
192 p.stderr,
193 )
194 return False
195 return True
Joanna Wang0e4f1e72022-12-08 17:46:28 -0500196
Gavin Makea2e3302023-03-11 06:46:20 +0000197 def _Fetch(self):
198 """Fetches a superproject for the manifest based on |_remote_url|.
Joanna Wang0e4f1e72022-12-08 17:46:28 -0500199
Gavin Makea2e3302023-03-11 06:46:20 +0000200 This runs git fetch which stores a local copy the superproject.
Raman Tenneti9e787532021-02-01 11:47:06 -0800201
Gavin Makea2e3302023-03-11 06:46:20 +0000202 Returns:
203 True if fetch is successful, or False.
204 """
205 if not os.path.exists(self._work_git):
206 self._LogWarning("git fetch missing directory: {}", self._work_git)
207 return False
208 if not git_require((2, 28, 0)):
209 self._LogWarning(
210 "superproject requires a git version 2.28 or later"
211 )
212 return False
213 cmd = [
214 "fetch",
215 self._remote_url,
216 "--depth",
217 "1",
218 "--force",
219 "--no-tags",
220 "--filter",
221 "blob:none",
222 ]
Raman Tenneti6a872c92021-01-14 19:17:50 -0800223
Gavin Makea2e3302023-03-11 06:46:20 +0000224 # Check if there is a local ref that we can pass to --negotiation-tip.
225 # If this is the first fetch, it does not exist yet.
226 # We use --negotiation-tip to speed up the fetch. Superproject branches
227 # do not share commits. So this lets git know it only needs to send
228 # commits reachable from the specified local refs.
229 rev_commit = GitRefs(self._work_git).get(f"refs/heads/{self.revision}")
230 if rev_commit:
231 cmd.extend(["--negotiation-tip", rev_commit])
Raman Tenneti6a872c92021-01-14 19:17:50 -0800232
Gavin Makea2e3302023-03-11 06:46:20 +0000233 if self._branch:
234 cmd += [self._branch + ":" + self._branch]
235 p = GitCommand(
236 None,
237 cmd,
238 cwd=self._work_git,
239 capture_stdout=True,
240 capture_stderr=True,
241 )
242 retval = p.Wait()
243 if retval:
244 self._LogWarning(
245 "git fetch call failed, command: git {}, "
246 "return code: {}, stderr: {}",
247 cmd,
248 retval,
249 p.stderr,
250 )
251 return False
252 return True
Raman Tennetice64e3d2021-02-08 13:27:41 -0800253
Gavin Makea2e3302023-03-11 06:46:20 +0000254 def _LsTree(self):
255 """Gets the commit ids for all projects.
Raman Tenneti6a872c92021-01-14 19:17:50 -0800256
Gavin Makea2e3302023-03-11 06:46:20 +0000257 Works only in git repositories.
Raman Tenneti6a872c92021-01-14 19:17:50 -0800258
Gavin Makea2e3302023-03-11 06:46:20 +0000259 Returns:
260 data: data returned from 'git ls-tree ...' instead of None.
261 """
262 if not os.path.exists(self._work_git):
263 self._LogWarning(
264 "git ls-tree missing directory: {}", self._work_git
265 )
266 return None
267 data = None
268 branch = "HEAD" if not self._branch else self._branch
269 cmd = ["ls-tree", "-z", "-r", branch]
LaMont Jonesd56e2eb2022-04-07 18:14:46 +0000270
Gavin Makea2e3302023-03-11 06:46:20 +0000271 p = GitCommand(
272 None,
273 cmd,
274 cwd=self._work_git,
275 capture_stdout=True,
276 capture_stderr=True,
277 )
278 retval = p.Wait()
279 if retval == 0:
280 data = p.stdout
281 else:
282 self._LogWarning(
283 "git ls-tree call failed, command: git {}, "
284 "return code: {}, stderr: {}",
285 cmd,
286 retval,
287 p.stderr,
288 )
289 return data
Raman Tenneti21dce3d2021-02-09 00:26:31 -0800290
Gavin Makea2e3302023-03-11 06:46:20 +0000291 def Sync(self, git_event_log):
292 """Gets a local copy of a superproject for the manifest.
LaMont Jones2cc3ab72022-04-13 15:58:58 +0000293
Gavin Makea2e3302023-03-11 06:46:20 +0000294 Args:
295 git_event_log: an EventLog, for git tracing.
Raman Tenneti8d43dea2021-02-07 16:30:27 -0800296
Gavin Makea2e3302023-03-11 06:46:20 +0000297 Returns:
298 SyncResult
299 """
300 self._git_event_log = git_event_log
301 if not self._manifest.superproject:
302 self._LogWarning(
303 "superproject tag is not defined in manifest: {}",
304 self._manifest.manifestFile,
305 )
306 return SyncResult(False, False)
Raman Tenneti6a872c92021-01-14 19:17:50 -0800307
Gavin Makea2e3302023-03-11 06:46:20 +0000308 _PrintBetaNotice()
Raman Tenneti21dce3d2021-02-09 00:26:31 -0800309
Gavin Makea2e3302023-03-11 06:46:20 +0000310 should_exit = True
311 if not self._remote_url:
312 self._LogWarning(
313 "superproject URL is not defined in manifest: {}",
314 self._manifest.manifestFile,
315 )
316 return SyncResult(False, should_exit)
Raman Tenneti21dce3d2021-02-09 00:26:31 -0800317
Gavin Makea2e3302023-03-11 06:46:20 +0000318 if not self._Init():
319 return SyncResult(False, should_exit)
320 if not self._Fetch():
321 return SyncResult(False, should_exit)
322 if not self._quiet:
323 print(
324 "%s: Initial setup for superproject completed." % self._work_git
325 )
326 return SyncResult(True, False)
Raman Tenneti6a872c92021-01-14 19:17:50 -0800327
Gavin Makea2e3302023-03-11 06:46:20 +0000328 def _GetAllProjectsCommitIds(self):
329 """Get commit ids for all projects from superproject and save them.
Raman Tenneti6a872c92021-01-14 19:17:50 -0800330
Gavin Makea2e3302023-03-11 06:46:20 +0000331 Commit ids are saved in _project_commit_ids.
Raman Tenneti1fd7bc22021-02-04 14:39:38 -0800332
Gavin Makea2e3302023-03-11 06:46:20 +0000333 Returns:
334 CommitIdsResult
335 """
336 sync_result = self.Sync(self._git_event_log)
337 if not sync_result.success:
338 return CommitIdsResult(None, sync_result.fatal)
Raman Tenneti1fd7bc22021-02-04 14:39:38 -0800339
Gavin Makea2e3302023-03-11 06:46:20 +0000340 data = self._LsTree()
341 if not data:
342 self._LogWarning(
343 "git ls-tree failed to return data for manifest: {}",
344 self._manifest.manifestFile,
345 )
346 return CommitIdsResult(None, True)
Raman Tenneti1fd7bc22021-02-04 14:39:38 -0800347
Gavin Makea2e3302023-03-11 06:46:20 +0000348 # Parse lines like the following to select lines starting with '160000'
349 # and build a dictionary with project path (last element) and its commit
350 # id (3rd element).
351 #
352 # 160000 commit 2c2724cb36cd5a9cec6c852c681efc3b7c6b86ea\tart\x00
353 # 120000 blob acc2cbdf438f9d2141f0ae424cec1d8fc4b5d97f\tbootstrap.bash\x00 # noqa: E501
354 commit_ids = {}
355 for line in data.split("\x00"):
356 ls_data = line.split(None, 3)
357 if not ls_data:
358 break
359 if ls_data[0] == "160000":
360 commit_ids[ls_data[3]] = ls_data[2]
Raman Tenneti784e16f2021-06-11 17:29:45 -0700361
Gavin Makea2e3302023-03-11 06:46:20 +0000362 self._project_commit_ids = commit_ids
363 return CommitIdsResult(commit_ids, False)
Raman Tenneti784e16f2021-06-11 17:29:45 -0700364
Gavin Makea2e3302023-03-11 06:46:20 +0000365 def _WriteManifestFile(self):
366 """Writes manifest to a file.
Raman Tenneti784e16f2021-06-11 17:29:45 -0700367
Gavin Makea2e3302023-03-11 06:46:20 +0000368 Returns:
369 manifest_path: Path name of the file into which manifest is written
370 instead of None.
371 """
372 if not os.path.exists(self._superproject_path):
373 self._LogWarning(
374 "missing superproject directory: {}", self._superproject_path
375 )
376 return None
377 manifest_str = self._manifest.ToXml(
378 groups=self._manifest.GetGroupsStr(), omit_local=True
379 ).toxml()
380 manifest_path = self._manifest_path
381 try:
382 with open(manifest_path, "w", encoding="utf-8") as fp:
383 fp.write(manifest_str)
384 except IOError as e:
385 self._LogError("cannot write manifest to : {} {}", manifest_path, e)
386 return None
387 return manifest_path
Raman Tenneti784e16f2021-06-11 17:29:45 -0700388
Gavin Makea2e3302023-03-11 06:46:20 +0000389 def _SkipUpdatingProjectRevisionId(self, project):
390 """Checks if a project's revision id needs to be updated or not.
Raman Tenneti1fd7bc22021-02-04 14:39:38 -0800391
Gavin Makea2e3302023-03-11 06:46:20 +0000392 Revision id for projects from local manifest will not be updated.
Raman Tenneti1fd7bc22021-02-04 14:39:38 -0800393
Gavin Makea2e3302023-03-11 06:46:20 +0000394 Args:
395 project: project whose revision id is being updated.
Raman Tenneti1fd7bc22021-02-04 14:39:38 -0800396
Gavin Makea2e3302023-03-11 06:46:20 +0000397 Returns:
398 True if a project's revision id should not be updated, or False,
399 """
400 path = project.relpath
401 if not path:
402 return True
403 # Skip the project with revisionId.
404 if project.revisionId:
405 return True
406 # Skip the project if it comes from the local manifest.
407 return project.manifest.IsFromLocalManifest(project)
Raman Tenneti784e16f2021-06-11 17:29:45 -0700408
Gavin Makea2e3302023-03-11 06:46:20 +0000409 def UpdateProjectsRevisionId(self, projects, git_event_log):
410 """Update revisionId of every project in projects with the commit id.
Raman Tenneti784e16f2021-06-11 17:29:45 -0700411
Gavin Makea2e3302023-03-11 06:46:20 +0000412 Args:
413 projects: a list of projects whose revisionId needs to be updated.
414 git_event_log: an EventLog, for git tracing.
Raman Tenneti1fd7bc22021-02-04 14:39:38 -0800415
Gavin Makea2e3302023-03-11 06:46:20 +0000416 Returns:
417 UpdateProjectsResult
418 """
419 self._git_event_log = git_event_log
420 commit_ids_result = self._GetAllProjectsCommitIds()
421 commit_ids = commit_ids_result.commit_ids
422 if not commit_ids:
423 return UpdateProjectsResult(None, commit_ids_result.fatal)
424
425 projects_missing_commit_ids = []
426 for project in projects:
427 if self._SkipUpdatingProjectRevisionId(project):
428 continue
429 path = project.relpath
430 commit_id = commit_ids.get(path)
431 if not commit_id:
432 projects_missing_commit_ids.append(path)
433
434 # If superproject doesn't have a commit id for a project, then report an
435 # error event and continue as if do not use superproject is specified.
436 if projects_missing_commit_ids:
437 self._LogWarning(
438 "please file a bug using {} to report missing "
439 "commit_ids for: {}",
440 self._manifest.contactinfo.bugurl,
441 projects_missing_commit_ids,
442 )
443 return UpdateProjectsResult(None, False)
444
445 for project in projects:
446 if not self._SkipUpdatingProjectRevisionId(project):
447 project.SetRevisionId(commit_ids.get(project.relpath))
448
449 manifest_path = self._WriteManifestFile()
450 return UpdateProjectsResult(manifest_path, False)
Xin Li0cb6e922021-06-16 10:19:00 -0700451
452
LaMont Jones2cc3ab72022-04-13 15:58:58 +0000453@functools.lru_cache(maxsize=10)
454def _PrintBetaNotice():
Gavin Makea2e3302023-03-11 06:46:20 +0000455 """Print the notice of beta status."""
456 print(
457 "NOTICE: --use-superproject is in beta; report any issues to the "
458 "address described in `repo version`",
459 file=sys.stderr,
460 )
LaMont Jones2cc3ab72022-04-13 15:58:58 +0000461
462
Xin Li0cb6e922021-06-16 10:19:00 -0700463@functools.lru_cache(maxsize=None)
464def _UseSuperprojectFromConfiguration():
Gavin Makea2e3302023-03-11 06:46:20 +0000465 """Returns the user choice of whether to use superproject."""
466 user_cfg = RepoConfig.ForUser()
467 time_now = int(time.time())
Xin Li0cb6e922021-06-16 10:19:00 -0700468
Gavin Makea2e3302023-03-11 06:46:20 +0000469 user_value = user_cfg.GetBoolean("repo.superprojectChoice")
470 if user_value is not None:
471 user_expiration = user_cfg.GetInt("repo.superprojectChoiceExpire")
472 if (
473 user_expiration is None
474 or user_expiration <= 0
475 or user_expiration >= time_now
476 ):
477 # TODO(b/190688390) - Remove prompt when we are comfortable with the
478 # new default value.
479 if user_value:
480 print(
481 (
482 "You are currently enrolled in Git submodules "
483 "experiment (go/android-submodules-quickstart). Use "
484 "--no-use-superproject to override.\n"
485 ),
486 file=sys.stderr,
487 )
488 else:
489 print(
490 (
491 "You are not currently enrolled in Git submodules "
492 "experiment (go/android-submodules-quickstart). Use "
493 "--use-superproject to override.\n"
494 ),
495 file=sys.stderr,
496 )
497 return user_value
Xin Li0cb6e922021-06-16 10:19:00 -0700498
Gavin Makea2e3302023-03-11 06:46:20 +0000499 # We don't have an unexpired choice, ask for one.
500 system_cfg = RepoConfig.ForSystem()
501 system_value = system_cfg.GetBoolean("repo.superprojectChoice")
502 if system_value:
503 # The system configuration is proposing that we should enable the
504 # use of superproject. Treat the user as enrolled for two weeks.
505 #
506 # TODO(b/190688390) - Remove prompt when we are comfortable with the new
507 # default value.
508 userchoice = True
509 time_choiceexpire = time_now + (86400 * 14)
510 user_cfg.SetString(
511 "repo.superprojectChoiceExpire", str(time_choiceexpire)
512 )
513 user_cfg.SetBoolean("repo.superprojectChoice", userchoice)
514 print(
515 "You are automatically enrolled in Git submodules experiment "
516 "(go/android-submodules-quickstart) for another two weeks.\n",
517 file=sys.stderr,
518 )
519 return True
Xin Li0cb6e922021-06-16 10:19:00 -0700520
Gavin Makea2e3302023-03-11 06:46:20 +0000521 # For all other cases, we would not use superproject by default.
522 return False
Xin Li0cb6e922021-06-16 10:19:00 -0700523
524
LaMont Jones5fa912b2022-04-14 14:41:13 +0000525def PrintMessages(use_superproject, manifest):
Gavin Makea2e3302023-03-11 06:46:20 +0000526 """Returns a boolean if error/warning messages are to be printed.
LaMont Jones5fa912b2022-04-14 14:41:13 +0000527
Gavin Makea2e3302023-03-11 06:46:20 +0000528 Args:
529 use_superproject: option value from optparse.
530 manifest: manifest to use.
531 """
532 return use_superproject is not None or bool(manifest.superproject)
Raman Tennetib55769a2021-08-13 11:47:24 -0700533
534
LaMont Jones5fa912b2022-04-14 14:41:13 +0000535def UseSuperproject(use_superproject, manifest):
Gavin Makea2e3302023-03-11 06:46:20 +0000536 """Returns a boolean if use-superproject option is enabled.
Xin Li0cb6e922021-06-16 10:19:00 -0700537
Gavin Makea2e3302023-03-11 06:46:20 +0000538 Args:
539 use_superproject: option value from optparse.
540 manifest: manifest to use.
LaMont Jonesff6b1da2022-06-01 21:03:34 +0000541
Gavin Makea2e3302023-03-11 06:46:20 +0000542 Returns:
543 Whether the superproject should be used.
544 """
LaMont Jones5fa912b2022-04-14 14:41:13 +0000545
Gavin Makea2e3302023-03-11 06:46:20 +0000546 if not manifest.superproject:
547 # This (sub) manifest does not have a superproject definition.
548 return False
549 elif use_superproject is not None:
550 return use_superproject
LaMont Jonesd56e2eb2022-04-07 18:14:46 +0000551 else:
Gavin Makea2e3302023-03-11 06:46:20 +0000552 client_value = manifest.manifestProject.use_superproject
553 if client_value is not None:
554 return client_value
555 elif manifest.superproject:
556 return _UseSuperprojectFromConfiguration()
557 else:
558 return False