diff options
| author | LaMont Jones <lamontjones@google.com> | 2022-04-11 22:50:11 +0000 |
|---|---|---|
| committer | LaMont Jones <lamontjones@google.com> | 2022-05-26 00:03:37 +0000 |
| commit | bdcba7dc36f1c8e6041681eb5b3b5229c93c7c5c (patch) | |
| tree | ef0dbd149d7e5cd35c4d007a5052ba42bcc1c881 | |
| parent | 1d00a7e2ae64b6c08aff60c2e7ed5c2d89caf8d6 (diff) | |
| download | git-repo-bdcba7dc36f1c8e6041681eb5b3b5229c93c7c5c.tar.gz | |
sync: add multi-manifest supportv2.26
With this change, partial syncs (sync with a project list) are again
supported.
If the updated manifest includes new sub manifests, download them
inheriting options from the parent manifestProject.
Change-Id: Id952f85df2e26d34e38b251973be26434443ff56
Reviewed-on: https://gerrit-review.googlesource.com/c/git-repo/+/334819
Reviewed-by: Mike Frysinger <vapier@google.com>
Tested-by: LaMont Jones <lamontjones@google.com>
| -rw-r--r-- | command.py | 11 | ||||
| -rwxr-xr-x | main.py | 3 | ||||
| -rw-r--r-- | project.py | 61 | ||||
| -rw-r--r-- | subcmds/init.py | 5 | ||||
| -rw-r--r-- | subcmds/sync.py | 274 |
5 files changed, 247 insertions, 107 deletions
| @@ -144,11 +144,10 @@ class Command(object): | |||
| 144 | help=f'number of jobs to run in parallel (default: {default})') | 144 | help=f'number of jobs to run in parallel (default: {default})') |
| 145 | 145 | ||
| 146 | m = p.add_option_group('Multi-manifest options') | 146 | m = p.add_option_group('Multi-manifest options') |
| 147 | m.add_option('--outer-manifest', action='store_true', | 147 | m.add_option('--outer-manifest', action='store_true', default=None, |
| 148 | help='operate starting at the outermost manifest') | 148 | help='operate starting at the outermost manifest') |
| 149 | m.add_option('--no-outer-manifest', dest='outer_manifest', | 149 | m.add_option('--no-outer-manifest', dest='outer_manifest', |
| 150 | action='store_false', default=None, | 150 | action='store_false', help='do not operate on outer manifests') |
| 151 | help='do not operate on outer manifests') | ||
| 152 | m.add_option('--this-manifest-only', action='store_true', default=None, | 151 | m.add_option('--this-manifest-only', action='store_true', default=None, |
| 153 | help='only operate on this (sub)manifest') | 152 | help='only operate on this (sub)manifest') |
| 154 | m.add_option('--no-this-manifest-only', '--all-manifests', | 153 | m.add_option('--no-this-manifest-only', '--all-manifests', |
| @@ -186,6 +185,10 @@ class Command(object): | |||
| 186 | """Validate common options.""" | 185 | """Validate common options.""" |
| 187 | opt.quiet = opt.output_mode is False | 186 | opt.quiet = opt.output_mode is False |
| 188 | opt.verbose = opt.output_mode is True | 187 | opt.verbose = opt.output_mode is True |
| 188 | if opt.outer_manifest is None: | ||
| 189 | # By default, treat multi-manifest instances as a single manifest from | ||
| 190 | # the user's perspective. | ||
| 191 | opt.outer_manifest = True | ||
| 189 | 192 | ||
| 190 | def ValidateOptions(self, opt, args): | 193 | def ValidateOptions(self, opt, args): |
| 191 | """Validate the user options & arguments before executing. | 194 | """Validate the user options & arguments before executing. |
| @@ -385,7 +388,7 @@ class Command(object): | |||
| 385 | opt: The command options. | 388 | opt: The command options. |
| 386 | """ | 389 | """ |
| 387 | top = self.outer_manifest | 390 | top = self.outer_manifest |
| 388 | if opt.outer_manifest is False or opt.this_manifest_only: | 391 | if not opt.outer_manifest or opt.this_manifest_only: |
| 389 | top = self.manifest | 392 | top = self.manifest |
| 390 | yield top | 393 | yield top |
| 391 | if not opt.this_manifest_only: | 394 | if not opt.this_manifest_only: |
| @@ -294,8 +294,7 @@ class _Repo(object): | |||
| 294 | cmd.ValidateOptions(copts, cargs) | 294 | cmd.ValidateOptions(copts, cargs) |
| 295 | 295 | ||
| 296 | this_manifest_only = copts.this_manifest_only | 296 | this_manifest_only = copts.this_manifest_only |
| 297 | # If not specified, default to using the outer manifest. | 297 | outer_manifest = copts.outer_manifest |
| 298 | outer_manifest = copts.outer_manifest is not False | ||
| 299 | if cmd.MULTI_MANIFEST_SUPPORT or this_manifest_only: | 298 | if cmd.MULTI_MANIFEST_SUPPORT or this_manifest_only: |
| 300 | result = cmd.Execute(copts, cargs) | 299 | result = cmd.Execute(copts, cargs) |
| 301 | elif outer_manifest and repo_client.manifest.is_submanifest: | 300 | elif outer_manifest and repo_client.manifest.is_submanifest: |
| @@ -3467,6 +3467,67 @@ class ManifestProject(MetaProject): | |||
| 3467 | """Return the name of the platform.""" | 3467 | """Return the name of the platform.""" |
| 3468 | return platform.system().lower() | 3468 | return platform.system().lower() |
| 3469 | 3469 | ||
| 3470 | def SyncWithPossibleInit(self, submanifest, verbose=False, | ||
| 3471 | current_branch_only=False, tags='', git_event_log=None): | ||
| 3472 | """Sync a manifestProject, possibly for the first time. | ||
| 3473 | |||
| 3474 | Call Sync() with arguments from the most recent `repo init`. If this is a | ||
| 3475 | new sub manifest, then inherit options from the parent's manifestProject. | ||
| 3476 | |||
| 3477 | This is used by subcmds.Sync() to do an initial download of new sub | ||
| 3478 | manifests. | ||
| 3479 | |||
| 3480 | Args: | ||
| 3481 | submanifest: an XmlSubmanifest, the submanifest to re-sync. | ||
| 3482 | verbose: a boolean, whether to show all output, rather than only errors. | ||
| 3483 | current_branch_only: a boolean, whether to only fetch the current manifest | ||
| 3484 | branch from the server. | ||
| 3485 | tags: a boolean, whether to fetch tags. | ||
| 3486 | git_event_log: an EventLog, for git tracing. | ||
| 3487 | """ | ||
| 3488 | # TODO(lamontjones): when refactoring sync (and init?) consider how to | ||
| 3489 | # better get the init options that we should use when syncing uncovers a new | ||
| 3490 | # submanifest. | ||
| 3491 | git_event_log = git_event_log or EventLog() | ||
| 3492 | spec = submanifest.ToSubmanifestSpec() | ||
| 3493 | # Use the init options from the existing manifestProject, or the parent if | ||
| 3494 | # it doesn't exist. | ||
| 3495 | # | ||
| 3496 | # Today, we only support changing manifest_groups on the sub-manifest, with | ||
| 3497 | # no supported-for-the-user way to change the other arguments from those | ||
| 3498 | # specified by the outermost manifest. | ||
| 3499 | # | ||
| 3500 | # TODO(lamontjones): determine which of these should come from the outermost | ||
| 3501 | # manifest and which should come from the parent manifest. | ||
| 3502 | mp = self if self.Exists else submanifest.parent.manifestProject | ||
| 3503 | return self.Sync( | ||
| 3504 | manifest_url=spec.manifestUrl, | ||
| 3505 | manifest_branch=spec.revision, | ||
| 3506 | standalone_manifest=mp.standalone_manifest_url, | ||
| 3507 | groups=mp.manifest_groups, | ||
| 3508 | platform=mp.manifest_platform, | ||
| 3509 | mirror=mp.mirror, | ||
| 3510 | dissociate=mp.dissociate, | ||
| 3511 | reference=mp.reference, | ||
| 3512 | worktree=mp.use_worktree, | ||
| 3513 | submodules=mp.submodules, | ||
| 3514 | archive=mp.archive, | ||
| 3515 | partial_clone=mp.partial_clone, | ||
| 3516 | clone_filter=mp.clone_filter, | ||
| 3517 | partial_clone_exclude=mp.partial_clone_exclude, | ||
| 3518 | clone_bundle=mp.clone_bundle, | ||
| 3519 | git_lfs=mp.git_lfs, | ||
| 3520 | use_superproject=mp.use_superproject, | ||
| 3521 | verbose=verbose, | ||
| 3522 | current_branch_only=current_branch_only, | ||
| 3523 | tags=tags, | ||
| 3524 | depth=mp.depth, | ||
| 3525 | git_event_log=git_event_log, | ||
| 3526 | manifest_name=spec.manifestName, | ||
| 3527 | this_manifest_only=True, | ||
| 3528 | outer_manifest=False, | ||
| 3529 | ) | ||
| 3530 | |||
| 3470 | def Sync(self, _kwargs_only=(), manifest_url='', manifest_branch=None, | 3531 | def Sync(self, _kwargs_only=(), manifest_url='', manifest_branch=None, |
| 3471 | standalone_manifest=False, groups='', mirror=False, reference='', | 3532 | standalone_manifest=False, groups='', mirror=False, reference='', |
| 3472 | dissociate=False, worktree=False, submodules=False, archive=False, | 3533 | dissociate=False, worktree=False, submodules=False, archive=False, |
diff --git a/subcmds/init.py b/subcmds/init.py index 6e3951c9..cced44d5 100644 --- a/subcmds/init.py +++ b/subcmds/init.py | |||
| @@ -89,11 +89,10 @@ to update the working directory files. | |||
| 89 | def _Options(self, p, gitc_init=False): | 89 | def _Options(self, p, gitc_init=False): |
| 90 | Wrapper().InitParser(p, gitc_init=gitc_init) | 90 | Wrapper().InitParser(p, gitc_init=gitc_init) |
| 91 | m = p.add_option_group('Multi-manifest') | 91 | m = p.add_option_group('Multi-manifest') |
| 92 | m.add_option('--outer-manifest', action='store_true', | 92 | m.add_option('--outer-manifest', action='store_true', default=True, |
| 93 | help='operate starting at the outermost manifest') | 93 | help='operate starting at the outermost manifest') |
| 94 | m.add_option('--no-outer-manifest', dest='outer_manifest', | 94 | m.add_option('--no-outer-manifest', dest='outer_manifest', |
| 95 | action='store_false', default=None, | 95 | action='store_false', help='do not operate on outer manifests') |
| 96 | help='do not operate on outer manifests') | ||
| 97 | m.add_option('--this-manifest-only', action='store_true', default=None, | 96 | m.add_option('--this-manifest-only', action='store_true', default=None, |
| 98 | help='only operate on this (sub)manifest') | 97 | help='only operate on this (sub)manifest') |
| 99 | m.add_option('--no-this-manifest-only', '--all-manifests', | 98 | m.add_option('--no-this-manifest-only', '--all-manifests', |
diff --git a/subcmds/sync.py b/subcmds/sync.py index 9a66e48b..0abe23d6 100644 --- a/subcmds/sync.py +++ b/subcmds/sync.py | |||
| @@ -12,6 +12,7 @@ | |||
| 12 | # See the License for the specific language governing permissions and | 12 | # See the License for the specific language governing permissions and |
| 13 | # limitations under the License. | 13 | # limitations under the License. |
| 14 | 14 | ||
| 15 | import collections | ||
| 15 | import functools | 16 | import functools |
| 16 | import http.cookiejar as cookielib | 17 | import http.cookiejar as cookielib |
| 17 | import io | 18 | import io |
| @@ -66,7 +67,7 @@ _ONE_DAY_S = 24 * 60 * 60 | |||
| 66 | class Sync(Command, MirrorSafeCommand): | 67 | class Sync(Command, MirrorSafeCommand): |
| 67 | jobs = 1 | 68 | jobs = 1 |
| 68 | COMMON = True | 69 | COMMON = True |
| 69 | MULTI_MANIFEST_SUPPORT = False | 70 | MULTI_MANIFEST_SUPPORT = True |
| 70 | helpSummary = "Update working tree to the latest revision" | 71 | helpSummary = "Update working tree to the latest revision" |
| 71 | helpUsage = """ | 72 | helpUsage = """ |
| 72 | %prog [<project>...] | 73 | %prog [<project>...] |
| @@ -295,52 +296,92 @@ later is required to fix a server side protocol bug. | |||
| 295 | """ | 296 | """ |
| 296 | return git_superproject.UseSuperproject(opt.use_superproject, manifest) or opt.current_branch_only | 297 | return git_superproject.UseSuperproject(opt.use_superproject, manifest) or opt.current_branch_only |
| 297 | 298 | ||
| 298 | def _UpdateProjectsRevisionId(self, opt, args, load_local_manifests, superproject_logging_data, manifest): | 299 | def _UpdateProjectsRevisionId(self, opt, args, superproject_logging_data, |
| 299 | """Update revisionId of every project with the SHA from superproject. | 300 | manifest): |
| 301 | """Update revisionId of projects with the commit hash from the superproject. | ||
| 300 | 302 | ||
| 301 | This function updates each project's revisionId with SHA from superproject. | 303 | This function updates each project's revisionId with the commit hash from |
| 302 | It writes the updated manifest into a file and reloads the manifest from it. | 304 | the superproject. It writes the updated manifest into a file and reloads |
| 305 | the manifest from it. When appropriate, sub manifests are also processed. | ||
| 303 | 306 | ||
| 304 | Args: | 307 | Args: |
| 305 | opt: Program options returned from optparse. See _Options(). | 308 | opt: Program options returned from optparse. See _Options(). |
| 306 | args: Arguments to pass to GetProjects. See the GetProjects | 309 | args: Arguments to pass to GetProjects. See the GetProjects |
| 307 | docstring for details. | 310 | docstring for details. |
| 308 | load_local_manifests: Whether to load local manifests. | 311 | superproject_logging_data: A dictionary of superproject data to log. |
| 309 | superproject_logging_data: A dictionary of superproject data that is to be logged. | ||
| 310 | manifest: The manifest to use. | 312 | manifest: The manifest to use. |
| 311 | |||
| 312 | Returns: | ||
| 313 | Returns path to the overriding manifest file instead of None. | ||
| 314 | """ | 313 | """ |
| 315 | superproject = self.manifest.superproject | 314 | have_superproject = manifest.superproject or any( |
| 316 | superproject.SetQuiet(opt.quiet) | 315 | m.superproject for m in manifest.all_children) |
| 317 | print_messages = git_superproject.PrintMessages(opt.use_superproject, | 316 | if not have_superproject: |
| 318 | self.manifest) | 317 | return |
| 319 | superproject.SetPrintMessages(print_messages) | 318 | |
| 320 | if opt.local_only: | 319 | if opt.local_only: |
| 321 | manifest_path = superproject.manifest_path | 320 | manifest_path = manifest.superproject.manifest_path |
| 322 | if manifest_path: | 321 | if manifest_path: |
| 323 | self._ReloadManifest(manifest_path, manifest, load_local_manifests) | 322 | self._ReloadManifest(manifest_path, manifest) |
| 324 | return manifest_path | 323 | return |
| 325 | 324 | ||
| 326 | all_projects = self.GetProjects(args, | 325 | all_projects = self.GetProjects(args, |
| 327 | missing_ok=True, | 326 | missing_ok=True, |
| 328 | submodules_ok=opt.fetch_submodules) | 327 | submodules_ok=opt.fetch_submodules, |
| 329 | update_result = superproject.UpdateProjectsRevisionId( | 328 | manifest=manifest, |
| 330 | all_projects, git_event_log=self.git_event_log) | 329 | all_manifests=not opt.this_manifest_only) |
| 331 | manifest_path = update_result.manifest_path | 330 | |
| 332 | superproject_logging_data['updatedrevisionid'] = bool(manifest_path) | 331 | per_manifest = collections.defaultdict(list) |
| 333 | if manifest_path: | 332 | manifest_paths = {} |
| 334 | self._ReloadManifest(manifest_path, manifest, load_local_manifests) | 333 | if opt.this_manifest_only: |
| 334 | per_manifest[manifest.path_prefix] = all_projects | ||
| 335 | else: | 335 | else: |
| 336 | if print_messages: | 336 | for p in all_projects: |
| 337 | print('warning: Update of revisionId from superproject has failed, ' | 337 | per_manifest[p.manifest.path_prefix].append(p) |
| 338 | 'repo sync will not use superproject to fetch the source. ', | 338 | |
| 339 | 'Please resync with the --no-use-superproject option to avoid this repo warning.', | 339 | superproject_logging_data = {} |
| 340 | file=sys.stderr) | 340 | need_unload = False |
| 341 | if update_result.fatal and opt.use_superproject is not None: | 341 | for m in self.ManifestList(opt): |
| 342 | sys.exit(1) | 342 | if not m.path_prefix in per_manifest: |
| 343 | return manifest_path | 343 | continue |
| 344 | use_super = git_superproject.UseSuperproject(opt.use_superproject, m) | ||
| 345 | if superproject_logging_data: | ||
| 346 | superproject_logging_data['multimanifest'] = True | ||
| 347 | superproject_logging_data.update( | ||
| 348 | superproject=use_super, | ||
| 349 | haslocalmanifests=bool(m.HasLocalManifests), | ||
| 350 | hassuperprojecttag=bool(m.superproject), | ||
| 351 | ) | ||
| 352 | if use_super and (m.IsMirror or m.IsArchive): | ||
| 353 | # Don't use superproject, because we have no working tree. | ||
| 354 | use_super = False | ||
| 355 | superproject_logging_data['superproject'] = False | ||
| 356 | superproject_logging_data['noworktree'] = True | ||
| 357 | if opt.use_superproject is not False: | ||
| 358 | print(f'{m.path_prefix}: not using superproject because there is no ' | ||
| 359 | 'working tree.') | ||
| 360 | |||
| 361 | if not use_super: | ||
| 362 | continue | ||
| 363 | m.superproject.SetQuiet(opt.quiet) | ||
| 364 | print_messages = git_superproject.PrintMessages(opt.use_superproject, m) | ||
| 365 | m.superproject.SetPrintMessages(print_messages) | ||
| 366 | update_result = m.superproject.UpdateProjectsRevisionId( | ||
| 367 | per_manifest[m.path_prefix], git_event_log=self.git_event_log) | ||
| 368 | manifest_path = update_result.manifest_path | ||
| 369 | superproject_logging_data['updatedrevisionid'] = bool(manifest_path) | ||
| 370 | if manifest_path: | ||
| 371 | m.SetManifestOverride(manifest_path) | ||
| 372 | need_unload = True | ||
| 373 | else: | ||
| 374 | if print_messages: | ||
| 375 | print(f'{m.path_prefix}: warning: Update of revisionId from ' | ||
| 376 | 'superproject has failed, repo sync will not use superproject ' | ||
| 377 | 'to fetch the source. ', | ||
| 378 | 'Please resync with the --no-use-superproject option to avoid ' | ||
| 379 | 'this repo warning.', | ||
| 380 | file=sys.stderr) | ||
| 381 | if update_result.fatal and opt.use_superproject is not None: | ||
| 382 | sys.exit(1) | ||
| 383 | if need_unload: | ||
| 384 | m.outer_client.manifest.Unload() | ||
| 344 | 385 | ||
| 345 | def _FetchProjectList(self, opt, projects): | 386 | def _FetchProjectList(self, opt, projects): |
| 346 | """Main function of the fetch worker. | 387 | """Main function of the fetch worker. |
| @@ -485,8 +526,8 @@ later is required to fix a server side protocol bug. | |||
| 485 | 526 | ||
| 486 | return (ret, fetched) | 527 | return (ret, fetched) |
| 487 | 528 | ||
| 488 | def _FetchMain(self, opt, args, all_projects, err_event, manifest_name, | 529 | def _FetchMain(self, opt, args, all_projects, err_event, |
| 489 | load_local_manifests, ssh_proxy, manifest): | 530 | ssh_proxy, manifest): |
| 490 | """The main network fetch loop. | 531 | """The main network fetch loop. |
| 491 | 532 | ||
| 492 | Args: | 533 | Args: |
| @@ -494,8 +535,6 @@ later is required to fix a server side protocol bug. | |||
| 494 | args: Command line args used to filter out projects. | 535 | args: Command line args used to filter out projects. |
| 495 | all_projects: List of all projects that should be fetched. | 536 | all_projects: List of all projects that should be fetched. |
| 496 | err_event: Whether an error was hit while processing. | 537 | err_event: Whether an error was hit while processing. |
| 497 | manifest_name: Manifest file to be reloaded. | ||
| 498 | load_local_manifests: Whether to load local manifests. | ||
| 499 | ssh_proxy: SSH manager for clients & masters. | 538 | ssh_proxy: SSH manager for clients & masters. |
| 500 | manifest: The manifest to use. | 539 | manifest: The manifest to use. |
| 501 | 540 | ||
| @@ -526,10 +565,12 @@ later is required to fix a server side protocol bug. | |||
| 526 | # Iteratively fetch missing and/or nested unregistered submodules | 565 | # Iteratively fetch missing and/or nested unregistered submodules |
| 527 | previously_missing_set = set() | 566 | previously_missing_set = set() |
| 528 | while True: | 567 | while True: |
| 529 | self._ReloadManifest(manifest_name, self.manifest, load_local_manifests) | 568 | self._ReloadManifest(None, manifest) |
| 530 | all_projects = self.GetProjects(args, | 569 | all_projects = self.GetProjects(args, |
| 531 | missing_ok=True, | 570 | missing_ok=True, |
| 532 | submodules_ok=opt.fetch_submodules) | 571 | submodules_ok=opt.fetch_submodules, |
| 572 | manifest=manifest, | ||
| 573 | all_manifests=not opt.this_manifest_only) | ||
| 533 | missing = [] | 574 | missing = [] |
| 534 | for project in all_projects: | 575 | for project in all_projects: |
| 535 | if project.gitdir not in fetched: | 576 | if project.gitdir not in fetched: |
| @@ -624,7 +665,7 @@ later is required to fix a server side protocol bug. | |||
| 624 | for project in projects: | 665 | for project in projects: |
| 625 | # Make sure pruning never kicks in with shared projects. | 666 | # Make sure pruning never kicks in with shared projects. |
| 626 | if (not project.use_git_worktrees and | 667 | if (not project.use_git_worktrees and |
| 627 | len(project.manifest.GetProjectsWithName(project.name)) > 1): | 668 | len(project.manifest.GetProjectsWithName(project.name, all_manifests=True)) > 1): |
| 628 | if not opt.quiet: | 669 | if not opt.quiet: |
| 629 | print('\r%s: Shared project %s found, disabling pruning.' % | 670 | print('\r%s: Shared project %s found, disabling pruning.' % |
| 630 | (project.relpath, project.name)) | 671 | (project.relpath, project.name)) |
| @@ -698,7 +739,7 @@ later is required to fix a server side protocol bug. | |||
| 698 | t.join() | 739 | t.join() |
| 699 | pm.end() | 740 | pm.end() |
| 700 | 741 | ||
| 701 | def _ReloadManifest(self, manifest_name, manifest, load_local_manifests=True): | 742 | def _ReloadManifest(self, manifest_name, manifest): |
| 702 | """Reload the manfiest from the file specified by the |manifest_name|. | 743 | """Reload the manfiest from the file specified by the |manifest_name|. |
| 703 | 744 | ||
| 704 | It unloads the manifest if |manifest_name| is None. | 745 | It unloads the manifest if |manifest_name| is None. |
| @@ -706,17 +747,29 @@ later is required to fix a server side protocol bug. | |||
| 706 | Args: | 747 | Args: |
| 707 | manifest_name: Manifest file to be reloaded. | 748 | manifest_name: Manifest file to be reloaded. |
| 708 | manifest: The manifest to use. | 749 | manifest: The manifest to use. |
| 709 | load_local_manifests: Whether to load local manifests. | ||
| 710 | """ | 750 | """ |
| 711 | if manifest_name: | 751 | if manifest_name: |
| 712 | # Override calls Unload already | 752 | # Override calls Unload already |
| 713 | manifest.Override(manifest_name, load_local_manifests=load_local_manifests) | 753 | manifest.Override(manifest_name) |
| 714 | else: | 754 | else: |
| 715 | manifest.Unload() | 755 | manifest.Unload() |
| 716 | 756 | ||
| 717 | def UpdateProjectList(self, opt, manifest): | 757 | def UpdateProjectList(self, opt, manifest): |
| 758 | """Update the cached projects list for |manifest| | ||
| 759 | |||
| 760 | In a multi-manifest checkout, each manifest has its own project.list. | ||
| 761 | |||
| 762 | Args: | ||
| 763 | opt: Program options returned from optparse. See _Options(). | ||
| 764 | manifest: The manifest to use. | ||
| 765 | |||
| 766 | Returns: | ||
| 767 | 0: success | ||
| 768 | 1: failure | ||
| 769 | """ | ||
| 718 | new_project_paths = [] | 770 | new_project_paths = [] |
| 719 | for project in self.GetProjects(None, missing_ok=True): | 771 | for project in self.GetProjects(None, missing_ok=True, manifest=manifest, |
| 772 | all_manifests=False): | ||
| 720 | if project.relpath: | 773 | if project.relpath: |
| 721 | new_project_paths.append(project.relpath) | 774 | new_project_paths.append(project.relpath) |
| 722 | file_name = 'project.list' | 775 | file_name = 'project.list' |
| @@ -766,7 +819,8 @@ later is required to fix a server side protocol bug. | |||
| 766 | new_paths = {} | 819 | new_paths = {} |
| 767 | new_linkfile_paths = [] | 820 | new_linkfile_paths = [] |
| 768 | new_copyfile_paths = [] | 821 | new_copyfile_paths = [] |
| 769 | for project in self.GetProjects(None, missing_ok=True): | 822 | for project in self.GetProjects(None, missing_ok=True, |
| 823 | manifest=manifest, all_manifests=False): | ||
| 770 | new_linkfile_paths.extend(x.dest for x in project.linkfiles) | 824 | new_linkfile_paths.extend(x.dest for x in project.linkfiles) |
| 771 | new_copyfile_paths.extend(x.dest for x in project.copyfiles) | 825 | new_copyfile_paths.extend(x.dest for x in project.copyfiles) |
| 772 | 826 | ||
| @@ -897,8 +951,40 @@ later is required to fix a server side protocol bug. | |||
| 897 | 951 | ||
| 898 | return manifest_name | 952 | return manifest_name |
| 899 | 953 | ||
| 954 | def _UpdateAllManifestProjects(self, opt, mp, manifest_name): | ||
| 955 | """Fetch & update the local manifest project. | ||
| 956 | |||
| 957 | After syncing the manifest project, if the manifest has any sub manifests, | ||
| 958 | those are recursively processed. | ||
| 959 | |||
| 960 | Args: | ||
| 961 | opt: Program options returned from optparse. See _Options(). | ||
| 962 | mp: the manifestProject to query. | ||
| 963 | manifest_name: Manifest file to be reloaded. | ||
| 964 | """ | ||
| 965 | if not mp.standalone_manifest_url: | ||
| 966 | self._UpdateManifestProject(opt, mp, manifest_name) | ||
| 967 | |||
| 968 | if mp.manifest.submanifests: | ||
| 969 | for submanifest in mp.manifest.submanifests.values(): | ||
| 970 | child = submanifest.repo_client.manifest | ||
| 971 | child.manifestProject.SyncWithPossibleInit( | ||
| 972 | submanifest, | ||
| 973 | current_branch_only=self._GetCurrentBranchOnly(opt, child), | ||
| 974 | verbose=opt.verbose, | ||
| 975 | tags=opt.tags, | ||
| 976 | git_event_log=self.git_event_log, | ||
| 977 | ) | ||
| 978 | self._UpdateAllManifestProjects(opt, child.manifestProject, None) | ||
| 979 | |||
| 900 | def _UpdateManifestProject(self, opt, mp, manifest_name): | 980 | def _UpdateManifestProject(self, opt, mp, manifest_name): |
| 901 | """Fetch & update the local manifest project.""" | 981 | """Fetch & update the local manifest project. |
| 982 | |||
| 983 | Args: | ||
| 984 | opt: Program options returned from optparse. See _Options(). | ||
| 985 | mp: the manifestProject to query. | ||
| 986 | manifest_name: Manifest file to be reloaded. | ||
| 987 | """ | ||
| 902 | if not opt.local_only: | 988 | if not opt.local_only: |
| 903 | start = time.time() | 989 | start = time.time() |
| 904 | success = mp.Sync_NetworkHalf(quiet=opt.quiet, verbose=opt.verbose, | 990 | success = mp.Sync_NetworkHalf(quiet=opt.quiet, verbose=opt.verbose, |
| @@ -924,6 +1010,7 @@ later is required to fix a server side protocol bug. | |||
| 924 | if not clean: | 1010 | if not clean: |
| 925 | sys.exit(1) | 1011 | sys.exit(1) |
| 926 | self._ReloadManifest(manifest_name, mp.manifest) | 1012 | self._ReloadManifest(manifest_name, mp.manifest) |
| 1013 | |||
| 927 | if opt.jobs is None: | 1014 | if opt.jobs is None: |
| 928 | self.jobs = mp.manifest.default.sync_j | 1015 | self.jobs = mp.manifest.default.sync_j |
| 929 | 1016 | ||
| @@ -948,9 +1035,6 @@ later is required to fix a server side protocol bug. | |||
| 948 | if opt.prune is None: | 1035 | if opt.prune is None: |
| 949 | opt.prune = True | 1036 | opt.prune = True |
| 950 | 1037 | ||
| 951 | if self.outer_client.manifest.is_multimanifest and not opt.this_manifest_only and args: | ||
| 952 | self.OptionParser.error('partial syncs must use --this-manifest-only') | ||
| 953 | |||
| 954 | def Execute(self, opt, args): | 1038 | def Execute(self, opt, args): |
| 955 | if opt.jobs: | 1039 | if opt.jobs: |
| 956 | self.jobs = opt.jobs | 1040 | self.jobs = opt.jobs |
| @@ -959,7 +1043,7 @@ later is required to fix a server side protocol bug. | |||
| 959 | self.jobs = min(self.jobs, (soft_limit - 5) // 3) | 1043 | self.jobs = min(self.jobs, (soft_limit - 5) // 3) |
| 960 | 1044 | ||
| 961 | manifest = self.outer_manifest | 1045 | manifest = self.outer_manifest |
| 962 | if opt.this_manifest_only or not opt.outer_manifest: | 1046 | if not opt.outer_manifest: |
| 963 | manifest = self.manifest | 1047 | manifest = self.manifest |
| 964 | 1048 | ||
| 965 | if opt.manifest_name: | 1049 | if opt.manifest_name: |
| @@ -994,39 +1078,26 @@ later is required to fix a server side protocol bug. | |||
| 994 | 'receive updates; run `repo init --repo-rev=stable` to fix.', | 1078 | 'receive updates; run `repo init --repo-rev=stable` to fix.', |
| 995 | file=sys.stderr) | 1079 | file=sys.stderr) |
| 996 | 1080 | ||
| 997 | mp = manifest.manifestProject | 1081 | for m in self.ManifestList(opt): |
| 998 | is_standalone_manifest = bool(mp.standalone_manifest_url) | 1082 | mp = m.manifestProject |
| 999 | if not is_standalone_manifest: | 1083 | is_standalone_manifest = bool(mp.standalone_manifest_url) |
| 1000 | mp.PreSync() | 1084 | if not is_standalone_manifest: |
| 1085 | mp.PreSync() | ||
| 1001 | 1086 | ||
| 1002 | if opt.repo_upgraded: | 1087 | if opt.repo_upgraded: |
| 1003 | _PostRepoUpgrade(manifest, quiet=opt.quiet) | 1088 | _PostRepoUpgrade(m, quiet=opt.quiet) |
| 1004 | 1089 | ||
| 1005 | if not opt.mp_update: | 1090 | if opt.mp_update: |
| 1091 | self._UpdateAllManifestProjects(opt, mp, manifest_name) | ||
| 1092 | else: | ||
| 1006 | print('Skipping update of local manifest project.') | 1093 | print('Skipping update of local manifest project.') |
| 1007 | elif not is_standalone_manifest: | ||
| 1008 | self._UpdateManifestProject(opt, mp, manifest_name) | ||
| 1009 | 1094 | ||
| 1010 | load_local_manifests = not manifest.HasLocalManifests | 1095 | superproject_logging_data = {} |
| 1011 | use_superproject = git_superproject.UseSuperproject(opt.use_superproject, manifest) | 1096 | self._UpdateProjectsRevisionId(opt, args, superproject_logging_data, |
| 1012 | if use_superproject and (manifest.IsMirror or manifest.IsArchive): | 1097 | manifest) |
| 1013 | # Don't use superproject, because we have no working tree. | ||
| 1014 | use_superproject = False | ||
| 1015 | if opt.use_superproject is not None: | ||
| 1016 | print('Defaulting to no-use-superproject because there is no working tree.') | ||
| 1017 | superproject_logging_data = { | ||
| 1018 | 'superproject': use_superproject, | ||
| 1019 | 'haslocalmanifests': bool(manifest.HasLocalManifests), | ||
| 1020 | 'hassuperprojecttag': bool(manifest.superproject), | ||
| 1021 | } | ||
| 1022 | if use_superproject: | ||
| 1023 | manifest_name = self._UpdateProjectsRevisionId( | ||
| 1024 | opt, args, load_local_manifests, superproject_logging_data, | ||
| 1025 | manifest) or opt.manifest_name | ||
| 1026 | 1098 | ||
| 1027 | if self.gitc_manifest: | 1099 | if self.gitc_manifest: |
| 1028 | gitc_manifest_projects = self.GetProjects(args, | 1100 | gitc_manifest_projects = self.GetProjects(args, missing_ok=True) |
| 1029 | missing_ok=True) | ||
| 1030 | gitc_projects = [] | 1101 | gitc_projects = [] |
| 1031 | opened_projects = [] | 1102 | opened_projects = [] |
| 1032 | for project in gitc_manifest_projects: | 1103 | for project in gitc_manifest_projects: |
| @@ -1059,9 +1130,12 @@ later is required to fix a server side protocol bug. | |||
| 1059 | for path in opened_projects] | 1130 | for path in opened_projects] |
| 1060 | if not args: | 1131 | if not args: |
| 1061 | return | 1132 | return |
| 1133 | |||
| 1062 | all_projects = self.GetProjects(args, | 1134 | all_projects = self.GetProjects(args, |
| 1063 | missing_ok=True, | 1135 | missing_ok=True, |
| 1064 | submodules_ok=opt.fetch_submodules) | 1136 | submodules_ok=opt.fetch_submodules, |
| 1137 | manifest=manifest, | ||
| 1138 | all_manifests=not opt.this_manifest_only) | ||
| 1065 | 1139 | ||
| 1066 | err_network_sync = False | 1140 | err_network_sync = False |
| 1067 | err_update_projects = False | 1141 | err_update_projects = False |
| @@ -1073,7 +1147,6 @@ later is required to fix a server side protocol bug. | |||
| 1073 | # Initialize the socket dir once in the parent. | 1147 | # Initialize the socket dir once in the parent. |
| 1074 | ssh_proxy.sock() | 1148 | ssh_proxy.sock() |
| 1075 | all_projects = self._FetchMain(opt, args, all_projects, err_event, | 1149 | all_projects = self._FetchMain(opt, args, all_projects, err_event, |
| 1076 | manifest_name, load_local_manifests, | ||
| 1077 | ssh_proxy, manifest) | 1150 | ssh_proxy, manifest) |
| 1078 | 1151 | ||
| 1079 | if opt.network_only: | 1152 | if opt.network_only: |
| @@ -1090,23 +1163,24 @@ later is required to fix a server side protocol bug. | |||
| 1090 | file=sys.stderr) | 1163 | file=sys.stderr) |
| 1091 | sys.exit(1) | 1164 | sys.exit(1) |
| 1092 | 1165 | ||
| 1093 | if manifest.IsMirror or manifest.IsArchive: | 1166 | for m in self.ManifestList(opt): |
| 1094 | # bail out now, we have no working tree | 1167 | if m.IsMirror or m.IsArchive: |
| 1095 | return | 1168 | # bail out now, we have no working tree |
| 1169 | continue | ||
| 1096 | 1170 | ||
| 1097 | if self.UpdateProjectList(opt, manifest): | 1171 | if self.UpdateProjectList(opt, m): |
| 1098 | err_event.set() | 1172 | err_event.set() |
| 1099 | err_update_projects = True | 1173 | err_update_projects = True |
| 1100 | if opt.fail_fast: | 1174 | if opt.fail_fast: |
| 1101 | print('\nerror: Local checkouts *not* updated.', file=sys.stderr) | 1175 | print('\nerror: Local checkouts *not* updated.', file=sys.stderr) |
| 1102 | sys.exit(1) | 1176 | sys.exit(1) |
| 1103 | 1177 | ||
| 1104 | err_update_linkfiles = not self.UpdateCopyLinkfileList(manifest) | 1178 | err_update_linkfiles = not self.UpdateCopyLinkfileList(m) |
| 1105 | if err_update_linkfiles: | 1179 | if err_update_linkfiles: |
| 1106 | err_event.set() | 1180 | err_event.set() |
| 1107 | if opt.fail_fast: | 1181 | if opt.fail_fast: |
| 1108 | print('\nerror: Local update copyfile or linkfile failed.', file=sys.stderr) | 1182 | print('\nerror: Local update copyfile or linkfile failed.', file=sys.stderr) |
| 1109 | sys.exit(1) | 1183 | sys.exit(1) |
| 1110 | 1184 | ||
| 1111 | err_results = [] | 1185 | err_results = [] |
| 1112 | # NB: We don't exit here because this is the last step. | 1186 | # NB: We don't exit here because this is the last step. |
| @@ -1114,10 +1188,14 @@ later is required to fix a server side protocol bug. | |||
| 1114 | if err_checkout: | 1188 | if err_checkout: |
| 1115 | err_event.set() | 1189 | err_event.set() |
| 1116 | 1190 | ||
| 1117 | # If there's a notice that's supposed to print at the end of the sync, print | 1191 | printed_notices = set() |
| 1118 | # it now... | 1192 | # If there's a notice that's supposed to print at the end of the sync, |
| 1119 | if manifest.notice: | 1193 | # print it now... But avoid printing duplicate messages, and preserve |
| 1120 | print(manifest.notice) | 1194 | # order. |
| 1195 | for m in sorted(self.ManifestList(opt), key=lambda x: x.path_prefix): | ||
| 1196 | if m.notice and m.notice not in printed_notices: | ||
| 1197 | print(m.notice) | ||
| 1198 | printed_notices.add(m.notice) | ||
| 1121 | 1199 | ||
| 1122 | # If we saw an error, exit with code 1 so that other scripts can check. | 1200 | # If we saw an error, exit with code 1 so that other scripts can check. |
| 1123 | if err_event.is_set(): | 1201 | if err_event.is_set(): |
