Only sync superproject if it will be used.
If the user says `--no-use-superproject`, then do not bother syncing the
superproject.
Also add/update docstrings and comments throughout.
Change-Id: I9cdad706130501bab9a22d3099a1dae605e9c194
Reviewed-on: https://gerrit-review.googlesource.com/c/git-repo/+/338975
Tested-by: LaMont Jones <lamontjones@google.com>
Reviewed-by: Mike Frysinger <vapier@google.com>
diff --git a/command.py b/command.py
index bd6d081..7c68ebc 100644
--- a/command.py
+++ b/command.py
@@ -277,6 +277,18 @@
def GetProjects(self, args, manifest=None, groups='', missing_ok=False,
submodules_ok=False, all_manifests=False):
"""A list of projects that match the arguments.
+
+ Args:
+ args: a list of (case-insensitive) strings, projects to search for.
+ manifest: an XmlManifest, the manifest to use, or None for default.
+ groups: a string, the manifest groups in use.
+ missing_ok: a boolean, whether to allow missing projects.
+ submodules_ok: a boolean, whether to allow submodules.
+ all_manifests: a boolean, if True then all manifests and submanifests are
+ used. If False, then only the local (sub)manifest is used.
+
+ Returns:
+ A list of matching Project instances.
"""
if all_manifests:
if not manifest:
diff --git a/git_superproject.py b/git_superproject.py
index 07bc264..5d00bd7 100644
--- a/git_superproject.py
+++ b/git_superproject.py
@@ -18,7 +18,7 @@
https://en.wikibooks.org/wiki/Git/Submodules_and_Superprojects
Examples:
- superproject = Superproject()
+ superproject = Superproject(manifest, name, remote, revision)
UpdateProjectsResult = superproject.UpdateProjectsRevisionId(projects)
"""
@@ -99,8 +99,8 @@
self._work_git_name = git_name + _SUPERPROJECT_GIT_NAME
self._work_git = os.path.join(self._superproject_path, self._work_git_name)
- # The following are command arguemnts, rather then superproject attributes,
- # and where included here originally. They should eventually become
+ # The following are command arguemnts, rather than superproject attributes,
+ # and were included here originally. They should eventually become
# arguments that are passed down from the public methods, instead of being
# treated as attributes.
self._git_event_log = None
@@ -329,7 +329,8 @@
"""Update revisionId of every project in projects with the commit id.
Args:
- projects: List of projects whose revisionId needs to be updated.
+ projects: a list of projects whose revisionId needs to be updated.
+ git_event_log: an EventLog, for git tracing.
Returns:
UpdateProjectsResult
@@ -431,9 +432,15 @@
Args:
use_superproject: option value from optparse.
manifest: manifest to use.
+
+ Returns:
+ Whether the superproject should be used.
"""
- if use_superproject is not None:
+ if not manifest.superproject:
+ # This (sub) manifest does not have a superproject definition.
+ return False
+ elif use_superproject is not None:
return use_superproject
else:
client_value = manifest.manifestProject.use_superproject
diff --git a/manifest_xml.py b/manifest_xml.py
index db7a928..32f6b68 100644
--- a/manifest_xml.py
+++ b/manifest_xml.py
@@ -348,7 +348,7 @@
be |repodir|/|MANIFEST_FILE_NAME|.
local_manifests: Full path to the directory of local override manifests.
This will usually be |repodir|/|LOCAL_MANIFESTS_DIR_NAME|.
- outer_client: RepoClient of the outertree.
+ outer_client: RepoClient of the outer manifest.
parent_groups: a string, the groups to apply to this projects.
submanifest_path: The submanifest root relative to the repo root.
default_groups: a string, the default manifest groups to use.
@@ -776,18 +776,21 @@
@property
def is_submanifest(self):
- """Whether this manifest is a submanifest"""
+ """Whether this manifest is a submanifest.
+
+ This is safe to use as long as the outermost manifest XML has been parsed.
+ """
return self._outer_client and self._outer_client != self
@property
def outer_client(self):
- """The instance of the outermost manifest client"""
+ """The instance of the outermost manifest client."""
self._Load()
return self._outer_client
@property
def all_manifests(self):
- """Generator yielding all (sub)manifests."""
+ """Generator yielding all (sub)manifests, in depth-first order."""
self._Load()
outer = self._outer_client
yield outer
@@ -796,7 +799,7 @@
@property
def all_children(self):
- """Generator yielding all child submanifests."""
+ """Generator yielding all (present) child submanifests."""
self._Load()
for child in self._submanifests.values():
if child.repo_client:
@@ -813,7 +816,14 @@
@property
def all_paths(self):
- """All project paths for all (sub)manifests. See `paths`."""
+ """All project paths for all (sub)manifests.
+
+ See also `paths`.
+
+ Returns:
+ A dictionary of {path: Project()}. `path` is relative to the outer
+ manifest.
+ """
ret = {}
for tree in self.all_manifests:
prefix = tree.path_prefix
@@ -829,7 +839,7 @@
def paths(self):
"""Return all paths for this manifest.
- Return:
+ Returns:
A dictionary of {path: Project()}. `path` is relative to this manifest.
"""
self._Load()
@@ -843,11 +853,13 @@
@property
def remotes(self):
+ """Return a list of remotes for this manifest."""
self._Load()
return self._remotes
@property
def default(self):
+ """Return default values for this manifest."""
self._Load()
return self._default
@@ -1090,8 +1102,8 @@
if override:
self.manifestFile = savedManifestFile
- # Now that we have loaded this manifest, load any submanifest manifests
- # as well. We need to do this after self._loaded is set to avoid looping.
+ # Now that we have loaded this manifest, load any submanifests as well.
+ # We need to do this after self._loaded is set to avoid looping.
for name in self._submanifests:
tree = self._submanifests[name]
spec = tree.ToSubmanifestSpec()
@@ -1659,6 +1671,10 @@
name: a string, the name of the project.
path: a string, the path of the project.
remote: a string, the remote.name of the project.
+
+ Returns:
+ A tuple of (relpath, worktree, gitdir, objdir, use_git_worktrees) for the
+ project with |name| and |path|.
"""
# The manifest entries might have trailing slashes. Normalize them to avoid
# unexpected filesystem behavior since we do string concatenation below.
@@ -1666,7 +1682,7 @@
name = name.rstrip('/')
remote = remote.rstrip('/')
use_git_worktrees = False
- use_remote_name = bool(self._outer_client._submanifests)
+ use_remote_name = self.is_multimanifest
relpath = path
if self.IsMirror:
worktree = None
@@ -1696,6 +1712,9 @@
name: a string, the name of the project.
all_manifests: a boolean, if True, then all manifests are searched. If
False, then only this manifest is searched.
+
+ Returns:
+ A list of Project instances with name |name|.
"""
if all_manifests:
return list(itertools.chain.from_iterable(
@@ -1956,6 +1975,16 @@
"""Manages a repo client checkout."""
def __init__(self, repodir, manifest_file=None, submanifest_path='', **kwargs):
+ """Initialize.
+
+ Args:
+ repodir: Path to the .repo/ dir for holding all internal checkout state.
+ It must be in the top directory of the repo client checkout.
+ manifest_file: Full path to the manifest file to parse. This will usually
+ be |repodir|/|MANIFEST_FILE_NAME|.
+ submanifest_path: The submanifest root relative to the repo root.
+ **kwargs: Additional keyword arguments, passed to XmlManifest.
+ """
self.isGitcClient = False
submanifest_path = submanifest_path or ''
if submanifest_path:
diff --git a/project.py b/project.py
index 8668bae..8fed8f5 100644
--- a/project.py
+++ b/project.py
@@ -33,6 +33,7 @@
from git_command import GitCommand, git_require
from git_config import GitConfig, IsId, GetSchemeFromUrl, GetUrlCookieFile, \
ID_RE
+import git_superproject
from git_trace2_event_log import EventLog
from error import GitError, UploadError, DownloadError
from error import ManifestInvalidRevisionError, ManifestInvalidPathError
@@ -2180,6 +2181,8 @@
if prune:
cmd.append('--prune')
+ # Always pass something for --recurse-submodules, git with GIT_DIR behaves
+ # incorrectly when not given `--recurse-submodules=no`. (b/218891912)
cmd.append(f'--recurse-submodules={"on-demand" if submodules else "no"}')
spec = []
@@ -3486,8 +3489,8 @@
git_event_log: an EventLog, for git tracing.
"""
# TODO(lamontjones): when refactoring sync (and init?) consider how to
- # better get the init options that we should use when syncing uncovers a new
- # submanifest.
+ # better get the init options that we should use for new submanifests that
+ # are added when syncing an existing workspace.
git_event_log = git_event_log or EventLog()
spec = submanifest.ToSubmanifestSpec()
# Use the init options from the existing manifestProject, or the parent if
@@ -3874,8 +3877,8 @@
)
# Lastly, if the manifest has a <superproject> then have the superproject
- # sync it if it will be used.
- if self.manifest.superproject:
+ # sync it (if it will be used).
+ if git_superproject.UseSuperproject(use_superproject, self.manifest):
sync_result = self.manifest.superproject.Sync(git_event_log)
if not sync_result.success:
print('warning: git update of superproject for '
diff --git a/subcmds/sync.py b/subcmds/sync.py
index 0abe23d..fa61d55 100644
--- a/subcmds/sync.py
+++ b/subcmds/sync.py
@@ -316,7 +316,7 @@
if not have_superproject:
return
- if opt.local_only:
+ if opt.local_only and manifest.superproject:
manifest_path = manifest.superproject.manifest_path
if manifest_path:
self._ReloadManifest(manifest_path, manifest)