Squashed 'yocto-poky/' changes from ea562de..7b86c77

7b86c77 bitbake: bitbake: bb.fetch2.git: Import errno module
e993aa6 bitbake: toaster: hide irrelevant builds in the project builds view
5b4e380 bitbake: data_smart: Ensure OVERRIDES dependencies account for contains()
60d019d bitbake: data_smart: Correctly handle OVERRIDE values set using ??=
701ad76 bitbake: data_smart: When considering OVERRIDE dependencies, do so recursively
4325f6f bitbake: data_smart: Expand overrides cache recursively
3a5e46b bitbake: bb.fetch2.{git, hg}: remove tarball if it needs updating
441f04c bitbake: toaster: Simplify redirects when build page parameters are missing
30f9f79 bitbake: toaster: Fix date range pickers on the project builds page
047245f bitbake: toaster: Show correct builds count on project pages
5528f3a bitbake: toaster: hide irrelevant builds in the project builds view
2bb600a bitbake: tests/fetch.py: Fix recursion failure in url mapping
4c3d4ec bitbake: fetch2/__init__.py: uri_replace regex handling
460e4c2 bitbake: toaster: Don't def a function for each call to build_artifact()
b6d1d2a bitbake: toaster: Avoid unnecessary local to local copy of cooker log
8c63d60 bitbake: toaster: Read correct cooker log path from toasterui
013c030 bitbake: toaster: delete multiple builds cleanup
3165af3 bitbake: data_smart: Separate out update_overridevars into separate function
07aef86 bitbake: cache: Handle spaces and colons in directory names for file-checksums
9679500 autotools.bbclass: mkdir ${B} -> mkdir -p ${B}
c30ee2a perf: mkdir ${B} -> mkdir -p ${B}
d18612a recipetool: add 'newappend' sub-command
4727384 oeqa/sstatetests: Add test for nativesdk stamp invariance with MACHINE
56b2c53 glibc: Ensure OVERRIDES doesn't influence sstate checksum
1884550 image.py: Ensure base image size is an integer
ec72426 python: Add python-misc as rdependency to python-modules
c170f35 cryptodev-tests: don't use STAGING_KERNEL_DIR, fix re-packaging in multi-machine builds
2d7fe03 adwaita-icon-theme: RREPLACE gnome-icon-theme
94d280f mkelfimage: fix owner for /usr/sbin/mkelfImage
3323c3f nspr: fix SRC_URI
935a8bd mkefidisk: Create interactive menu for the script
6c05e6a image.bbclass: add do_rootfs vardeps for {COMPRESS, IMAGE}_CMD_*
82be1f3 squashfs-tools: make it be able to be compiled by gcc5 with "-O0"
dc3bc22 linux-firmware: package Broadcom BCM4354 firmware
db8f796 perf: fix the install-python_ext on upstream kernel
bfe2cd1 systemd: fix missing space in SRC_URI append
2515cf2 python: remove --with-wctype-functions configure option
17f5a5a kmod: fix link creation when base_bindir != /bin
e2cfe93 prelink: Move to latest release
32472dc glibc: don't require bash for nscd init script
d8eb9d4 oeqa/decorators: Added decorator to restart the DUT in case of test hang.
5acf99d init-install-efi.sh: Avoid /mnt/mtab creation if already present

git-subtree-dir: yocto-poky
git-subtree-split: 7b86c771c80d0759c2ca0e57c46c4c966f89c49e
diff --git a/bitbake/lib/bb/cache.py b/bitbake/lib/bb/cache.py
index ef4d660..ab09b08 100644
--- a/bitbake/lib/bb/cache.py
+++ b/bitbake/lib/bb/cache.py
@@ -528,7 +528,20 @@
 
         if hasattr(info_array[0], 'file_checksums'):
             for _, fl in info_array[0].file_checksums.items():
-                for f in fl.split():
+                fl = fl.strip()
+                while fl:
+                    # A .split() would be simpler but means spaces or colons in filenames would break
+                    a = fl.find(":True")
+                    b = fl.find(":False")
+                    if ((a < 0) and b) or ((b > 0) and (b < a)):
+                       f = fl[:b+6]
+                       fl = fl[b+7:]
+                    elif ((b < 0) and a) or ((a > 0) and (a < b)):
+                       f = fl[:a+5]
+                       fl = fl[a+6:]
+                    else:
+                       break
+                    fl = fl.strip()
                     if "*" in f:
                         continue
                     f, exist = f.split(":")
