[bitbake-devel] bb.fetch2.git: support resolving both tags and branches

Submitted by Olof Johansson on Dec. 19, 2013, 2:16 p.m.


Message ID 1387462588-26060-1-git-send-email-olof.johansson@axis.com
State New
Headers show

Commit Message

Olof Johansson Dec. 19, 2013, 2:16 p.m.
Before this change, the resolution of a git reference to a commit sha1,
was done in a way that was prone to bogus matches. Looking for a tag
R1.2.3 would potentially get the SHA1 of a branch ending in R1.2.3, like
refs/heads/foo/bar/R1.2.3, instead of refs/tags/R1.2.3.

But since tags and branches are used somewhat ambiguously, we will fall
back to resolve it as a branch with that exact name, if no tag with the
exact name was found.

Signed-off-by: Olof Johansson <olof.johansson@axis.com>

This patch was originally included in a patch series with unit
tests as well. There is some more work needed for the unittests
though. I will resubmit the unittest changes when this has been
merged, and the review comments has been resolved.

 lib/bb/fetch2/git.py | 47 +++++++++++++++++++++++++++++++++++++++++------
 1 file changed, 41 insertions(+), 6 deletions(-)

Patch hide | download patch | download mbox

diff --git a/lib/bb/fetch2/git.py b/lib/bb/fetch2/git.py
index bd107db..6ba52b1 100644
--- a/lib/bb/fetch2/git.py
+++ b/lib/bb/fetch2/git.py
@@ -304,23 +304,58 @@  class Git(FetchMethod):
         return "git:" + ud.host + ud.path.replace('/', '.') + ud.unresolvedrev[name]
-    def _latest_revision(self, ud, d, name):
+    def _gen_git_url(self, ud, d):
-        Compute the HEAD revision for the url
+        Based on the FetchData object, return a valid remote url that
+        you can pass to git.
         if ud.user:
             username = ud.user + '@'
             username = ""
-        cmd = "%s ls-remote %s://%s%s%s %s" % \
-              (ud.basecmd, ud.proto, username, ud.host, ud.path, ud.unresolvedrev[name])
+        return "%s://%s%s%s" % (ud.proto, username, ud.host, ud.path)
+    def _resolve_ref(self, ud, d, ref):
+        """
+        Try to resolve a reference using git ls-remote. We assume the
+        reference is fully qualified, or otherwise can be uniquely
+        resolved. Will return the commit sha1 of the reference.
+        If more than one line of output is returned, we'll raise an
+        FetchError exception. Same if no output is returned.
+        """
+        url = self._gen_git_url(ud, d)
+        cmd = "%s ls-remote %s %s" % (ud.basecmd, url, ref)
         if ud.proto.lower() != 'file':
             bb.fetch2.check_network_access(d, cmd)
         output = runfetchcmd(cmd, d, True)
         if not output:
-            raise bb.fetch2.FetchError("The command %s gave empty output unexpectedly" % cmd, ud.url)
-        return output.split()[0]
+            raise bb.fetch2.FetchError(
+                "The command %s gave empty output unexpectedly" % cmd, ud.url)
+        output = output.split()
+        if len(output) > 2:
+            raise bb.fetch2.FetchError(
+                "The command %s gave more than one result" % cmd, ud.url)
+        return output[0]
+    def _latest_revision(self, ud, d, name):
+        """
+        Compute the HEAD revision for the url. The reference is first
+        tried as refs/tags/<ref>^{}, which should return a sha1 of the
+        commit object pointed to by the tag. If nothing is found, we'll
+        try to resolve it as refs/heads/<tag> instead.
+        """
+        ref = ud.unresolvedrev[name]
+        try:
+            return self._resolve_ref(ud, d, "refs/tags/%s^{}" % ref)
+        except:
+            return self._resolve_ref(ud, d, "refs/heads/%s" % ref)
     def _build_revision(self, ud, d, name):
         return ud.revisions[name]