You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@buildstream.apache.org by ro...@apache.org on 2020/12/29 13:49:40 UTC
[buildstream] 02/13: _gitsourcebase.py: Fetch with depth=1 when an
available tag is given
This is an automated email from the ASF dual-hosted git repository.
root pushed a commit to branch tmewett/merge-git-tag
in repository https://gitbox.apache.org/repos/asf/buildstream.git
commit c171026e988fa79383843c4880e9733a2acb1cf4
Author: Tom Mewett <to...@codethink.co.uk>
AuthorDate: Wed Dec 18 17:15:36 2019 +0000
_gitsourcebase.py: Fetch with depth=1 when an available tag is given
---
src/buildstream/_gitsourcebase.py | 89 +++++++++++++++++++++++++++++++++------
1 file changed, 76 insertions(+), 13 deletions(-)
diff --git a/src/buildstream/_gitsourcebase.py b/src/buildstream/_gitsourcebase.py
index afbf992..7d1858a 100644
--- a/src/buildstream/_gitsourcebase.py
+++ b/src/buildstream/_gitsourcebase.py
@@ -48,6 +48,21 @@ class _RefFormat(FastEnum):
GIT_DESCRIBE = "git-describe"
+# _has_matching_ref():
+#
+# Args:
+# refs: Iterable of string (ref id, ref name) pairs
+# tag (str): Tag name
+# commit (str): Commit ID
+#
+# Returns:
+# (bool): Whether the given tag is found in `refs` and points to ID `commit`
+#
+def _has_matching_ref(refs, tag, commit):
+ names = ("refs/tags/{tag}^{{}}".format(tag=tag), "refs/tags/{tag}".format(tag=tag))
+ return any(ref_commit == commit and ref_name in names for ref_commit, ref_name in refs)
+
+
# This class represents a single Git repository. The Git source needs to account for
# submodules, but we don't want to cache them all under the umbrella of the
# superproject - so we use this class which caches them independently, according
@@ -103,19 +118,67 @@ class _GitMirror(SourceFetcher):
def _fetch(self, url):
self._ensure_repo()
- self.source.call(
- [
- self.source.host_git,
- "fetch",
- "--prune",
- url,
- "+refs/heads/*:refs/heads/*",
- "+refs/tags/*:refs/tags/*",
- ],
- fail="Failed to fetch from remote git repository: {}".format(url),
- fail_temporarily=True,
- cwd=self.mirror,
- )
+ fetch_all = False
+
+ # Work out whether we can fetch a specific tag: are we given a ref which
+ # 1. is in git-describe format
+ # 2. refers to an exact tag (is "...-0-g...")
+ # 3. is available on the remote and tags the specified commit?
+ if not self.ref:
+ fetch_all = True
+ else:
+ m = re.match(r"(?P<tag>.*)-0-g(?P<commit>.*)", self.ref)
+ if m is None:
+ fetch_all = True
+ else:
+ tag = m.group("tag")
+ commit = m.group("commit")
+
+ _, ls_remote = self.source.check_output(
+ [self.source.host_git, "ls-remote", url],
+ cwd=self.mirror,
+ fail="Failed to list advertised remote refs from git repository {}".format(url),
+ )
+
+ refs = [line.split("\t", 1) for line in ls_remote.splitlines()]
+ has_ref = _has_matching_ref(refs, tag, commit)
+
+ if not has_ref:
+ self.source.status(
+ "{}: {} is not advertised on {}. Fetching all Git refs".format(self.source, self.ref, url)
+ )
+ fetch_all = True
+ else:
+ exit_code = self.source.call(
+ [
+ self.source.host_git,
+ "fetch",
+ "--depth=1",
+ url,
+ "+refs/tags/{tag}:refs/tags/{tag}".format(tag=tag),
+ ],
+ cwd=self.mirror,
+ )
+ if exit_code != 0:
+ self.source.status(
+ "{}: Failed to fetch tag '{}' from {}. Fetching all Git refs".format(self.source, tag, url)
+ )
+ fetch_all = True
+
+ if fetch_all:
+ self.source.call(
+ [
+ self.source.host_git,
+ "fetch",
+ "--prune",
+ url,
+ "+refs/heads/*:refs/heads/*",
+ "+refs/tags/*:refs/tags/*",
+ ],
+ fail="Failed to fetch from remote git repository: {}".format(url),
+ fail_temporarily=True,
+ cwd=self.mirror,
+ )
def fetch(self, alias_override=None): # pylint: disable=arguments-differ
resolved_url = self.source.translate_url(self.url, alias_override=alias_override, primary=self.primary)