diff --git a/bitbake/lib/bb/data_smart.py b/bitbake/lib/bb/data_smart.py
index 79b4ed9..70558c1 100644
--- a/bitbake/lib/bb/data_smart.py
+++ b/bitbake/lib/bb/data_smart.py
@@ -413,9 +413,11 @@
         self.overrides = None
 
     def need_overrides(self):
-        if self.overrides is None:
-            if self.inoverride:
-                return
+        if self.overrides is not None:
+            return
+        if self.inoverride:
+            return
+        for count in range(5):
             self.inoverride = True
             # Can end up here recursively so setup dummy values
             self.overrides = []
@@ -424,6 +426,13 @@
             self.overridesset = set(self.overrides)
             self.inoverride = False
             self.expand_cache = {}
+            newoverrides = (self.getVar("OVERRIDES", True) or "").split(":") or []
+            if newoverrides == self.overrides:
+                break
+            self.overrides = newoverrides
+            self.overridesset = set(self.overrides)
+        else:
+            bb.fatal("Overrides could not be expanded into a stable state after 5 iterations, overrides must be being referenced by other overridden variables in some recursive fashion. Please provide your configuration to bitbake-devel so we can laugh, er, I mean try and understand how to make it work.")
 
     def initVar(self, var):
         self.expand_cache = {}
@@ -484,10 +493,8 @@
             if '_' in var:
                 self._setvar_update_overrides(base, **loginfo)
 
-
             if base in self.overridevars:
-                self.overridevars.update(self.expandWithRefs(value, var).references)
-                self.internal_finalize(True)
+                self._setvar_update_overridevars(var, value)
             return
 
         if not var in self.dict:
@@ -520,8 +527,21 @@
         self.varhistory.record(**loginfo)
 
         if var in self.overridevars:
-            self.overridevars.update(self.expandWithRefs(value, var).references)
-            self.internal_finalize(True)
+            self._setvar_update_overridevars(var, value)
+
+    def _setvar_update_overridevars(self, var, value):
+        vardata = self.expandWithRefs(value, var)
+        new = vardata.references
+        new.update(vardata.contains.keys())
+        while not new.issubset(self.overridevars):
+            nextnew = set()
+            self.overridevars.update(new)
+            for i in new:
+                vardata = self.expandWithRefs(self.getVar(i, True), i)
+                nextnew.update(vardata.references)
+                nextnew.update(vardata.contains.keys())
+            new = nextnew
+        self.internal_finalize(True)
 
     def _setvar_update_overrides(self, var, **loginfo):
         # aka pay the cookie monster
@@ -628,6 +648,8 @@
 
         if flag == "_defaultval" and '_' in var:
             self._setvar_update_overrides(var, **loginfo)
+        if flag == "_defaultval" and var in self.overridevars:
+            self._setvar_update_overridevars(var, value)
 
         if flag == "unexport" or flag == "export":
             if not "__exportlist" in self.dict:
diff --git a/bitbake/lib/bb/fetch2/__init__.py b/bitbake/lib/bb/fetch2/__init__.py
index 3d53b63..288a1c8 100644
--- a/bitbake/lib/bb/fetch2/__init__.py
+++ b/bitbake/lib/bb/fetch2/__init__.py
@@ -464,7 +464,7 @@
                 for k in replacements:
                     uri_replace_decoded[loc] = uri_replace_decoded[loc].replace(k, replacements[k])
                 #bb.note("%s %s %s" % (regexp, uri_replace_decoded[loc], uri_decoded[loc]))
-                result_decoded[loc] = re.sub(regexp, uri_replace_decoded[loc], uri_decoded[loc])
+                result_decoded[loc] = re.sub(regexp, uri_replace_decoded[loc], uri_decoded[loc], 1)
             if loc == 2:
                 # Handle path manipulations
                 basename = None
@@ -862,7 +862,7 @@
     replacements["BASENAME"] = origud.path.split("/")[-1]
     replacements["MIRRORNAME"] = origud.host.replace(':','.') + origud.path.replace('/', '.').replace('*', '.')
 
-    def adduri(ud, uris, uds):
+    def adduri(ud, uris, uds, mirrors):
         for line in mirrors:
             try:
                 (find, replace) = line
