init: add multi-manifest support

This moves more of the manifest project handling into ManifestProject.

Change-Id: Iecdafbec18cccdfd8e625753c3bd1bcddf2b227f
Reviewed-on: https://gerrit-review.googlesource.com/c/git-repo/+/334520
Tested-by: LaMont Jones <lamontjones@google.com>
Reviewed-by: Mike Frysinger <vapier@google.com>
This commit is contained in:
LaMont Jones 2022-04-05 21:21:56 +00:00
parent d82be3e672
commit 409407a731
2 changed files with 100 additions and 41 deletions

View File

@ -34,7 +34,8 @@ from git_config import GitConfig, IsId, GetSchemeFromUrl, GetUrlCookieFile, \
ID_RE ID_RE
from error import GitError, UploadError, DownloadError from error import GitError, UploadError, DownloadError
from error import ManifestInvalidRevisionError, ManifestInvalidPathError from error import ManifestInvalidRevisionError, ManifestInvalidPathError
from error import NoManifestException from error import NoManifestException, ManifestParseError
import git_superproject
import platform_utils import platform_utils
import progress import progress
from repo_trace import IsTrace, Trace from repo_trace import IsTrace, Trace
@ -3443,7 +3444,8 @@ class ManifestProject(MetaProject):
partial_clone=None, depth=None, clone_filter='blob:none', partial_clone=None, depth=None, clone_filter='blob:none',
partial_clone_exclude=None, clone_bundle=None, git_lfs=None, partial_clone_exclude=None, clone_bundle=None, git_lfs=None,
use_superproject=None, verbose=False, current_branch_only=False, use_superproject=None, verbose=False, current_branch_only=False,
platform='', tags=''): platform='', tags='', manifest_name='default.xml',
this_manifest_only=False, outer_manifest=True):
"""Sync the manifest and all submanifests. """Sync the manifest and all submanifests.
Args: Args:
@ -3477,12 +3479,45 @@ class ManifestProject(MetaProject):
platform: a string, restrict the checkout to projects with the specified platform: a string, restrict the checkout to projects with the specified
platform group. platform group.
tags: a boolean, whether to fetch tags., tags: a boolean, whether to fetch tags.,
manifest_name: a string, the name of the manifest file to use.
this_manifest_only: a boolean, whether to only operate on the current sub
manifest.
outer_manifest: a boolean, whether to start at the outermost manifest.
Returns: Returns:
a boolean, whether the sync was successful. a boolean, whether the sync was successful.
""" """
assert _kwargs_only == (), 'Sync only accepts keyword arguments.' assert _kwargs_only == (), 'Sync only accepts keyword arguments.'
if outer_manifest and self.manifest.is_submanifest:
# In a multi-manifest checkout, use the outer manifest unless we are told
# not to.
return self.client.outer_manifest.manifestProject.Sync(
manifest_url=manifest_url,
manifest_branch=manifest_branch,
standalone_manifest=standalone_manifest,
groups=groups,
platform=platform,
mirror=mirror,
dissociate=dissociate,
reference=reference,
worktree=worktree,
submodules=submodules,
archive=archive,
partial_clone=partial_clone,
clone_filter=clone_filter,
partial_clone_exclude=partial_clone_exclude,
clone_bundle=clone_bundle,
git_lfs=git_lfs,
use_superproject=use_superproject,
verbose=verbose,
current_branch_only=current_branch_only,
tags=tags,
depth=depth,
manifest_name=manifest_name,
this_manifest_only=this_manifest_only,
outer_manifest=False)
# If repo has already been initialized, we take -u with the absence of # If repo has already been initialized, we take -u with the absence of
# --standalone-manifest to mean "transition to a standard repo set up", # --standalone-manifest to mean "transition to a standard repo set up",
# which necessitates starting fresh. # which necessitates starting fresh.
@ -3508,7 +3543,7 @@ class ManifestProject(MetaProject):
print('fatal: manifest url is required.', file=sys.stderr) print('fatal: manifest url is required.', file=sys.stderr)
return False return False
if not quiet: if verbose:
print('Downloading manifest from %s' % print('Downloading manifest from %s' %
(GitConfig.ForUser().UrlInsteadOf(manifest_url),), (GitConfig.ForUser().UrlInsteadOf(manifest_url),),
file=sys.stderr) file=sys.stderr)
@ -3700,6 +3735,65 @@ class ManifestProject(MetaProject):
print('fatal: cannot create default in manifest', file=sys.stderr) print('fatal: cannot create default in manifest', file=sys.stderr)
return False return False
if not manifest_name:
print('fatal: manifest name (-m) is required.', file=sys.stderr)
return False
try:
self.manifest.Link(manifest_name)
except ManifestParseError as e:
print("fatal: manifest '%s' not available" % manifest_name,
file=sys.stderr)
print('fatal: %s' % str(e), file=sys.stderr)
return False
# Lastly, clone the superproject.
superproject = git_superproject.Superproject(self.manifest,
self.repodir,
self.git_event_log,
quiet=not verbose)
sync_result = superproject.Sync()
if not sync_result.success:
print('warning: git update of superproject failed, repo sync will not '
'use superproject to fetch source; while this error is not fatal, '
'and you can continue to run repo sync, please run repo init with '
'the --no-use-superproject option to stop seeing this warning',
file=sys.stderr)
if sync_result.fatal and use_superproject is not None:
return False
if this_manifest_only:
return True
for submanifest in self.manifest.submanifests.values():
spec = submanifest.ToSubmanifestSpec(root=self.manifest.outer_client)
submanifest.repo_client.manifestProject.Sync(
manifest_url=spec.manifestUrl,
manifest_branch=spec.revision,
standalone_manifest=standalone_manifest,
groups=self.manifest_groups,
platform=platform,
mirror=mirror,
dissociate=dissociate,
reference=reference,
worktree=worktree,
submodules=submodules,
archive=archive,
partial_clone=partial_clone,
clone_filter=clone_filter,
partial_clone_exclude=partial_clone_exclude,
clone_bundle=clone_bundle,
git_lfs=git_lfs,
use_superproject=use_superproject,
verbose=verbose,
current_branch_only=current_branch_only,
tags=tags,
depth=depth,
manifest_name=spec.manifestName,
this_manifest_only=False,
outer_manifest=False,
)
return True return True
def _ConfigureDepth(self, depth): def _ConfigureDepth(self, depth):

