summaryrefslogtreecommitdiffstats
path: root/project.py
diff options
context:
space:
mode:
Diffstat (limited to 'project.py')
-rw-r--r--project.py289
1 files changed, 289 insertions, 0 deletions
diff --git a/project.py b/project.py
index ed58c956..43cac88c 100644
--- a/project.py
+++ b/project.py
@@ -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)