@@ -876,6 +876,12 @@
                 logger.debug(1, "Mirror %s not in the list of trusted networks, skipping" %  (newuri))
                 continue
 
+            # Create a local copy of the mirrors minus the current line
+            # this will prevent us from recursively processing the same line
+            # as well as indirect recursion A -> B -> C -> A
+            localmirrors = list(mirrors)
+            localmirrors.remove(line)
+
             try:
                 newud = FetchData(newuri, ld)
                 newud.setup_localpath(ld)
@@ -885,16 +891,16 @@
                 try:
                     # setup_localpath of file:// urls may fail, we should still see 
                     # if mirrors of the url exist
-                    adduri(newud, uris, uds)
+                    adduri(newud, uris, uds, localmirrors)
                 except UnboundLocalError:
                     pass
                 continue   
             uris.append(newuri)
             uds.append(newud)
 
-            adduri(newud, uris, uds)
+            adduri(newud, uris, uds, localmirrors)
 
-    adduri(origud, uris, uds)
+    adduri(origud, uris, uds, mirrors)
 
     return uris, uds
 
diff --git a/bitbake/lib/bb/fetch2/git.py b/bitbake/lib/bb/fetch2/git.py
index 40658ff..9bd87ad 100644
--- a/bitbake/lib/bb/fetch2/git.py
+++ b/bitbake/lib/bb/fetch2/git.py
@@ -66,6 +66,7 @@
 # with this program; if not, write to the Free Software Foundation, Inc.,
 # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 
+import errno
 import os
 import re
 import bb
@@ -181,8 +182,6 @@
     def download(self, ud, d):
         """Fetch url"""
 
-        ud.repochanged = not os.path.exists(ud.fullmirror)
-
         # If the checkout doesn't exist and the mirror tarball does, extract it
         if not os.path.exists(ud.clonedir) and os.path.exists(ud.fullmirror):
             bb.utils.mkdirhier(ud.clonedir)
@@ -220,7 +219,11 @@
             runfetchcmd(fetch_cmd, d)
             runfetchcmd("%s prune-packed" % ud.basecmd, d)
             runfetchcmd("%s pack-redundant --all | xargs -r rm" % ud.basecmd, d)
-            ud.repochanged = True
+            try:
+                os.unlink(ud.fullmirror)
+            except OSError as exc:
+                if exc.errno != errno.ENOENT:
+                    raise
         os.chdir(ud.clonedir)
         for name in ud.names:
             if not self._contains_ref(ud, d, name):
@@ -228,7 +231,7 @@
 
     def build_mirror_data(self, ud, d):
         # Generate a mirror tarball if needed
-        if ud.write_tarballs and (ud.repochanged or not os.path.exists(ud.fullmirror)):
+        if ud.write_tarballs and not os.path.exists(ud.fullmirror):
             # it's possible that this symlink points to read-only filesystem with PREMIRROR
             if os.path.islink(ud.fullmirror):
                 os.unlink(ud.fullmirror)
diff --git a/bitbake/lib/bb/fetch2/hg.py b/bitbake/lib/bb/fetch2/hg.py
index d978630..bbb4ed9 100644
--- a/bitbake/lib/bb/fetch2/hg.py
+++ b/bitbake/lib/bb/fetch2/hg.py
@@ -163,8 +163,6 @@
     def download(self, ud, d):
         """Fetch url"""
 
-        ud.repochanged = not os.path.exists(ud.fullmirror)
-
         logger.debug(2, "Fetch: checking for module directory '" + ud.moddir + "'")
 
         # If the checkout doesn't exist and the mirror tarball does, extract it
@@ -189,7 +187,11 @@
                 logger.debug(1, "Running %s", pullcmd)
                 bb.fetch2.check_network_access(d, pullcmd, ud.url)
                 runfetchcmd(pullcmd, d)
-                ud.repochanged = True
+                try:
+                    os.unlink(ud.fullmirror)
+                except OSError as exc:
+                    if exc.errno != errno.ENOENT:
+                        raise
 
         # No source found, clone it.
         if not os.path.exists(ud.moddir):
@@ -238,7 +240,7 @@
 
     def build_mirror_data(self, ud, d):
         # Generate a mirror tarball if needed