View File

@ -32,7 +32,7 @@ from wrapper import Wrapper
class Init(InteractiveCommand, MirrorSafeCommand): class Init(InteractiveCommand, MirrorSafeCommand):
COMMON = True COMMON = True
MULTI_MANIFEST_SUPPORT = False MULTI_MANIFEST_SUPPORT = True
helpSummary = "Initialize a repo client checkout in the current directory" helpSummary = "Initialize a repo client checkout in the current directory"
helpUsage = """ helpUsage = """
%prog [options] [manifest url] %prog [options] [manifest url]
@ -107,26 +107,6 @@ to update the working directory files.
return {'REPO_MANIFEST_URL': 'manifest_url', return {'REPO_MANIFEST_URL': 'manifest_url',
'REPO_MIRROR_LOCATION': 'reference'} 'REPO_MIRROR_LOCATION': 'reference'}
def _CloneSuperproject(self, opt):
"""Clone the superproject based on the superproject's url and branch.
Args:
opt: Program options returned from optparse. See _Options().
"""
superproject = git_superproject.Superproject(self.manifest,
self.repodir,
self.git_event_log,
quiet=opt.quiet)
sync_result = superproject.Sync()
if not sync_result.success:
print('warning: git update of superproject failed, repo sync will not '
'use superproject to fetch source; while this error is not fatal, '
'and you can continue to run repo sync, please run repo init with '
'the --no-use-superproject option to stop seeing this warning',
file=sys.stderr)
if sync_result.fatal and opt.use_superproject is not None:
sys.exit(1)
def _SyncManifest(self, opt): def _SyncManifest(self, opt):
"""Call manifestProject.Sync with arguments from opt. """Call manifestProject.Sync with arguments from opt.
@ -154,19 +134,8 @@ to update the working directory files.
verbose=opt.verbose, verbose=opt.verbose,
current_branch_only=opt.current_branch_only, current_branch_only=opt.current_branch_only,
tags=opt.tags, tags=opt.tags,
depth=opt.depth): depth=opt.depth,
sys.exit(1) manifest_name=opt.manifest_name):
def _LinkManifest(self, name):
if not name:
print('fatal: manifest name (-m) is required.', file=sys.stderr)
sys.exit(1)
try:
self.manifest.Link(name)
except ManifestParseError as e:
print("fatal: manifest '%s' not available" % name, file=sys.stderr)
print('fatal: %s' % str(e), file=sys.stderr)
sys.exit(1) sys.exit(1)
def _Prompt(self, prompt, value): def _Prompt(self, prompt, value):
@ -343,10 +312,6 @@ to update the working directory files.
git_require((2, 15, 0), fail=True, msg='git gc worktree corruption') git_require((2, 15, 0), fail=True, msg='git gc worktree corruption')
self._SyncManifest(opt) self._SyncManifest(opt)
self._LinkManifest(opt.manifest_name)
if self.manifest.manifestProject.use_superproject:
self._CloneSuperproject(opt)
if os.isatty(0) and os.isatty(1) and not self.manifest.IsMirror: if os.isatty(0) and os.isatty(1) and not self.manifest.IsMirror:
if opt.config_name or self._ShouldConfigureUser(opt): if opt.config_name or self._ShouldConfigureUser(opt):