diff options
author | LaMont Jones <lamontjones@google.com> | 2022-03-29 23:01:18 +0000 |
---|---|---|
committer | LaMont Jones <lamontjones@google.com> | 2022-04-01 15:48:04 +0000 |
commit | 9b03f15e8e870866b26699f696af1884100f51b5 (patch) | |
tree | 20a464d35d2c022ab5b0d05de109b4477fd7e1c5 /project.py | |
parent | 9b72cf2ba5c00bee726aa4bddbb84be554294284 (diff) | |
download | git-repo-9b03f15e8e870866b26699f696af1884100f51b5.tar.gz |
project: add ManifestProject.Sync()
Move the logic to sync a ManifestProject out of subcmds/init.py
Change-Id: Ia9d00f3da1dc3c5dada84c4d19cf9802c2346cb0
Reviewed-on: https://gerrit-review.googlesource.com/c/git-repo/+/334140
Tested-by: LaMont Jones <lamontjones@google.com>
Reviewed-by: Mike Frysinger <vapier@google.com>
Diffstat (limited to 'project.py')
-rw-r--r-- | project.py | 289 |
1 files changed, 289 insertions, 0 deletions
@@ -3357,3 +3357,292 @@ class ManifestProject(MetaProject): | |||
3357 | ['update-ref', '-d', 'refs/heads/default'], | 3357 | ['update-ref', '-d', 'refs/heads/default'], |
3358 | capture_stdout=True, | 3358 | capture_stdout=True, |
3359 | capture_stderr=True).Wait() == 0 | 3359 | capture_stderr=True).Wait() == 0 |
3360 | |||
3361 | @property | ||
3362 | def _platform_name(self): | ||
3363 | """Return the name of the platform.""" | ||
3364 | return platform.system().lower() | ||
3365 | |||
3366 | def Sync(self, _kwargs_only=(), manifest_url='', manifest_branch=None, | ||
3367 | standalone_manifest=False, groups='', platform='', mirror=False, | ||
3368 | dissociate=False, reference='', worktree=False, submodules=False, | ||
3369 | archive=False, partial_clone=None, clone_filter='blob:none', | ||
3370 | partial_clone_exclude=None, clone_bundle=None, git_lfs=None, | ||
3371 | use_superproject=None, verbose=False, current_branch_only=False, | ||
3372 | tags='', depth=None): | ||
3373 | """Sync the manifest and all submanifests. | ||
3374 | |||
3375 | Args: | ||
3376 | manifest_url: a string, the URL of the manifest project. | ||
3377 | manifest_branch: a string, the manifest branch to use. | ||
3378 | standalone_manifest: a boolean, whether to store the manifest as a static | ||
3379 | file. | ||
3380 | groups: a string, restricts the checkout to projects with the specified | ||
3381 | groups. | ||
3382 | platform: a string, restrict the checkout to projects with the specified | ||
3383 | platform group. | ||
3384 | mirror: a boolean, whether to create a mirror of the remote repository. | ||
3385 | reference: a string, location of a repo instance to use as a reference. | ||
3386 | dissociate: a boolean, whether to dissociate from reference mirrors after | ||
3387 | clone. | ||
3388 | worktree: a boolean, whether to use git-worktree to manage projects. | ||
3389 | submodules: a boolean, whether sync submodules associated with the | ||
3390 | manifest project. | ||
3391 | archive: a boolean, whether to checkout each project as an archive. See | ||
3392 | git-archive. | ||
3393 | partial_clone: a boolean, whether to perform a partial clone. | ||
3394 | clone_filter: a string, filter to use with partial_clone. | ||
3395 | partial_clone_exclude : a string, comma-delimeted list of project namess | ||
3396 | to exclude from partial clone. | ||
3397 | clone_bundle: a boolean, whether to enable /clone.bundle on HTTP/HTTPS. | ||
3398 | git_lfs: a boolean, whether to enable git LFS support. | ||
3399 | use_superproject: a boolean, whether to use the manifest superproject to | ||
3400 | sync projects. | ||
3401 | verbose: a boolean, whether to show all output, rather than only errors. | ||
3402 | current_branch_only: a boolean, whether to only fetch the current manifest | ||
3403 | branch from the server. | ||
3404 | tags: a boolean, whether to fetch tags., | ||
3405 | depth: an int, how deep of a shallow clone to create. | ||
3406 | |||
3407 | Returns: | ||
3408 | a boolean, whether the sync was successful. | ||
3409 | """ | ||
3410 | assert _kwargs_only == (), 'Sync only accepts keyword arguments.' | ||
3411 | |||
3412 | # If repo has already been initialized, we take -u with the absence of | ||
3413 | # --standalone-manifest to mean "transition to a standard repo set up", | ||
3414 | # which necessitates starting fresh. | ||
3415 | # If --standalone-manifest is set, we always tear everything down and start | ||
3416 | # anew. | ||
3417 | if self.Exists: | ||
3418 | was_standalone_manifest = self.config.GetString('manifest.standalone') | ||
3419 | if was_standalone_manifest and not manifest_url: | ||
3420 | print('fatal: repo was initialized with a standlone manifest, ' | ||
3421 | 'cannot be re-initialized without --manifest-url/-u') | ||
3422 | return False | ||
3423 | |||
3424 | if standalone_manifest or (was_standalone_manifest and manifest_url): | ||
3425 | self.config.ClearCache() | ||
3426 | if self.gitdir and os.path.exists(self.gitdir): | ||
3427 | platform_utils.rmtree(self.gitdir) | ||
3428 | if self.worktree and os.path.exists(self.worktree): | ||
3429 | platform_utils.rmtree(self.worktree) | ||
3430 | |||
3431 | is_new = not self.Exists | ||
3432 | if is_new: | ||
3433 | if not manifest_url: | ||
3434 | print('fatal: manifest url is required.', file=sys.stderr) | ||
3435 | return False | ||
3436 | |||
3437 | if not quiet: | ||
3438 | print('Downloading manifest from %s' % | ||
3439 | (GitConfig.ForUser().UrlInsteadOf(manifest_url),), | ||
3440 | file=sys.stderr) | ||
3441 | |||
3442 | # The manifest project object doesn't keep track of the path on the | ||
3443 | # server where this git is located, so let's save that here. | ||
3444 | mirrored_manifest_git = None | ||
3445 | if reference: | ||
3446 | manifest_git_path = urllib.parse.urlparse(manifest_url).path[1:] | ||
3447 | mirrored_manifest_git = os.path.join(reference, manifest_git_path) | ||
3448 | if not mirrored_manifest_git.endswith(".git"): | ||
3449 | mirrored_manifest_git += ".git" | ||
3450 | if not os.path.exists(mirrored_manifest_git): | ||
3451 | mirrored_manifest_git = os.path.join(reference, | ||
3452 | '.repo/manifests.git') | ||
3453 | |||
3454 | self._InitGitDir(mirror_git=mirrored_manifest_git) | ||
3455 | |||
3456 | # If standalone_manifest is set, mark the project as "standalone" -- we'll | ||
3457 | # still do much of the manifests.git set up, but will avoid actual syncs to | ||
3458 | # a remote. | ||
3459 | if standalone_manifest: | ||
3460 | self.config.SetString('manifest.standalone', manifest_url) | ||
3461 | elif not manifest_url and not manifest_branch: | ||
3462 | # If -u is set and --standalone-manifest is not, then we're not in | ||
3463 | # standalone mode. Otherwise, use config to infer what we were in the last | ||
3464 | # init. | ||
3465 | standalone_manifest = bool(self.config.GetString('manifest.standalone')) | ||
3466 | if not standalone_manifest: | ||
3467 | self.config.SetString('manifest.standalone', None) | ||
3468 | |||
3469 | self._ConfigureDepth(depth) | ||
3470 | |||
3471 | # Set the remote URL before the remote branch as we might need it below. | ||
3472 | if manifest_url: | ||
3473 | r = self.GetRemote(self.remote.name) | ||
3474 | r.url = manifest_url | ||
3475 | r.ResetFetch() | ||
3476 | r.Save() | ||
3477 | |||
3478 | if not standalone_manifest: | ||
3479 | if manifest_branch: | ||
3480 | if manifest_branch == 'HEAD': | ||
3481 | manifest_branch = self.ResolveRemoteHead() | ||
3482 | if manifest_branch is None: | ||
3483 | print('fatal: unable to resolve HEAD', file=sys.stderr) | ||
3484 | return False | ||
3485 | self.revisionExpr = manifest_branch | ||
3486 | else: | ||
3487 | if is_new: | ||
3488 | default_branch = self.ResolveRemoteHead() | ||
3489 | if default_branch is None: | ||
3490 | # If the remote doesn't have HEAD configured, default to master. | ||
3491 | default_branch = 'refs/heads/master' | ||
3492 | self.revisionExpr = default_branch | ||
3493 | else: | ||
3494 | self.PreSync() | ||
3495 | |||
3496 | groups = re.split(r'[,\s]+', groups) | ||
3497 | all_platforms = ['linux', 'darwin', 'windows'] | ||
3498 | platformize = lambda x: 'platform-' + x | ||
3499 | if platform == 'auto': | ||
3500 | if (not mirror and not self.config.GetString('repo.mirror') == 'true'): | ||
3501 | groups.append(platformize(self._platform_name)) | ||
3502 | elif platform == 'all': | ||
3503 | groups.extend(map(platformize, all_platforms)) | ||
3504 | elif platform in all_platforms: | ||
3505 | groups.append(platformize(platform)) | ||
3506 | elif platform != 'none': | ||
3507 | print('fatal: invalid platform flag', file=sys.stderr) | ||
3508 | return False | ||
3509 | |||
3510 | groups = [x for x in groups if x] | ||
3511 | groupstr = ','.join(groups) | ||
3512 | if platform == 'auto' and groupstr == self.manifest.GetDefaultGroupsStr(): | ||
3513 | groupstr = None | ||
3514 | self.config.SetString('manifest.groups', groupstr) | ||
3515 | |||
3516 | if reference: | ||
3517 | self.config.SetString('repo.reference', reference) | ||
3518 | |||
3519 | if dissociate: | ||
3520 | self.config.SetBoolean('repo.dissociate', dissociate) | ||
3521 | |||
3522 | if worktree: | ||
3523 | if mirror: | ||
3524 | print('fatal: --mirror and --worktree are incompatible', | ||
3525 | file=sys.stderr) | ||
3526 | return False | ||
3527 | if submodules: | ||
3528 | print('fatal: --submodules and --worktree are incompatible', | ||
3529 | file=sys.stderr) | ||
3530 | return False | ||
3531 | self.config.SetBoolean('repo.worktree', worktree) | ||
3532 | if is_new: | ||
3533 | self.use_git_worktrees = True | ||
3534 | print('warning: --worktree is experimental!', file=sys.stderr) | ||
3535 | |||
3536 | if archive: | ||
3537 | if is_new: | ||
3538 | self.config.SetBoolean('repo.archive', archive) | ||
3539 | else: | ||
3540 | print('fatal: --archive is only supported when initializing a new ' | ||
3541 | 'workspace.', file=sys.stderr) | ||
3542 | print('Either delete the .repo folder in this workspace, or initialize ' | ||
3543 | 'in another location.', file=sys.stderr) | ||
3544 | return False | ||
3545 | |||
3546 | if mirror: | ||
3547 | if is_new: | ||
3548 | self.config.SetBoolean('repo.mirror', mirror) | ||
3549 | else: | ||
3550 | print('fatal: --mirror is only supported when initializing a new ' | ||
3551 | 'workspace.', file=sys.stderr) | ||
3552 | print('Either delete the .repo folder in this workspace, or initialize ' | ||
3553 | 'in another location.', file=sys.stderr) | ||
3554 | return False | ||
3555 | |||
3556 | if partial_clone is not None: | ||
3557 | if mirror: | ||
3558 | print('fatal: --mirror and --partial-clone are mutually exclusive', | ||
3559 | file=sys.stderr) | ||
3560 | return False | ||
3561 | self.config.SetBoolean('repo.partialclone', partial_clone) | ||
3562 | if clone_filter: | ||
3563 | self.config.SetString('repo.clonefilter', clone_filter) | ||
3564 | elif self.config.GetBoolean('repo.partialclone'): | ||
3565 | clone_filter = self.config.GetString('repo.clonefilter') | ||
3566 | else: | ||
3567 | clone_filter = None | ||
3568 | |||
3569 | if partial_clone_exclude is not None: | ||
3570 | self.config.SetString('repo.partialcloneexclude', partial_clone_exclude) | ||
3571 | |||
3572 | if clone_bundle is None: | ||
3573 | clone_bundle = False if partial_clone else True | ||
3574 | else: | ||
3575 | self.config.SetBoolean('repo.clonebundle', clone_bundle) | ||
3576 | |||
3577 | if submodules: | ||
3578 | self.config.SetBoolean('repo.submodules', submodules) | ||
3579 | |||
3580 | if git_lfs is not None: | ||
3581 | if git_lfs: | ||
3582 | git_require((2, 17, 0), fail=True, msg='Git LFS support') | ||
3583 | |||
3584 | self.config.SetBoolean('repo.git-lfs', git_lfs) | ||
3585 | if not is_new: | ||
3586 | print('warning: Changing --git-lfs settings will only affect new project checkouts.\n' | ||
3587 | ' Existing projects will require manual updates.\n', file=sys.stderr) | ||
3588 | |||
3589 | if use_superproject is not None: | ||
3590 | self.config.SetBoolean('repo.superproject', use_superproject) | ||
3591 | |||
3592 | if standalone_manifest: | ||
3593 | if is_new: | ||
3594 | manifest_name = 'default.xml' | ||
3595 | manifest_data = fetch.fetch_file(manifest_url, verbose=verbose) | ||
3596 | dest = os.path.join(self.worktree, manifest_name) | ||
3597 | os.makedirs(os.path.dirname(dest), exist_ok=True) | ||
3598 | with open(dest, 'wb') as f: | ||
3599 | f.write(manifest_data) | ||
3600 | return | ||
3601 | |||
3602 | if not self.Sync_NetworkHalf(is_new=is_new, quiet=not verbose, verbose=verbose, | ||
3603 | clone_bundle=clone_bundle, | ||
3604 | current_branch_only=current_branch_only, | ||
3605 | tags=tags, submodules=submodules, | ||
3606 | clone_filter=clone_filter, | ||
3607 | partial_clone_exclude=self.manifest.PartialCloneExclude): | ||
3608 | r = self.GetRemote(self.remote.name) | ||
3609 | print('fatal: cannot obtain manifest %s' % r.url, file=sys.stderr) | ||
3610 | |||
3611 | # Better delete the manifest git dir if we created it; otherwise next | ||
3612 | # time (when user fixes problems) we won't go through the "is_new" logic. | ||
3613 | if is_new: | ||
3614 | platform_utils.rmtree(self.gitdir) | ||
3615 | return False | ||
3616 | |||
3617 | if manifest_branch: | ||
3618 | self.MetaBranchSwitch(submodules=submodules) | ||
3619 | |||
3620 | syncbuf = SyncBuffer(self.config) | ||
3621 | self.Sync_LocalHalf(syncbuf, submodules=submodules) | ||
3622 | syncbuf.Finish() | ||
3623 | |||
3624 | if is_new or self.CurrentBranch is None: | ||
3625 | if not self.StartBranch('default'): | ||
3626 | print('fatal: cannot create default in manifest', file=sys.stderr) | ||
3627 | return False | ||
3628 | |||
3629 | return True | ||
3630 | |||
3631 | def _ConfigureDepth(self, depth): | ||
3632 | """Configure the depth we'll sync down. | ||
3633 | |||
3634 | Args: | ||
3635 | depth: an int, how deep of a partial clone to create. | ||
3636 | """ | ||
3637 | # Opt.depth will be non-None if user actually passed --depth to repo init. | ||
3638 | if depth is not None: | ||
3639 | if depth > 0: | ||
3640 | # Positive values will set the depth. | ||
3641 | depth = str(depth) | ||
3642 | else: | ||
3643 | # Negative numbers will clear the depth; passing None to SetString | ||
3644 | # will do that. | ||
3645 | depth = None | ||
3646 | |||
3647 | # We store the depth in the main manifest project. | ||
3648 | self.config.SetString('repo.depth', depth) | ||