-        if ud.write_tarballs == "1" and (ud.repochanged or not os.path.exists(ud.fullmirror)):
+        if ud.write_tarballs == "1" and not os.path.exists(ud.fullmirror):
             # it's possible that this symlink points to read-only filesystem with PREMIRROR
             if os.path.islink(ud.fullmirror):
                 os.unlink(ud.fullmirror)
diff --git a/bitbake/lib/bb/tests/fetch.py b/bitbake/lib/bb/tests/fetch.py
index 1e61f3a..94173c1 100644
--- a/bitbake/lib/bb/tests/fetch.py
+++ b/bitbake/lib/bb/tests/fetch.py
@@ -405,6 +405,16 @@
                                 'http://otherdownloads.yoctoproject.org/downloads/bitbake-1.0.tar.gz',
                                 'http://downloads2.yoctoproject.org/downloads/bitbake-1.0.tar.gz'])
 
+    recmirrorvar = "https://.*/[^/]*    http://AAAA/A/A/A/ \n" \
+                   "https://.*/[^/]*    https://BBBB/B/B/B/ \n"
+
+    def test_recursive(self):
+        fetcher = bb.fetch.FetchData("https://downloads.yoctoproject.org/releases/bitbake/bitbake-1.0.tar.gz", self.d)
+        mirrors = bb.fetch2.mirror_from_string(self.recmirrorvar)
+        uris, uds = bb.fetch2.build_mirroruris(fetcher, mirrors, self.d)
+        self.assertEqual(uris, ['http://AAAA/A/A/A/bitbake/bitbake-1.0.tar.gz',
+                                'https://BBBB/B/B/B/bitbake/bitbake-1.0.tar.gz',
+                                'http://AAAA/A/A/A/B/B/bitbake/bitbake-1.0.tar.gz'])
 
 class FetcherLocalTest(FetcherTest):
     def setUp(self):
diff --git a/bitbake/lib/bb/ui/buildinfohelper.py b/bitbake/lib/bb/ui/buildinfohelper.py
index 2d1ed51..6e313fe 100644
--- a/bitbake/lib/bb/ui/buildinfohelper.py
+++ b/bitbake/lib/bb/ui/buildinfohelper.py
@@ -704,7 +704,7 @@
     ## methods to convert event/external info into objects that the ORM layer uses
 
 
-    def _get_build_information(self):
+    def _get_build_information(self, consolelogfile):
         build_info = {}
         # Generate an identifier for each new build
 
@@ -713,7 +713,7 @@
         build_info['distro_version'] = self.server.runCommand(["getVariable", "DISTRO_VERSION"])[0]
         build_info['started_on'] = timezone.now()
         build_info['completed_on'] = timezone.now()
-        build_info['cooker_log_path'] = self.server.runCommand(["getVariable", "BB_CONSOLELOG"])[0]
+        build_info['cooker_log_path'] = consolelogfile
         build_info['build_name'] = self.server.runCommand(["getVariable", "BUILDNAME"])[0]
         build_info['bitbake_version'] = self.server.runCommand(["getVariable", "BB_VERSION"])[0]
 
@@ -847,9 +847,9 @@
                 logger.warn("buildinfohelper: cannot identify layer exception:%s ", nee)
 
 
-    def store_started_build(self, event):
+    def store_started_build(self, event, consolelogfile):
         assert '_pkgs' in vars(event)
-        build_information = self._get_build_information()
+        build_information = self._get_build_information(consolelogfile)
 
         build_obj = self.orm_wrapper.create_build_object(build_information, self.brbe, self.project)
 
diff --git a/bitbake/lib/bb/ui/toasterui.py b/bitbake/lib/bb/ui/toasterui.py
index 9c7e87d..e0c278b 100644
--- a/bitbake/lib/bb/ui/toasterui.py
+++ b/bitbake/lib/bb/ui/toasterui.py
@@ -126,7 +126,7 @@
             # the code will look into the protected variables of the event; no easy way around this
 
             if isinstance(event, bb.event.BuildStarted):
-                buildinfohelper.store_started_build(event)
+                buildinfohelper.store_started_build(event, consolelogfile)
 
             if isinstance(event, (bb.build.TaskStarted, bb.build.TaskSucceeded, bb.build.TaskFailedSilent)):
                 buildinfohelper.update_and_store_task(event)