diff options
author | Richard Purdie <richard.purdie@linuxfoundation.org> | 2023-09-16 18:20:03 +0100 |
---|---|---|
committer | Richard Purdie <richard.purdie@linuxfoundation.org> | 2023-09-18 11:35:05 +0100 |
commit | 37c31a5adc26fc947a447ca9eae0983a654d1a33 (patch) | |
tree | 4d40adb741fd25fb0f60993e303ad5e9e7d5fa1a | |
parent | d1f84db670bd130353ebc5fb8077cf9657fb4e44 (diff) | |
download | poky-37c31a5adc26fc947a447ca9eae0983a654d1a33.tar.gz |
bitbake: lib: Drop inotify support and replace with mtime checks
With the flush in serverlog() removed and a memory resident bitbake with a
60s timeout, the following could fail in strange ways:
rm bitbake-cookerdaemon.log
bitbake-layers add-layer ../meta-virtualization/
bitbake-layers add-layer ../meta-openembedded/meta-oe/
bitbake -m
specifically that it might error adding meta-oe with an error related to meta-virt.
This clearly shows that whilst bblayers.conf was modified, bitbake was not
recognising that. This would fit with the random autobuilder issues seen when
the serverlog flush() call was removed.
The issue appears to be that you have no way to "sync()" the inotify events with
the command stream coming over the socket. There is no way to know if there are
changes in the IO queue which bitbake needs to wait for before proceeding with
the next command.
I did experiment with os.sync() and fsync on the inotify fd, however nothing
addressed the issue. Since it is extremely important we have accurate cache data,
the only realistic thing to do is to switch to stat() calls and check mtime.
For bitbake commands, this is straightforward since we can revalidate the cache
upon new connections/commands. For tinfoil this is problematic and we need to
introduce and explict command "revalidateCaches" that the code can use to force
bitbake to re-check it's cache validity. I've exposed this through tinfoil with
a new "modified_files" function.
So, this patch:
a) drops inotify support within bitbake's cooker/server and switch to using mtime
b) requires a new function call in tinfoil when metadata has been modified
(Bitbake rev: da3ec3801bdb80180b3f1ac24edb27a698415ff7)
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
-rw-r--r-- | bitbake/lib/bb/command.py | 8 | ||||
-rw-r--r-- | bitbake/lib/bb/cooker.py | 179 | ||||
-rw-r--r-- | bitbake/lib/bb/parse/__init__.py | 8 | ||||
-rw-r--r-- | bitbake/lib/bb/server/process.py | 6 | ||||
-rw-r--r-- | bitbake/lib/bb/tinfoil.py | 6 | ||||
-rw-r--r-- | bitbake/lib/bblayers/action.py | 6 |
6 files changed, 65 insertions, 148 deletions
diff --git a/bitbake/lib/bb/command.py b/bitbake/lib/bb/command.py index b494f84a0a..8663eed933 100644 --- a/bitbake/lib/bb/command.py +++ b/bitbake/lib/bb/command.py | |||
@@ -85,8 +85,6 @@ class Command: | |||
85 | if not hasattr(command_method, 'readonly') or not getattr(command_method, 'readonly'): | 85 | if not hasattr(command_method, 'readonly') or not getattr(command_method, 'readonly'): |
86 | return None, "Not able to execute not readonly commands in readonly mode" | 86 | return None, "Not able to execute not readonly commands in readonly mode" |
87 | try: | 87 | try: |
88 | if command != "ping": | ||
89 | self.cooker.process_inotify_updates_apply() | ||
90 | if getattr(command_method, 'needconfig', True): | 88 | if getattr(command_method, 'needconfig', True): |
91 | self.cooker.updateCacheSync() | 89 | self.cooker.updateCacheSync() |
92 | result = command_method(self, commandline) | 90 | result = command_method(self, commandline) |
@@ -110,7 +108,6 @@ class Command: | |||
110 | 108 | ||
111 | def runAsyncCommand(self, _, process_server, halt): | 109 | def runAsyncCommand(self, _, process_server, halt): |
112 | try: | 110 | try: |
113 | self.cooker.process_inotify_updates_apply() | ||
114 | if self.cooker.state in (bb.cooker.state.error, bb.cooker.state.shutdown, bb.cooker.state.forceshutdown): | 111 | if self.cooker.state in (bb.cooker.state.error, bb.cooker.state.shutdown, bb.cooker.state.forceshutdown): |
115 | # updateCache will trigger a shutdown of the parser | 112 | # updateCache will trigger a shutdown of the parser |
116 | # and then raise BBHandledException triggering an exit | 113 | # and then raise BBHandledException triggering an exit |
@@ -310,6 +307,11 @@ class CommandsSync: | |||
310 | return ret | 307 | return ret |
311 | getLayerPriorities.readonly = True | 308 | getLayerPriorities.readonly = True |
312 | 309 | ||
310 | def revalidateCaches(self, command, params): | ||
311 | """Called by UI clients when metadata may have changed""" | ||
312 | command.cooker.revalidateCaches() | ||
313 | parseConfiguration.needconfig = False | ||
314 | |||
313 | def getRecipes(self, command, params): | 315 | def getRecipes(self, command, params): |
314 | try: | 316 | try: |
315 | mc = params[0] | 317 | mc = params[0] |
diff --git a/bitbake/lib/bb/cooker.py b/bitbake/lib/bb/cooker.py index 064e3cae6e..4089d003bb 100644 --- a/bitbake/lib/bb/cooker.py +++ b/bitbake/lib/bb/cooker.py | |||
@@ -22,7 +22,6 @@ from bb import utils, data, parse, event, cache, providers, taskdata, runqueue, | |||
22 | import queue | 22 | import queue |
23 | import signal | 23 | import signal |
24 | import prserv.serv | 24 | import prserv.serv |
25 | import pyinotify | ||
26 | import json | 25 | import json |
27 | import pickle | 26 | import pickle |
28 | import codecs | 27 | import codecs |
@@ -175,15 +174,8 @@ class BBCooker: | |||
175 | bb.debug(1, "BBCooker starting %s" % time.time()) | 174 | bb.debug(1, "BBCooker starting %s" % time.time()) |
176 | sys.stdout.flush() | 175 | sys.stdout.flush() |
177 | 176 | ||
178 | self.configwatcher = None | 177 | self.configwatched = {} |
179 | self.confignotifier = None | 178 | self.parsewatched = {} |
180 | |||
181 | self.watchmask = pyinotify.IN_CLOSE_WRITE | pyinotify.IN_CREATE | pyinotify.IN_DELETE | \ | ||
182 | pyinotify.IN_DELETE_SELF | pyinotify.IN_MODIFY | pyinotify.IN_MOVE_SELF | \ | ||
183 | pyinotify.IN_MOVED_FROM | pyinotify.IN_MOVED_TO | ||
184 | |||
185 | self.watcher = None | ||
186 | self.notifier = None | ||
187 | 179 | ||
188 | # If being called by something like tinfoil, we need to clean cached data | 180 | # If being called by something like tinfoil, we need to clean cached data |
189 | # which may now be invalid | 181 | # which may now be invalid |
@@ -194,8 +186,6 @@ class BBCooker: | |||
194 | self.hashserv = None | 186 | self.hashserv = None |
195 | self.hashservaddr = None | 187 | self.hashservaddr = None |
196 | 188 | ||
197 | self.inotify_modified_files = [] | ||
198 | |||
199 | # TOSTOP must not be set or our children will hang when they output | 189 | # TOSTOP must not be set or our children will hang when they output |
200 | try: | 190 | try: |
201 | fd = sys.stdout.fileno() | 191 | fd = sys.stdout.fileno() |
@@ -221,8 +211,6 @@ class BBCooker: | |||
221 | bb.debug(1, "BBCooker startup complete %s" % time.time()) | 211 | bb.debug(1, "BBCooker startup complete %s" % time.time()) |
222 | sys.stdout.flush() | 212 | sys.stdout.flush() |
223 | 213 | ||
224 | self.inotify_threadlock = threading.Lock() | ||
225 | |||
226 | def init_configdata(self): | 214 | def init_configdata(self): |
227 | if not hasattr(self, "data"): | 215 | if not hasattr(self, "data"): |
228 | self.initConfigurationData() | 216 | self.initConfigurationData() |
@@ -230,42 +218,6 @@ class BBCooker: | |||
230 | sys.stdout.flush() | 218 | sys.stdout.flush() |
231 | self.handlePRServ() | 219 | self.handlePRServ() |
232 | 220 | ||
233 | def setupConfigWatcher(self): | ||
234 | with bb.utils.lock_timeout(self.inotify_threadlock): | ||
235 | if self.configwatcher: | ||
236 | self.configwatcher.close() | ||
237 | self.confignotifier = None | ||
238 | self.configwatcher = None | ||
239 | self.configwatcher = pyinotify.WatchManager() | ||
240 | self.configwatcher.bbseen = set() | ||
241 | self.configwatcher.bbwatchedfiles = set() | ||
242 | self.confignotifier = pyinotify.Notifier(self.configwatcher, self.config_notifications) | ||
243 | |||
244 | def setupParserWatcher(self): | ||
245 | with bb.utils.lock_timeout(self.inotify_threadlock): | ||
246 | if self.watcher: | ||
247 | self.watcher.close() | ||
248 | self.notifier = None | ||
249 | self.watcher = None | ||
250 | self.watcher = pyinotify.WatchManager() | ||
251 | self.watcher.bbseen = set() | ||
252 | self.watcher.bbwatchedfiles = set() | ||
253 | self.notifier = pyinotify.Notifier(self.watcher, self.notifications) | ||
254 | |||
255 | def process_inotify_updates(self): | ||
256 | with bb.utils.lock_timeout(self.inotify_threadlock): | ||
257 | for n in [self.confignotifier, self.notifier]: | ||
258 | if n and n.check_events(timeout=0): | ||
259 | # read notified events and enqueue them | ||
260 | n.read_events() | ||
261 | |||
262 | def process_inotify_updates_apply(self): | ||
263 | with bb.utils.lock_timeout(self.inotify_threadlock): | ||
264 | for n in [self.confignotifier, self.notifier]: | ||
265 | if n and n.check_events(timeout=0): | ||
266 | n.read_events() | ||
267 | n.process_events() | ||
268 | |||
269 | def _baseconfig_set(self, value): | 221 | def _baseconfig_set(self, value): |
270 | if value and not self.baseconfig_valid: | 222 | if value and not self.baseconfig_valid: |
271 | bb.server.process.serverlog("Base config valid") | 223 | bb.server.process.serverlog("Base config valid") |
@@ -280,88 +232,16 @@ class BBCooker: | |||
280 | bb.server.process.serverlog("Parse cache invalidated") | 232 | bb.server.process.serverlog("Parse cache invalidated") |
281 | self.parsecache_valid = value | 233 | self.parsecache_valid = value |
282 | 234 | ||
283 | def config_notifications(self, event): | 235 | def add_filewatch(self, deps, configwatcher=False): |
284 | if event.maskname == "IN_Q_OVERFLOW": | 236 | if configwatcher: |
285 | bb.warn("inotify event queue overflowed, invalidating caches.") | 237 | watcher = self.configwatched |
286 | self._parsecache_set(False) | 238 | else: |
287 | self._baseconfig_set(False) | 239 | watcher = self.parsewatched |
288 | bb.parse.clear_cache() | ||
289 | return | ||
290 | if not event.pathname in self.configwatcher.bbwatchedfiles: | ||
291 | return | ||
292 | if "IN_ISDIR" in event.maskname: | ||
293 | if "IN_CREATE" in event.maskname or "IN_DELETE" in event.maskname: | ||
294 | if event.pathname in self.configwatcher.bbseen: | ||
295 | self.configwatcher.bbseen.remove(event.pathname) | ||
296 | # Could remove all entries starting with the directory but for now... | ||
297 | bb.parse.clear_cache() | ||
298 | if not event.pathname in self.inotify_modified_files: | ||
299 | self.inotify_modified_files.append(event.pathname) | ||
300 | self._baseconfig_set(False) | ||
301 | |||
302 | def notifications(self, event): | ||
303 | if event.maskname == "IN_Q_OVERFLOW": | ||
304 | bb.warn("inotify event queue overflowed, invalidating caches.") | ||
305 | self._parsecache_set(False) | ||
306 | bb.parse.clear_cache() | ||
307 | return | ||
308 | if event.pathname.endswith("bitbake-cookerdaemon.log") \ | ||
309 | or event.pathname.endswith("bitbake.lock"): | ||
310 | return | ||
311 | if "IN_ISDIR" in event.maskname: | ||
312 | if "IN_CREATE" in event.maskname or "IN_DELETE" in event.maskname: | ||
313 | if event.pathname in self.watcher.bbseen: | ||
314 | self.watcher.bbseen.remove(event.pathname) | ||
315 | # Could remove all entries starting with the directory but for now... | ||
316 | bb.parse.clear_cache() | ||
317 | if not event.pathname in self.inotify_modified_files: | ||
318 | self.inotify_modified_files.append(event.pathname) | ||
319 | self._parsecache_set(False) | ||
320 | 240 | ||
321 | def add_filewatch(self, deps, watcher=None, dirs=False): | ||
322 | if not watcher: | ||
323 | watcher = self.watcher | ||
324 | for i in deps: | 241 | for i in deps: |
325 | watcher.bbwatchedfiles.add(i[0]) | 242 | f = i[0] |
326 | if dirs: | 243 | mtime = i[1] |
327 | f = i[0] | 244 | watcher[f] = mtime |
328 | else: | ||
329 | f = os.path.dirname(i[0]) | ||
330 | if f in watcher.bbseen: | ||
331 | continue | ||
332 | watcher.bbseen.add(f) | ||
333 | watchtarget = None | ||
334 | while True: | ||
335 | # We try and add watches for files that don't exist but if they did, would influence | ||
336 | # the parser. The parent directory of these files may not exist, in which case we need | ||
337 | # to watch any parent that does exist for changes. | ||
338 | try: | ||
339 | watcher.add_watch(f, self.watchmask, quiet=False) | ||
340 | if watchtarget: | ||
341 | watcher.bbwatchedfiles.add(watchtarget) | ||
342 | break | ||
343 | except pyinotify.WatchManagerError as e: | ||
344 | if 'ENOENT' in str(e): | ||
345 | watchtarget = f | ||
346 | f = os.path.dirname(f) | ||
347 | if f in watcher.bbseen: | ||
348 | break | ||
349 | watcher.bbseen.add(f) | ||
350 | continue | ||
351 | if 'ENOSPC' in str(e): | ||
352 | providerlog.error("No space left on device or exceeds fs.inotify.max_user_watches?") | ||
353 | providerlog.error("To check max_user_watches: sysctl -n fs.inotify.max_user_watches.") | ||
354 | providerlog.error("To modify max_user_watches: sysctl -n -w fs.inotify.max_user_watches=<value>.") | ||
355 | providerlog.error("Root privilege is required to modify max_user_watches.") | ||
356 | raise | ||
357 | |||
358 | def handle_inotify_updates(self): | ||
359 | # reload files for which we got notifications | ||
360 | for p in self.inotify_modified_files: | ||
361 | bb.parse.update_cache(p) | ||
362 | if p in bb.parse.BBHandler.cached_statements: | ||
363 | del bb.parse.BBHandler.cached_statements[p] | ||
364 | self.inotify_modified_files = [] | ||
365 | 245 | ||
366 | def sigterm_exception(self, signum, stackframe): | 246 | def sigterm_exception(self, signum, stackframe): |
367 | if signum == signal.SIGTERM: | 247 | if signum == signal.SIGTERM: |
@@ -392,8 +272,7 @@ class BBCooker: | |||
392 | if mod not in self.orig_sysmodules: | 272 | if mod not in self.orig_sysmodules: |
393 | del sys.modules[mod] | 273 | del sys.modules[mod] |
394 | 274 | ||
395 | self.handle_inotify_updates() | 275 | self.configwatched = {} |
396 | self.setupConfigWatcher() | ||
397 | 276 | ||
398 | # Need to preserve BB_CONSOLELOG over resets | 277 | # Need to preserve BB_CONSOLELOG over resets |
399 | consolelog = None | 278 | consolelog = None |
@@ -436,7 +315,7 @@ class BBCooker: | |||
436 | self.disableDataTracking() | 315 | self.disableDataTracking() |
437 | 316 | ||
438 | for mc in self.databuilder.mcdata.values(): | 317 | for mc in self.databuilder.mcdata.values(): |
439 | self.add_filewatch(mc.getVar("__base_depends", False), self.configwatcher) | 318 | self.add_filewatch(mc.getVar("__base_depends", False), configwatcher=True) |
440 | 319 | ||
441 | self._baseconfig_set(True) | 320 | self._baseconfig_set(True) |
442 | self._parsecache_set(False) | 321 | self._parsecache_set(False) |
@@ -486,6 +365,29 @@ class BBCooker: | |||
486 | if hasattr(self, "data"): | 365 | if hasattr(self, "data"): |
487 | self.data.disableTracking() | 366 | self.data.disableTracking() |
488 | 367 | ||
368 | def revalidateCaches(self): | ||
369 | bb.parse.clear_cache() | ||
370 | |||
371 | clean = True | ||
372 | for f in self.configwatched: | ||
373 | if not bb.parse.check_mtime(f, self.configwatched[f]): | ||
374 | bb.server.process.serverlog("Found %s changed, invalid cache" % f) | ||
375 | self._baseconfig_set(False) | ||
376 | self._parsecache_set(False) | ||
377 | clean = False | ||
378 | break | ||
379 | |||
380 | if clean: | ||
381 | for f in self.parsewatched: | ||
382 | if not bb.parse.check_mtime(f, self.parsewatched[f]): | ||
383 | bb.server.process.serverlog("Found %s changed, invalid cache" % f) | ||
384 | self._parsecache_set(False) | ||
385 | clean = False | ||
386 | break | ||
387 | |||
388 | if not clean: | ||
389 | bb.parse.BBHandler.cached_statements = {} | ||
390 | |||
489 | def parseConfiguration(self): | 391 | def parseConfiguration(self): |
490 | self.updateCacheSync() | 392 | self.updateCacheSync() |
491 | 393 | ||
@@ -566,6 +468,7 @@ class BBCooker: | |||
566 | # Now update all the variables not in the datastore to match | 468 | # Now update all the variables not in the datastore to match |
567 | self.configuration.env = environment | 469 | self.configuration.env = environment |
568 | 470 | ||
471 | self.revalidateCaches() | ||
569 | if not clean: | 472 | if not clean: |
570 | logger.debug("Base environment change, triggering reparse") | 473 | logger.debug("Base environment change, triggering reparse") |
571 | self.reset() | 474 | self.reset() |
@@ -1644,8 +1547,6 @@ class BBCooker: | |||
1644 | if self.state == state.running: | 1547 | if self.state == state.running: |
1645 | return | 1548 | return |
1646 | 1549 | ||
1647 | self.handle_inotify_updates() | ||
1648 | |||
1649 | if not self.baseconfig_valid: | 1550 | if not self.baseconfig_valid: |
1650 | logger.debug("Reloading base configuration data") | 1551 | logger.debug("Reloading base configuration data") |
1651 | self.initConfigurationData() | 1552 | self.initConfigurationData() |
@@ -1667,7 +1568,7 @@ class BBCooker: | |||
1667 | 1568 | ||
1668 | if self.state != state.parsing and not self.parsecache_valid: | 1569 | if self.state != state.parsing and not self.parsecache_valid: |
1669 | bb.server.process.serverlog("Parsing started") | 1570 | bb.server.process.serverlog("Parsing started") |
1670 | self.setupParserWatcher() | 1571 | self.parsewatched = {} |
1671 | 1572 | ||
1672 | bb.parse.siggen.reset(self.data) | 1573 | bb.parse.siggen.reset(self.data) |
1673 | self.parseConfiguration () | 1574 | self.parseConfiguration () |
@@ -1692,9 +1593,9 @@ class BBCooker: | |||
1692 | total_masked += masked | 1593 | total_masked += masked |
1693 | searchdirs |= set(search) | 1594 | searchdirs |= set(search) |
1694 | 1595 | ||
1695 | # Add inotify watches for directories searched for bb/bbappend files | 1596 | # Add mtimes for directories searched for bb/bbappend files |
1696 | for dirent in searchdirs: | 1597 | for dirent in searchdirs: |
1697 | self.add_filewatch([[dirent]], dirs=True) | 1598 | self.add_filewatch([(dirent, bb.parse.cached_mtime_noerror(dirent))]) |
1698 | 1599 | ||
1699 | self.parser = CookerParser(self, mcfilelist, total_masked) | 1600 | self.parser = CookerParser(self, mcfilelist, total_masked) |
1700 | self._parsecache_set(True) | 1601 | self._parsecache_set(True) |
@@ -1881,7 +1782,7 @@ class CookerCollectFiles(object): | |||
1881 | collectlog.error("no recipe files to build, check your BBPATH and BBFILES?") | 1782 | collectlog.error("no recipe files to build, check your BBPATH and BBFILES?") |
1882 | bb.event.fire(CookerExit(), eventdata) | 1783 | bb.event.fire(CookerExit(), eventdata) |
1883 | 1784 | ||
1884 | # We need to track where we look so that we can add inotify watches. There | 1785 | # We need to track where we look so that we can know when the cache is invalid. There |
1885 | # is no nice way to do this, this is horrid. We intercept the os.listdir() | 1786 | # is no nice way to do this, this is horrid. We intercept the os.listdir() |
1886 | # (or os.scandir() for python 3.6+) calls while we run glob(). | 1787 | # (or os.scandir() for python 3.6+) calls while we run glob(). |
1887 | origlistdir = os.listdir | 1788 | origlistdir = os.listdir |
diff --git a/bitbake/lib/bb/parse/__init__.py b/bitbake/lib/bb/parse/__init__.py index 4cd82f115b..a4358f1374 100644 --- a/bitbake/lib/bb/parse/__init__.py +++ b/bitbake/lib/bb/parse/__init__.py | |||
@@ -60,6 +60,14 @@ def cached_mtime_noerror(f): | |||
60 | return 0 | 60 | return 0 |
61 | return __mtime_cache[f] | 61 | return __mtime_cache[f] |
62 | 62 | ||
63 | def check_mtime(f, mtime): | ||
64 | try: | ||
65 | current_mtime = os.stat(f)[stat.ST_MTIME] | ||
66 | __mtime_cache[f] = current_mtime | ||
67 | except OSError: | ||
68 | current_mtime = 0 | ||
69 | return current_mtime == mtime | ||
70 | |||
63 | def update_mtime(f): | 71 | def update_mtime(f): |
64 | try: | 72 | try: |
65 | __mtime_cache[f] = os.stat(f)[stat.ST_MTIME] | 73 | __mtime_cache[f] = os.stat(f)[stat.ST_MTIME] |
diff --git a/bitbake/lib/bb/server/process.py b/bitbake/lib/bb/server/process.py index 40cb99bc97..993ae66279 100644 --- a/bitbake/lib/bb/server/process.py +++ b/bitbake/lib/bb/server/process.py | |||
@@ -410,12 +410,6 @@ class ProcessServer(): | |||
410 | nextsleep = 0.1 | 410 | nextsleep = 0.1 |
411 | fds = [] | 411 | fds = [] |
412 | 412 | ||
413 | try: | ||
414 | self.cooker.process_inotify_updates() | ||
415 | except Exception as exc: | ||
416 | serverlog("Exception %s in inofify updates broke the idle_thread, exiting" % traceback.format_exc()) | ||
417 | self.quit = True | ||
418 | |||
419 | with bb.utils.lock_timeout(self._idlefuncsLock): | 413 | with bb.utils.lock_timeout(self._idlefuncsLock): |
420 | items = list(self._idlefuns.items()) | 414 | items = list(self._idlefuns.items()) |
421 | 415 | ||
diff --git a/bitbake/lib/bb/tinfoil.py b/bitbake/lib/bb/tinfoil.py index 91fbf1b13e..2200caa54c 100644 --- a/bitbake/lib/bb/tinfoil.py +++ b/bitbake/lib/bb/tinfoil.py | |||
@@ -449,6 +449,12 @@ class Tinfoil: | |||
449 | self.run_actions(config_params) | 449 | self.run_actions(config_params) |
450 | self.recipes_parsed = True | 450 | self.recipes_parsed = True |
451 | 451 | ||
452 | def modified_files(self): | ||
453 | """ | ||
454 | Notify the server it needs to revalidate it's caches since the client has modified files | ||
455 | """ | ||
456 | self.run_command("revalidateCaches") | ||
457 | |||
452 | def run_command(self, command, *params, handle_events=True): | 458 | def run_command(self, command, *params, handle_events=True): |
453 | """ | 459 | """ |
454 | Run a command on the server (as implemented in bb.command). | 460 | Run a command on the server (as implemented in bb.command). |
diff --git a/bitbake/lib/bblayers/action.py b/bitbake/lib/bblayers/action.py index 0d7fd6edd1..a8f2699335 100644 --- a/bitbake/lib/bblayers/action.py +++ b/bitbake/lib/bblayers/action.py | |||
@@ -50,12 +50,14 @@ class ActionPlugin(LayerPlugin): | |||
50 | 50 | ||
51 | try: | 51 | try: |
52 | notadded, _ = bb.utils.edit_bblayers_conf(bblayers_conf, layerdirs, None) | 52 | notadded, _ = bb.utils.edit_bblayers_conf(bblayers_conf, layerdirs, None) |
53 | self.tinfoil.modified_files() | ||
53 | if not (args.force or notadded): | 54 | if not (args.force or notadded): |
54 | try: | 55 | try: |
55 | self.tinfoil.run_command('parseConfiguration') | 56 | self.tinfoil.run_command('parseConfiguration') |
56 | except (bb.tinfoil.TinfoilUIException, bb.BBHandledException): | 57 | except (bb.tinfoil.TinfoilUIException, bb.BBHandledException): |
57 | # Restore the back up copy of bblayers.conf | 58 | # Restore the back up copy of bblayers.conf |
58 | shutil.copy2(backup, bblayers_conf) | 59 | shutil.copy2(backup, bblayers_conf) |
60 | self.tinfoil.modified_files() | ||
59 | bb.fatal("Parse failure with the specified layer added, exiting.") | 61 | bb.fatal("Parse failure with the specified layer added, exiting.") |
60 | else: | 62 | else: |
61 | for item in notadded: | 63 | for item in notadded: |
@@ -81,6 +83,7 @@ class ActionPlugin(LayerPlugin): | |||
81 | layerdir = os.path.abspath(item) | 83 | layerdir = os.path.abspath(item) |
82 | layerdirs.append(layerdir) | 84 | layerdirs.append(layerdir) |
83 | (_, notremoved) = bb.utils.edit_bblayers_conf(bblayers_conf, None, layerdirs) | 85 | (_, notremoved) = bb.utils.edit_bblayers_conf(bblayers_conf, None, layerdirs) |
86 | self.tinfoil.modified_files() | ||
84 | if notremoved: | 87 | if notremoved: |
85 | for item in notremoved: | 88 | for item in notremoved: |
86 | sys.stderr.write("No layers matching %s found in BBLAYERS\n" % item) | 89 | sys.stderr.write("No layers matching %s found in BBLAYERS\n" % item) |
@@ -240,6 +243,9 @@ build results (as the layer priority order has effectively changed). | |||
240 | if not entry_found: | 243 | if not entry_found: |
241 | logger.warning("File %s does not match the flattened layer's BBFILES setting, you may need to edit conf/layer.conf or move the file elsewhere" % f1full) | 244 | logger.warning("File %s does not match the flattened layer's BBFILES setting, you may need to edit conf/layer.conf or move the file elsewhere" % f1full) |
242 | 245 | ||
246 | self.tinfoil.modified_files() | ||
247 | |||
248 | |||
243 | def get_file_layer(self, filename): | 249 | def get_file_layer(self, filename): |
244 | layerdir = self.get_file_layerdir(filename) | 250 | layerdir = self.get_file_layerdir(filename) |
245 | if layerdir: | 251 | if layerdir: |