From c474c9cba1a8fbe09c219cc588d9ed334d31cd1e Mon Sep 17 00:00:00 2001 From: Jack Neus Date: Mon, 26 Jul 2021 23:08:54 +0000 Subject: repo: Add support for standalone manifests Added --standalone_manifest to repo tool. If set, the manifest is downloaded directly from the appropriate source (currently, we only support GS) and used instead of creating a manifest git checkout. The manifests.git repo is still created to keep track of various config but is marked as being for a standalone manifest so that the repo tool doesn't try to run networked git commands in it. BUG=b:192664812 TEST=existing tests (no coverage), manual runs Change-Id: I84378cbc7f8e515eabeccdde9665efc8cd2a9d21 Reviewed-on: https://gerrit-review.googlesource.com/c/git-repo/+/312942 Tested-by: Jack Neus Reviewed-by: Mike Frysinger --- subcmds/init.py | 83 ++++++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 68 insertions(+), 15 deletions(-) (limited to 'subcmds/init.py') diff --git a/subcmds/init.py b/subcmds/init.py index 5671fc24..9c6b2ad9 100644 --- a/subcmds/init.py +++ b/subcmds/init.py @@ -15,6 +15,7 @@ import os import platform import re +import subprocess import sys import urllib.parse @@ -24,6 +25,7 @@ from error import ManifestParseError from project import SyncBuffer from git_config import GitConfig from git_command import git_require, MIN_GIT_VERSION_SOFT, MIN_GIT_VERSION_HARD +import fetch import git_superproject import platform_utils from wrapper import Wrapper @@ -53,6 +55,12 @@ The optional -m argument can be used to specify an alternate manifest to be used. If no manifest is specified, the manifest default.xml will be used. +If the --standalone-manifest argument is set, the manifest will be downloaded +directly from the specified --manifest-url as a static file (rather than +setting up a manifest git checkout). With --standalone-manifest, the manifest +will be fully static and will not be re-downloaded during subsesquent +`repo init` and `repo sync` calls. + The --reference option can be used to point to a directory that has the content of a --mirror sync. This will make the working directory use as much data as possible from the local reference @@ -112,6 +120,22 @@ to update the working directory files. m = self.manifest.manifestProject is_new = not m.Exists + # If repo has already been initialized, we take -u with the absence of + # --standalone-manifest to mean "transition to a standard repo set up", + # which necessitates starting fresh. + # If --standalone-manifest is set, we always tear everything down and start + # anew. + if not is_new: + was_standalone_manifest = m.config.GetString('manifest.standalone') + if opt.standalone_manifest or ( + was_standalone_manifest and opt.manifest_url): + m.config.ClearCache() + if m.gitdir and os.path.exists(m.gitdir): + platform_utils.rmtree(m.gitdir) + if m.worktree and os.path.exists(m.worktree): + platform_utils.rmtree(m.worktree) + + is_new = not m.Exists if is_new: if not opt.manifest_url: print('fatal: manifest url is required.', file=sys.stderr) @@ -136,6 +160,19 @@ to update the working directory files. m._InitGitDir(mirror_git=mirrored_manifest_git) + # If standalone_manifest is set, mark the project as "standalone" -- we'll + # still do much of the manifests.git set up, but will avoid actual syncs to + # a remote. + standalone_manifest = False + if opt.standalone_manifest: + standalone_manifest = True + elif not opt.manifest_url: + # If -u is set and --standalone-manifest is not, then we're not in + # standalone mode. Otherwise, use config to infer what we were in the last + # init. + standalone_manifest = bool(m.config.GetString('manifest.standalone')) + m.config.SetString('manifest.standalone', opt.manifest_url) + self._ConfigureDepth(opt) # Set the remote URL before the remote branch as we might need it below. @@ -145,22 +182,23 @@ to update the working directory files. r.ResetFetch() r.Save() - if opt.manifest_branch: - if opt.manifest_branch == 'HEAD': - opt.manifest_branch = m.ResolveRemoteHead() - if opt.manifest_branch is None: - print('fatal: unable to resolve HEAD', file=sys.stderr) - sys.exit(1) - m.revisionExpr = opt.manifest_branch - else: - if is_new: - default_branch = m.ResolveRemoteHead() - if default_branch is None: - # If the remote doesn't have HEAD configured, default to master. - default_branch = 'refs/heads/master' - m.revisionExpr = default_branch + if not standalone_manifest: + if opt.manifest_branch: + if opt.manifest_branch == 'HEAD': + opt.manifest_branch = m.ResolveRemoteHead() + if opt.manifest_branch is None: + print('fatal: unable to resolve HEAD', file=sys.stderr) + sys.exit(1) + m.revisionExpr = opt.manifest_branch else: - m.PreSync() + if is_new: + default_branch = m.ResolveRemoteHead() + if default_branch is None: + # If the remote doesn't have HEAD configured, default to master. + default_branch = 'refs/heads/master' + m.revisionExpr = default_branch + else: + m.PreSync() groups = re.split(r'[,\s]+', opt.groups) all_platforms = ['linux', 'darwin', 'windows'] @@ -250,6 +288,16 @@ to update the working directory files. if opt.use_superproject is not None: m.config.SetBoolean('repo.superproject', opt.use_superproject) + if standalone_manifest: + if is_new: + manifest_name = 'default.xml' + manifest_data = fetch.fetch_file(opt.manifest_url) + dest = os.path.join(m.worktree, manifest_name) + os.makedirs(os.path.dirname(dest), exist_ok=True) + with open(dest, 'wb') as f: + f.write(manifest_data) + return + if not m.Sync_NetworkHalf(is_new=is_new, quiet=opt.quiet, verbose=opt.verbose, clone_bundle=opt.clone_bundle, current_branch_only=opt.current_branch_only, @@ -426,6 +474,11 @@ to update the working directory files. if opt.archive and opt.mirror: self.OptionParser.error('--mirror and --archive cannot be used together.') + if opt.standalone_manifest and ( + opt.manifest_branch or opt.manifest_name != 'default.xml'): + self.OptionParser.error('--manifest-branch and --manifest-name cannot' + ' be used with --standalone-manifest.') + if args: if opt.manifest_url: self.OptionParser.error( -- cgit v1.2.3-54-g00ecf