<div dir="ltr">Hi;<div><br></div><div>I was just wondering what the expected procedure is here among the bitbake devs. Should I be contacting the specific people that have historically been the committers for the particular code affected by the change?</div><div><br></div><div>Thanks,</div><div>Matt</div><br><div class="gmail_quote"><div dir="ltr">On Fri, May 25, 2018 at 8:45 AM Matt Hoosier &lt;<a href="mailto:matt.hoosier@gmail.com">matt.hoosier@gmail.com</a>&gt; wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Although the submodules&#39; histories have been fetched during the<br>
do_fetch() phase, the mechanics used to clone the workdir copy<br>
of the repo haven&#39;t been transferring the actual .git/modules<br>
directory from the repo fetched into downloads/ during the<br>
fetch task.<br>
<br>
Fix that, and for good measure also explicitly tell Git to avoid<br>
hitting the network during do_unpack() of the submodules.<br>
<br>
[YOCTO #12739]<br>
<br>
Signed-off-by: Matt Hoosier &lt;<a href="mailto:matt.hoosier@gmail.com" target="_blank">matt.hoosier@gmail.com</a>&gt;<br>
---<br>
 lib/bb/fetch2/gitsm.py | 84 +++++++++++++++++++++++++++++++++++++++++++++-----<br>
 1 file changed, 76 insertions(+), 8 deletions(-)<br>
<br>
diff --git a/lib/bb/fetch2/gitsm.py b/lib/bb/fetch2/gitsm.py<br>
index 0aff1008..7ac0dbb1 100644<br>
--- a/lib/bb/fetch2/gitsm.py<br>
+++ b/lib/bb/fetch2/gitsm.py<br>
@@ -98,7 +98,7 @@ class GitSM(Git):<br>
                         for line in lines:<br>
                             f.write(line)<br>
<br>
-    def update_submodules(self, ud, d):<br>
+    def update_submodules(self, ud, d, allow_network):<br>
         # We have to convert bare -&gt; full repo, do the submodule bit, then convert back<br>
         tmpclonedir = ud.clonedir + &quot;.tmp&quot;<br>
         gitdir = tmpclonedir + os.sep + &quot;.git&quot;<br>
@@ -108,11 +108,47 @@ class GitSM(Git):<br>
         runfetchcmd(&quot;sed &quot; + gitdir + &quot;/config -i -e &#39;s/bare.*=.*true/bare = false/&#39;&quot;, d)<br>
         runfetchcmd(ud.basecmd + &quot; reset --hard&quot;, d, workdir=tmpclonedir)<br>
         runfetchcmd(ud.basecmd + &quot; checkout -f &quot; + ud.revisions[ud.names[0]], d, workdir=tmpclonedir)<br>
-        runfetchcmd(ud.basecmd + &quot; submodule update --init --recursive&quot;, d, workdir=tmpclonedir)<br>
-        self._set_relative_paths(tmpclonedir)<br>
-        runfetchcmd(&quot;sed &quot; + gitdir + &quot;/config -i -e &#39;s/bare.*=.*false/bare = true/&#39;&quot;, d, workdir=tmpclonedir)<br>
-        os.rename(gitdir, ud.clonedir,)<br>
-        bb.utils.remove(tmpclonedir, True)<br>
+<br>
+        try:<br>
+            if allow_network:<br>
+                fetch_flags = &quot;&quot;<br>
+            else:<br>
+                fetch_flags = &quot;--no-fetch&quot;<br>
+<br>
+            # The &#39;git submodule sync&#39; sandwiched between two successive &#39;git submodule update&#39; commands is<br>
+            # intentional. See the notes on the similar construction in download() for an explanation.<br>
+            runfetchcmd(&quot;%(basecmd)s submodule update --init --recursive %(fetch_flags)s || (%(basecmd)s submodule sync --recursive &amp;&amp; %(basecmd)s submodule update --init --recursive %(fetch_flags)s)&quot; % {&#39;basecmd&#39;: ud.basecmd, &#39;fetch_flags&#39; : fetch_flags}, d, workdir=tmpclonedir)<br>
+        except bb.fetch.FetchError:<br>
+            if allow_network:<br>
+                raise<br>
+            else:<br>
+                # This method was called as a probe to see whether the submodule history<br>
+                # is complete enough to allow the current working copy to have its<br>
+                # modules filled in. It&#39;s not, so swallow up the exception and report<br>
+                # the negative result.<br>
+                return False<br>
+        finally:<br>
+            self._set_relative_paths(tmpclonedir)<br>
+            runfetchcmd(ud.basecmd + &quot; submodule deinit -f --all&quot;, d, workdir=tmpclonedir)<br>
+            runfetchcmd(&quot;sed &quot; + gitdir + &quot;/config -i -e &#39;s/bare.*=.*false/bare = true/&#39;&quot;, d, workdir=tmpclonedir)<br>
+            os.rename(gitdir, ud.clonedir,)<br>
+            bb.utils.remove(tmpclonedir, True)<br>
+<br>
+        return True<br>
+<br>
+    def need_update(self, ud, d):<br>
+        main_repo_needs_update = Git.need_update(self, ud, d)<br>
+<br>
+        # First check that the main repository has enough history fetched. If it doesn&#39;t, then we don&#39;t<br>
+        # even have the .gitmodules and gitlinks for the submodules to attempt asking whether the<br>
+        # submodules&#39; histories are recent enough.<br>
+        if main_repo_needs_update:<br>
+            return True<br>
+<br>
+        # Now check that the submodule histories are new enough. The git-submodule command doesn&#39;t have<br>
+        # any clean interface for doing this aside from just attempting the checkout (with network<br>
+        # fetched disabled).<br>
+        return not self.update_submodules(ud, d, allow_network=False)<br>
<br>
     def download(self, ud, d):<br>
         Git.download(self, ud, d)<br>
@@ -120,7 +156,7 @@ class GitSM(Git):<br>
         if not ud.shallow or ud.localpath != ud.fullshallow:<br>
             submodules = self.uses_submodules(ud, d, ud.clonedir)<br>
             if submodules:<br>
-                self.update_submodules(ud, d)<br>
+                self.update_submodules(ud, d, allow_network=True)<br>
<br>
     def clone_shallow_local(self, ud, dest, d):<br>
         super(GitSM, self).clone_shallow_local(ud, dest, d)<br>
@@ -132,4 +168,36 @@ class GitSM(Git):<br>
<br>
         if self.uses_submodules(ud, d, ud.destdir):<br>
             runfetchcmd(ud.basecmd + &quot; checkout &quot; + ud.revisions[ud.names[0]], d, workdir=ud.destdir)<br>
-            runfetchcmd(ud.basecmd + &quot; submodule update --init --recursive&quot;, d, workdir=ud.destdir)<br>
+<br>
+            # Copy over the submodules&#39; fetched histories too.<br>
+            if ud.bareclone:<br>
+                repo_conf = ud.destdir<br>
+            else:<br>
+                repo_conf = os.path.join(ud.destdir, &#39;.git&#39;)<br>
+<br>
+            if os.path.exists(ud.clonedir):<br>
+                # This is not a copy unpacked from a shallow mirror clone. So<br>
+                # the manual intervention to populate the .git/modules done<br>
+                # in clone_shallow_local() won&#39;t have been done yet.<br>
+                runfetchcmd(&quot;cp -fpPRH %s %s&quot; % (os.path.join(ud.clonedir, &#39;modules&#39;), repo_conf), d)<br>
+                fetch_flags = &quot;--no-fetch&quot;<br>
+            elif os.path.exists(os.path.join(repo_conf, &#39;modules&#39;)):<br>
+                # Unpacked from a shallow mirror clone. Manual population of<br>
+                # .git/modules is already done.<br>
+                fetch_flags = &quot;--no-fetch&quot;<br>
+            else:<br>
+                # This isn&#39;t fatal; git-submodule will just fetch it<br>
+                # during do_unpack().<br>
+                fetch_flags = &quot;&quot;<br>
+                bb.error(&quot;submodule history not retrieved during do_fetch()&quot;)<br>
+<br>
+            # Careful not to hit the network during unpacking; all history should already<br>
+            # be fetched.<br>
+            #<br>
+            # The repeated attempts to do the submodule initialization sandwiched around a sync to<br>
+            # install the correct remote URLs into the submodules&#39; .git/config metadata are deliberate.<br>
+            # Bad remote URLs are leftover in the modules&#39; .git/config files from the unpack of bare<br>
+            # clone tarballs and an initial &#39;git submodule update&#39; is necessary to prod them back to<br>
+            # enough life so that the &#39;git submodule sync&#39; realizes the existing module .git/config<br>
+            # files exist to be updated.<br>
+            runfetchcmd(&quot;%(basecmd)s submodule update --init --recursive %(fetch_flags)s || (%(basecmd)s submodule sync --recursive &amp;&amp; %(basecmd)s submodule update --init --recursive %(fetch_flags)s)&quot; % {&#39;basecmd&#39;: ud.basecmd, &#39;fetch_flags&#39;: fetch_flags}, d, workdir=ud.destdir)<br>
-- <br>
2.13.6<br>
<br>
</blockquote></div></div>