blob: 0a21f1c2f8bec1e03b7bc08cc06234474fca139f [file] [log] [blame]
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001#
2# Copyright (C) 2003, 2004 Chris Larson
3# Copyright (C) 2003, 2004 Phil Blundell
4# Copyright (C) 2003 - 2005 Michael 'Mickey' Lauer
5# Copyright (C) 2005 Holger Hans Peter Freyther
6# Copyright (C) 2005 ROAD GmbH
7# Copyright (C) 2006 - 2007 Richard Purdie
8#
Brad Bishopc342db32019-05-15 21:57:59 -04009# SPDX-License-Identifier: GPL-2.0-only
Patrick Williamsc124f4f2015-09-15 14:41:29 -050010#
Patrick Williamsc0f7c042017-02-23 20:41:17 -060011
Patrick Williamsc124f4f2015-09-15 14:41:29 -050012import sys, os, glob, os.path, re, time
Patrick Williamsc124f4f2015-09-15 14:41:29 -050013import itertools
14import logging
15import multiprocessing
Patrick Williamsc124f4f2015-09-15 14:41:29 -050016import threading
Patrick Williamsc0f7c042017-02-23 20:41:17 -060017from io import StringIO, UnsupportedOperation
Patrick Williamsc124f4f2015-09-15 14:41:29 -050018from contextlib import closing
Patrick Williamsc0f7c042017-02-23 20:41:17 -060019from collections import defaultdict, namedtuple
Patrick Williamsc124f4f2015-09-15 14:41:29 -050020import bb, bb.exceptions, bb.command
21from bb import utils, data, parse, event, cache, providers, taskdata, runqueue, build
Patrick Williamsc0f7c042017-02-23 20:41:17 -060022import queue
Patrick Williamsc124f4f2015-09-15 14:41:29 -050023import signal
Patrick Williamsc124f4f2015-09-15 14:41:29 -050024import prserv.serv
25import pyinotify
Patrick Williamsc0f7c042017-02-23 20:41:17 -060026import json
27import pickle
28import codecs
Brad Bishop08902b02019-08-20 09:16:51 -040029import hashserv
Patrick Williamsc124f4f2015-09-15 14:41:29 -050030
31logger = logging.getLogger("BitBake")
32collectlog = logging.getLogger("BitBake.Collection")
33buildlog = logging.getLogger("BitBake.Build")
34parselog = logging.getLogger("BitBake.Parsing")
35providerlog = logging.getLogger("BitBake.Provider")
36
37class NoSpecificMatch(bb.BBHandledException):
38 """
39 Exception raised when no or multiple file matches are found
40 """
41
42class NothingToBuild(Exception):
43 """
44 Exception raised when there is nothing to build
45 """
46
47class CollectionError(bb.BBHandledException):
48 """
49 Exception raised when layer configuration is incorrect
50 """
51
52class state:
Patrick Williamsc0f7c042017-02-23 20:41:17 -060053 initial, parsing, running, shutdown, forceshutdown, stopped, error = list(range(7))
Patrick Williamsc124f4f2015-09-15 14:41:29 -050054
Patrick Williamsd8c66bc2016-06-20 12:57:21 -050055 @classmethod
56 def get_name(cls, code):
57 for name in dir(cls):
58 value = getattr(cls, name)
59 if type(value) == type(cls.initial) and value == code:
60 return name
61 raise ValueError("Invalid status code: %s" % code)
62
Patrick Williamsc124f4f2015-09-15 14:41:29 -050063
64class SkippedPackage:
65 def __init__(self, info = None, reason = None):
66 self.pn = None
67 self.skipreason = None
68 self.provides = None
69 self.rprovides = None
70
71 if info:
72 self.pn = info.pn
73 self.skipreason = info.skipreason
74 self.provides = info.provides
Andrew Geisslerd1e89492021-02-12 15:35:20 -060075 self.rprovides = info.packages + info.rprovides
76 for package in info.packages:
77 self.rprovides += info.rprovides_pkg[package]
Patrick Williamsc124f4f2015-09-15 14:41:29 -050078 elif reason:
79 self.skipreason = reason
80
81
82class CookerFeatures(object):
Andrew Geissler517393d2023-01-13 08:55:19 -060083 _feature_list = [HOB_EXTRA_CACHES, BASEDATASTORE_TRACKING, SEND_SANITYEVENTS, RECIPE_SIGGEN_INFO] = list(range(4))
Patrick Williamsc124f4f2015-09-15 14:41:29 -050084
85 def __init__(self):
86 self._features=set()
87
88 def setFeature(self, f):
89 # validate we got a request for a feature we support
90 if f not in CookerFeatures._feature_list:
91 return
92 self._features.add(f)
93
94 def __contains__(self, f):
95 return f in self._features
96
97 def __iter__(self):
98 return self._features.__iter__()
99
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600100 def __next__(self):
101 return next(self._features)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500102
103
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600104class EventWriter:
105 def __init__(self, cooker, eventfile):
106 self.file_inited = None
107 self.cooker = cooker
108 self.eventfile = eventfile
109 self.event_queue = []
110
111 def write_event(self, event):
112 with open(self.eventfile, "a") as f:
113 try:
114 str_event = codecs.encode(pickle.dumps(event), 'base64').decode('utf-8')
115 f.write("%s\n" % json.dumps({"class": event.__module__ + "." + event.__class__.__name__,
116 "vars": str_event}))
117 except Exception as err:
118 import traceback
119 print(err, traceback.format_exc())
120
121 def send(self, event):
122 if self.file_inited:
123 # we have the file, just write the event
124 self.write_event(event)
125 else:
126 # init on bb.event.BuildStarted
127 name = "%s.%s" % (event.__module__, event.__class__.__name__)
128 if name in ("bb.event.BuildStarted", "bb.cooker.CookerExit"):
129 with open(self.eventfile, "w") as f:
130 f.write("%s\n" % json.dumps({ "allvariables" : self.cooker.getAllKeysWithFlags(["doc", "func"])}))
131
132 self.file_inited = True
133
134 # write pending events
135 for evt in self.event_queue:
136 self.write_event(evt)
137
138 # also write the current event
139 self.write_event(event)
140 else:
141 # queue all events until the file is inited
142 self.event_queue.append(event)
143
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500144#============================================================================#
145# BBCooker
146#============================================================================#
147class BBCooker:
148 """
149 Manages one bitbake build run
150 """
151
Andrew Geissler517393d2023-01-13 08:55:19 -0600152 def __init__(self, featureSet=None, server=None):
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600153 self.recipecaches = None
Andrew Geissler028142b2023-05-05 11:29:21 -0500154 self.baseconfig_valid = False
155 self.parsecache_valid = False
Andrew Geisslerc9f78652020-09-18 14:11:35 -0500156 self.eventlog = None
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500157 self.skiplist = {}
158 self.featureset = CookerFeatures()
159 if featureSet:
160 for f in featureSet:
161 self.featureset.setFeature(f)
162
Patrick Williams45852732022-04-02 08:58:32 -0500163 self.orig_syspath = sys.path.copy()
164 self.orig_sysmodules = [*sys.modules]
165
Andrew Geisslerc9f78652020-09-18 14:11:35 -0500166 self.configuration = bb.cookerdata.CookerConfiguration()
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500167
Andrew Geissler517393d2023-01-13 08:55:19 -0600168 self.process_server = server
169 self.idleCallBackRegister = None
170 self.waitIdle = None
171 if server:
172 self.idleCallBackRegister = server.register_idle_function
173 self.waitIdle = server.wait_for_idle
Andrew Geissler635e0e42020-08-21 15:58:33 -0500174
Brad Bishopf058f492019-01-28 23:50:33 -0500175 bb.debug(1, "BBCooker starting %s" % time.time())
176 sys.stdout.flush()
177
Patrick Williamsde0582f2022-04-08 10:23:27 -0500178 self.configwatcher = None
179 self.confignotifier = None
Brad Bishopf058f492019-01-28 23:50:33 -0500180
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500181 self.watchmask = pyinotify.IN_CLOSE_WRITE | pyinotify.IN_CREATE | pyinotify.IN_DELETE | \
182 pyinotify.IN_DELETE_SELF | pyinotify.IN_MODIFY | pyinotify.IN_MOVE_SELF | \
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500183 pyinotify.IN_MOVED_FROM | pyinotify.IN_MOVED_TO
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500184
Patrick Williamsde0582f2022-04-08 10:23:27 -0500185 self.watcher = None
186 self.notifier = None
Brad Bishopf058f492019-01-28 23:50:33 -0500187
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500188 # If being called by something like tinfoil, we need to clean cached data
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500189 # which may now be invalid
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500190 bb.parse.clear_cache()
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500191 bb.parse.BBHandler.cached_statements = {}
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500192
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500193 self.ui_cmdline = None
Brad Bishop08902b02019-08-20 09:16:51 -0400194 self.hashserv = None
Brad Bishopa34c0302019-09-23 22:34:48 -0400195 self.hashservaddr = None
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500196
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500197 self.inotify_modified_files = []
198
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500199 # TOSTOP must not be set or our children will hang when they output
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600200 try:
201 fd = sys.stdout.fileno()
202 if os.isatty(fd):
203 import termios
204 tcattr = termios.tcgetattr(fd)
205 if tcattr[3] & termios.TOSTOP:
206 buildlog.info("The terminal had the TOSTOP bit set, clearing...")
207 tcattr[3] = tcattr[3] & ~termios.TOSTOP
208 termios.tcsetattr(fd, termios.TCSANOW, tcattr)
209 except UnsupportedOperation:
210 pass
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500211
Andrew Geissler517393d2023-01-13 08:55:19 -0600212 self.command = bb.command.Command(self, self.process_server)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500213 self.state = state.initial
214
215 self.parser = None
216
217 signal.signal(signal.SIGTERM, self.sigterm_exception)
218 # Let SIGHUP exit as SIGTERM
219 signal.signal(signal.SIGHUP, self.sigterm_exception)
220
Brad Bishopf058f492019-01-28 23:50:33 -0500221 bb.debug(1, "BBCooker startup complete %s" % time.time())
222 sys.stdout.flush()
223
Andrew Geissler517393d2023-01-13 08:55:19 -0600224 self.inotify_threadlock = threading.Lock()
225
Andrew Geisslerc9f78652020-09-18 14:11:35 -0500226 def init_configdata(self):
227 if not hasattr(self, "data"):
228 self.initConfigurationData()
229 bb.debug(1, "BBCooker parsed base configuration %s" % time.time())
230 sys.stdout.flush()
231 self.handlePRServ()
232
Patrick Williamsde0582f2022-04-08 10:23:27 -0500233 def setupConfigWatcher(self):
Andrew Geissler6aa7eec2023-03-03 12:41:14 -0600234 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)
Patrick Williamsde0582f2022-04-08 10:23:27 -0500243
244 def setupParserWatcher(self):
Andrew Geissler6aa7eec2023-03-03 12:41:14 -0600245 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)
Patrick Williamsde0582f2022-04-08 10:23:27 -0500254
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500255 def process_inotify_updates(self):
Andrew Geissler517393d2023-01-13 08:55:19 -0600256 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()
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500268
Andrew Geissler028142b2023-05-05 11:29:21 -0500269 def _baseconfig_set(self, value):
270 if value and not self.baseconfig_valid:
271 bb.server.process.serverlog("Base config valid")
272 elif not value and self.baseconfig_valid:
273 bb.server.process.serverlog("Base config invalidated")
274 self.baseconfig_valid = value
275
276 def _parsecache_set(self, value):
277 if value and not self.parsecache_valid:
278 bb.server.process.serverlog("Parse cache valid")
279 elif not value and self.parsecache_valid:
280 bb.server.process.serverlog("Parse cache invalidated")
281 self.parsecache_valid = value
282
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500283 def config_notifications(self, event):
Brad Bishop37a0e4d2017-12-04 01:01:44 -0500284 if event.maskname == "IN_Q_OVERFLOW":
285 bb.warn("inotify event queue overflowed, invalidating caches.")
Andrew Geissler028142b2023-05-05 11:29:21 -0500286 self._parsecache_set(False)
287 self._baseconfig_set(False)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500288 bb.parse.clear_cache()
Brad Bishop37a0e4d2017-12-04 01:01:44 -0500289 return
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500290 if not event.pathname in self.configwatcher.bbwatchedfiles:
291 return
Andrew Geissler9aee5002022-03-30 16:27:02 +0000292 if "IN_ISDIR" in event.maskname:
Patrick Williams45852732022-04-02 08:58:32 -0500293 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()
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500298 if not event.pathname in self.inotify_modified_files:
299 self.inotify_modified_files.append(event.pathname)
Andrew Geissler028142b2023-05-05 11:29:21 -0500300 self._baseconfig_set(False)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500301
302 def notifications(self, event):
Brad Bishop37a0e4d2017-12-04 01:01:44 -0500303 if event.maskname == "IN_Q_OVERFLOW":
304 bb.warn("inotify event queue overflowed, invalidating caches.")
Andrew Geissler028142b2023-05-05 11:29:21 -0500305 self._parsecache_set(False)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500306 bb.parse.clear_cache()
307 return
308 if event.pathname.endswith("bitbake-cookerdaemon.log") \
309 or event.pathname.endswith("bitbake.lock"):
Brad Bishop37a0e4d2017-12-04 01:01:44 -0500310 return
Andrew Geissler9aee5002022-03-30 16:27:02 +0000311 if "IN_ISDIR" in event.maskname:
Patrick Williams45852732022-04-02 08:58:32 -0500312 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()
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500317 if not event.pathname in self.inotify_modified_files:
318 self.inotify_modified_files.append(event.pathname)
Andrew Geissler028142b2023-05-05 11:29:21 -0500319 self._parsecache_set(False)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500320
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500321 def add_filewatch(self, deps, watcher=None, dirs=False):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500322 if not watcher:
323 watcher = self.watcher
324 for i in deps:
Andrew Geissler82c905d2020-04-13 13:39:40 -0500325 watcher.bbwatchedfiles.add(i[0])
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500326 if dirs:
327 f = i[0]
328 else:
329 f = os.path.dirname(i[0])
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500330 if f in watcher.bbseen:
331 continue
Andrew Geissler82c905d2020-04-13 13:39:40 -0500332 watcher.bbseen.add(f)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500333 watchtarget = None
334 while True:
335 # We try and add watches for files that don't exist but if they did, would influence
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500336 # the parser. The parent directory of these files may not exist, in which case we need
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500337 # to watch any parent that does exist for changes.
338 try:
339 watcher.add_watch(f, self.watchmask, quiet=False)
340 if watchtarget:
Andrew Geissler82c905d2020-04-13 13:39:40 -0500341 watcher.bbwatchedfiles.add(watchtarget)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500342 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
Andrew Geissler82c905d2020-04-13 13:39:40 -0500349 watcher.bbseen.add(f)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500350 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
Andrew Geissler6aa7eec2023-03-03 12:41:14 -0600358 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
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500366 def sigterm_exception(self, signum, stackframe):
367 if signum == signal.SIGTERM:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500368 bb.warn("Cooker received SIGTERM, shutting down...")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500369 elif signum == signal.SIGHUP:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500370 bb.warn("Cooker received SIGHUP, shutting down...")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500371 self.state = state.forceshutdown
Andrew Geissler6aa7eec2023-03-03 12:41:14 -0600372 bb.event._should_exit.set()
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500373
374 def setFeatures(self, features):
375 # we only accept a new feature set if we're in state initial, so we can reset without problems
376 if not self.state in [state.initial, state.shutdown, state.forceshutdown, state.stopped, state.error]:
377 raise Exception("Illegal state for feature set change")
378 original_featureset = list(self.featureset)
379 for feature in features:
380 self.featureset.setFeature(feature)
381 bb.debug(1, "Features set %s (was %s)" % (original_featureset, list(self.featureset)))
Andrew Geisslerc9f78652020-09-18 14:11:35 -0500382 if (original_featureset != list(self.featureset)) and self.state != state.error and hasattr(self, "data"):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500383 self.reset()
384
385 def initConfigurationData(self):
386
387 self.state = state.initial
388 self.caches_array = []
389
Patrick Williams45852732022-04-02 08:58:32 -0500390 sys.path = self.orig_syspath.copy()
391 for mod in [*sys.modules]:
392 if mod not in self.orig_sysmodules:
393 del sys.modules[mod]
394
Andrew Geissler6aa7eec2023-03-03 12:41:14 -0600395 self.handle_inotify_updates()
Patrick Williamsde0582f2022-04-08 10:23:27 -0500396 self.setupConfigWatcher()
397
Patrick Williamsf1e5d692016-03-30 15:21:19 -0500398 # Need to preserve BB_CONSOLELOG over resets
399 consolelog = None
400 if hasattr(self, "data"):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500401 consolelog = self.data.getVar("BB_CONSOLELOG")
Patrick Williamsf1e5d692016-03-30 15:21:19 -0500402
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500403 if CookerFeatures.BASEDATASTORE_TRACKING in self.featureset:
404 self.enableDataTracking()
405
Andrew Geissler517393d2023-01-13 08:55:19 -0600406 caches_name_array = ['bb.cache:CoreRecipeInfo']
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500407 # We hardcode all known cache types in a single place, here.
408 if CookerFeatures.HOB_EXTRA_CACHES in self.featureset:
Andrew Geissler517393d2023-01-13 08:55:19 -0600409 caches_name_array.append("bb.cache_extra:HobRecipeInfo")
410 if CookerFeatures.RECIPE_SIGGEN_INFO in self.featureset:
411 caches_name_array.append("bb.cache:SiggenRecipeInfo")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500412
413 # At least CoreRecipeInfo will be loaded, so caches_array will never be empty!
414 # This is the entry point, no further check needed!
415 for var in caches_name_array:
416 try:
417 module_name, cache_name = var.split(':')
418 module = __import__(module_name, fromlist=(cache_name,))
419 self.caches_array.append(getattr(module, cache_name))
420 except ImportError as exc:
421 logger.critical("Unable to import extra RecipeInfo '%s' from '%s': %s" % (cache_name, module_name, exc))
Andrew Geisslerc9f78652020-09-18 14:11:35 -0500422 raise bb.BBHandledException()
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500423
424 self.databuilder = bb.cookerdata.CookerDataBuilder(self.configuration, False)
425 self.databuilder.parseBaseConfiguration()
426 self.data = self.databuilder.data
427 self.data_hash = self.databuilder.data_hash
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500428 self.extraconfigdata = {}
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500429
Patrick Williamsf1e5d692016-03-30 15:21:19 -0500430 if consolelog:
431 self.data.setVar("BB_CONSOLELOG", consolelog)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500432
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500433 self.data.setVar('BB_CMDLINE', self.ui_cmdline)
434
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500435 if CookerFeatures.BASEDATASTORE_TRACKING in self.featureset:
436 self.disableDataTracking()
437
Brad Bishop15ae2502019-06-18 21:44:24 -0400438 for mc in self.databuilder.mcdata.values():
Brad Bishop15ae2502019-06-18 21:44:24 -0400439 self.add_filewatch(mc.getVar("__base_depends", False), self.configwatcher)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500440
Andrew Geissler028142b2023-05-05 11:29:21 -0500441 self._baseconfig_set(True)
442 self._parsecache_set(False)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500443
444 def handlePRServ(self):
445 # Setup a PR Server based on the new configuration
446 try:
447 self.prhost = prserv.serv.auto_start(self.data)
448 except prserv.serv.PRServiceConfigError as e:
Andrew Geisslerd159c7f2021-09-02 21:05:58 -0500449 bb.fatal("Unable to start PR Server, exiting, check the bitbake-cookerdaemon.log")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500450
Brad Bishopa34c0302019-09-23 22:34:48 -0400451 if self.data.getVar("BB_HASHSERVE") == "auto":
452 # Create a new hash server bound to a unix domain socket
Brad Bishop08902b02019-08-20 09:16:51 -0400453 if not self.hashserv:
454 dbfile = (self.data.getVar("PERSISTENT_DIR") or self.data.getVar("CACHE")) + "/hashserv.db"
Andrew Geissler595f6302022-01-24 19:11:47 +0000455 upstream = self.data.getVar("BB_HASHSERVE_UPSTREAM") or None
456 if upstream:
457 import socket
458 try:
459 sock = socket.create_connection(upstream.split(":"), 5)
460 sock.close()
461 except socket.error as e:
Andrew Geissler87f5cff2022-09-30 13:13:31 -0500462 bb.warn("BB_HASHSERVE_UPSTREAM is not valid, unable to connect hash equivalence server at '%s': %s"
Andrew Geissler595f6302022-01-24 19:11:47 +0000463 % (upstream, repr(e)))
464
Brad Bishopa34c0302019-09-23 22:34:48 -0400465 self.hashservaddr = "unix://%s/hashserve.sock" % self.data.getVar("TOPDIR")
Andrew Geissler5199d832021-09-24 16:47:35 -0500466 self.hashserv = hashserv.create_server(
467 self.hashservaddr,
468 dbfile,
469 sync=False,
Andrew Geissler595f6302022-01-24 19:11:47 +0000470 upstream=upstream,
Andrew Geissler5199d832021-09-24 16:47:35 -0500471 )
Patrick Williams213cb262021-08-07 19:21:33 -0500472 self.hashserv.serve_as_process()
Brad Bishop08902b02019-08-20 09:16:51 -0400473 for mc in self.databuilder.mcdata:
Andrew Geissler517393d2023-01-13 08:55:19 -0600474 self.databuilder.mcorigdata[mc].setVar("BB_HASHSERVE", self.hashservaddr)
Brad Bishopa34c0302019-09-23 22:34:48 -0400475 self.databuilder.mcdata[mc].setVar("BB_HASHSERVE", self.hashservaddr)
Brad Bishop08902b02019-08-20 09:16:51 -0400476
477 bb.parse.init_parser(self.data)
478
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500479 def enableDataTracking(self):
480 self.configuration.tracking = True
481 if hasattr(self, "data"):
482 self.data.enableTracking()
483
484 def disableDataTracking(self):
485 self.configuration.tracking = False
486 if hasattr(self, "data"):
487 self.data.disableTracking()
488
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500489 def parseConfiguration(self):
Andrew Geisslerd1e89492021-02-12 15:35:20 -0600490 self.updateCacheSync()
491
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500492 # Change nice level if we're asked to
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500493 nice = self.data.getVar("BB_NICE_LEVEL")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500494 if nice:
495 curnice = os.nice(0)
496 nice = int(nice) - curnice
497 buildlog.verbose("Renice to %s " % os.nice(nice))
498
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600499 if self.recipecaches:
500 del self.recipecaches
501 self.multiconfigs = self.databuilder.mcdata.keys()
502 self.recipecaches = {}
503 for mc in self.multiconfigs:
504 self.recipecaches[mc] = bb.cache.CacheData(self.caches_array)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500505
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500506 self.handleCollections(self.data.getVar("BBFILE_COLLECTIONS"))
Patrick Williamse760df82023-05-26 11:10:49 -0500507 self.collections = {}
508 for mc in self.multiconfigs:
509 self.collections[mc] = CookerCollectFiles(self.bbfile_config_priorities, mc)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500510
Andrew Geissler028142b2023-05-05 11:29:21 -0500511 self._parsecache_set(False)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500512
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500513 def updateConfigOpts(self, options, environment, cmdline):
514 self.ui_cmdline = cmdline
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500515 clean = True
516 for o in options:
517 if o in ['prefile', 'postfile']:
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500518 # Only these options may require a reparse
519 try:
520 if getattr(self.configuration, o) == options[o]:
521 # Value is the same, no need to mark dirty
522 continue
523 except AttributeError:
524 pass
Andrew Geisslerd1e89492021-02-12 15:35:20 -0600525 logger.debug("Marking as dirty due to '%s' option change to '%s'" % (o, options[o]))
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500526 print("Marking as dirty due to '%s' option change to '%s'" % (o, options[o]))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500527 clean = False
Andrew Geisslerc9f78652020-09-18 14:11:35 -0500528 if hasattr(self.configuration, o):
529 setattr(self.configuration, o, options[o])
530
531 if self.configuration.writeeventlog:
532 if self.eventlog and self.eventlog[0] != self.configuration.writeeventlog:
533 bb.event.unregister_UIHhandler(self.eventlog[1])
534 if not self.eventlog or self.eventlog[0] != self.configuration.writeeventlog:
535 # we log all events to a file if so directed
536 # register the log file writer as UI Handler
537 writer = EventWriter(self, self.configuration.writeeventlog)
538 EventLogWriteHandler = namedtuple('EventLogWriteHandler', ['event'])
539 self.eventlog = (self.configuration.writeeventlog, bb.event.register_UIHhandler(EventLogWriteHandler(writer)))
540
541 bb.msg.loggerDefaultLogLevel = self.configuration.default_loglevel
542 bb.msg.loggerDefaultDomains = self.configuration.debug_domains
543
544 if hasattr(self, "data"):
545 origenv = bb.data.init()
546 for k in environment:
547 origenv.setVar(k, environment[k])
548 self.data.setVar("BB_ORIGENV", origenv)
549
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500550 for k in bb.utils.approved_variables():
551 if k in environment and k not in self.configuration.env:
Andrew Geisslerd1e89492021-02-12 15:35:20 -0600552 logger.debug("Updating new environment variable %s to %s" % (k, environment[k]))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500553 self.configuration.env[k] = environment[k]
554 clean = False
555 if k in self.configuration.env and k not in environment:
Andrew Geisslerd1e89492021-02-12 15:35:20 -0600556 logger.debug("Updating environment variable %s (deleted)" % (k))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500557 del self.configuration.env[k]
558 clean = False
559 if k not in self.configuration.env and k not in environment:
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500560 continue
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500561 if environment[k] != self.configuration.env[k]:
Andrew Geisslerd1e89492021-02-12 15:35:20 -0600562 logger.debug("Updating environment variable %s from %s to %s" % (k, self.configuration.env[k], environment[k]))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500563 self.configuration.env[k] = environment[k]
564 clean = False
Andrew Geisslerc9f78652020-09-18 14:11:35 -0500565
566 # Now update all the variables not in the datastore to match
567 self.configuration.env = environment
568
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500569 if not clean:
Andrew Geisslerd1e89492021-02-12 15:35:20 -0600570 logger.debug("Base environment change, triggering reparse")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500571 self.reset()
572
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500573 def showVersions(self):
574
Andrew Geissler95ac1b82021-03-31 14:34:31 -0500575 (latest_versions, preferred_versions, required) = self.findProviders()
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500576
Andrew Geissler95ac1b82021-03-31 14:34:31 -0500577 logger.plain("%-35s %25s %25s %25s", "Recipe Name", "Latest Version", "Preferred Version", "Required Version")
578 logger.plain("%-35s %25s %25s %25s\n", "===========", "==============", "=================", "================")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500579
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500580 for p in sorted(self.recipecaches[''].pkg_pn):
Andrew Geissler95ac1b82021-03-31 14:34:31 -0500581 preferred = preferred_versions[p]
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500582 latest = latest_versions[p]
Andrew Geissler95ac1b82021-03-31 14:34:31 -0500583 requiredstr = ""
584 preferredstr = ""
585 if required[p]:
586 if preferred[0] is not None:
587 requiredstr = preferred[0][0] + ":" + preferred[0][1] + '-' + preferred[0][2]
588 else:
589 bb.fatal("REQUIRED_VERSION of package %s not available" % p)
590 else:
591 preferredstr = preferred[0][0] + ":" + preferred[0][1] + '-' + preferred[0][2]
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500592
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500593 lateststr = latest[0][0] + ":" + latest[0][1] + "-" + latest[0][2]
594
Andrew Geissler95ac1b82021-03-31 14:34:31 -0500595 if preferred == latest:
596 preferredstr = ""
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500597
Andrew Geissler95ac1b82021-03-31 14:34:31 -0500598 logger.plain("%-35s %25s %25s %25s", p, lateststr, preferredstr, requiredstr)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500599
600 def showEnvironment(self, buildfile=None, pkgs_to_build=None):
601 """
602 Show the outer or per-recipe environment
603 """
604 fn = None
605 envdata = None
Brad Bishop15ae2502019-06-18 21:44:24 -0400606 mc = ''
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500607 if not pkgs_to_build:
608 pkgs_to_build = []
609
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500610 orig_tracking = self.configuration.tracking
611 if not orig_tracking:
612 self.enableDataTracking()
613 self.reset()
Andrew Geissler9aee5002022-03-30 16:27:02 +0000614 # reset() resets to the UI requested value so we have to redo this
615 self.enableDataTracking()
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500616
Brad Bishop15ae2502019-06-18 21:44:24 -0400617 def mc_base(p):
618 if p.startswith('mc:'):
619 s = p.split(':')
620 if len(s) == 2:
621 return s[1]
622 return None
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500623
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500624 if buildfile:
625 # Parse the configuration here. We need to do it explicitly here since
626 # this showEnvironment() code path doesn't use the cache
627 self.parseConfiguration()
628
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600629 fn, cls, mc = bb.cache.virtualfn2realfn(buildfile)
Andrew Geissler5a43b432020-06-13 10:46:56 -0500630 fn = self.matchFile(fn, mc)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600631 fn = bb.cache.realfn2virtual(fn, cls, mc)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500632 elif len(pkgs_to_build) == 1:
Brad Bishop15ae2502019-06-18 21:44:24 -0400633 mc = mc_base(pkgs_to_build[0])
634 if not mc:
635 ignore = self.data.getVar("ASSUME_PROVIDED") or ""
636 if pkgs_to_build[0] in set(ignore.split()):
637 bb.fatal("%s is in ASSUME_PROVIDED" % pkgs_to_build[0])
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500638
Andrew Geissler7e0e3c02022-02-25 20:34:39 +0000639 taskdata, runlist = self.buildTaskData(pkgs_to_build, None, self.configuration.halt, allowincomplete=True)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500640
Brad Bishop15ae2502019-06-18 21:44:24 -0400641 mc = runlist[0][0]
642 fn = runlist[0][3]
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500643
644 if fn:
645 try:
Patrick Williamse760df82023-05-26 11:10:49 -0500646 layername = self.collections[mc].calc_bbfile_priority(fn)[2]
647 envdata = self.databuilder.parseRecipe(fn, self.collections[mc].get_file_appends(fn), layername)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500648 except Exception as e:
649 parselog.exception("Unable to read %s", fn)
650 raise
Brad Bishop15ae2502019-06-18 21:44:24 -0400651 else:
652 if not mc in self.databuilder.mcdata:
653 bb.fatal('Not multiconfig named "%s" found' % mc)
654 envdata = self.databuilder.mcdata[mc]
655 data.expandKeys(envdata)
656 parse.ast.runAnonFuncs(envdata)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500657
658 # Display history
659 with closing(StringIO()) as env:
660 self.data.inchistory.emit(env)
661 logger.plain(env.getvalue())
662
663 # emit variables and shell functions
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500664 with closing(StringIO()) as env:
665 data.emit_env(env, envdata, True)
666 logger.plain(env.getvalue())
667
Andrew Geissler7e0e3c02022-02-25 20:34:39 +0000668 # emit the metadata which isn't valid shell
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500669 for e in sorted(envdata.keys()):
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600670 if envdata.getVarFlag(e, 'func', False) and envdata.getVarFlag(e, 'python', False):
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500671 logger.plain("\npython %s () {\n%s}\n", e, envdata.getVar(e, False))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500672
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500673 if not orig_tracking:
674 self.disableDataTracking()
675 self.reset()
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500676
Andrew Geissler7e0e3c02022-02-25 20:34:39 +0000677 def buildTaskData(self, pkgs_to_build, task, halt, allowincomplete=False):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500678 """
679 Prepare a runqueue and taskdata object for iteration over pkgs_to_build
680 """
681 bb.event.fire(bb.event.TreeDataPreparationStarted(), self.data)
682
683 # A task of None means use the default task
684 if task is None:
685 task = self.configuration.cmd
Brad Bishop37a0e4d2017-12-04 01:01:44 -0500686 if not task.startswith("do_"):
687 task = "do_%s" % task
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500688
Brad Bishop37a0e4d2017-12-04 01:01:44 -0500689 targetlist = self.checkPackages(pkgs_to_build, task)
690 fulltargetlist = []
691 defaulttask_implicit = ''
692 defaulttask_explicit = False
693 wildcard = False
694
695 # Wild card expansion:
Brad Bishop15ae2502019-06-18 21:44:24 -0400696 # Replace string such as "mc:*:bash"
697 # into "mc:A:bash mc:B:bash bash"
Brad Bishop37a0e4d2017-12-04 01:01:44 -0500698 for k in targetlist:
Andrew Geisslerd1e89492021-02-12 15:35:20 -0600699 if k.startswith("mc:") and k.count(':') >= 2:
Brad Bishop37a0e4d2017-12-04 01:01:44 -0500700 if wildcard:
701 bb.fatal('multiconfig conflict')
702 if k.split(":")[1] == "*":
703 wildcard = True
704 for mc in self.multiconfigs:
705 if mc:
706 fulltargetlist.append(k.replace('*', mc))
707 # implicit default task
708 else:
709 defaulttask_implicit = k.split(":")[2]
710 else:
711 fulltargetlist.append(k)
712 else:
713 defaulttask_explicit = True
714 fulltargetlist.append(k)
715
716 if not defaulttask_explicit and defaulttask_implicit != '':
717 fulltargetlist.append(defaulttask_implicit)
718
719 bb.debug(1,"Target list: %s" % (str(fulltargetlist)))
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600720 taskdata = {}
721 localdata = {}
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500722
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600723 for mc in self.multiconfigs:
Andrew Geissler7e0e3c02022-02-25 20:34:39 +0000724 taskdata[mc] = bb.taskdata.TaskData(halt, skiplist=self.skiplist, allowincomplete=allowincomplete)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600725 localdata[mc] = data.createCopy(self.databuilder.mcdata[mc])
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600726 bb.data.expandKeys(localdata[mc])
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500727
728 current = 0
729 runlist = []
730 for k in fulltargetlist:
Andrew Geisslerb7d28612020-07-24 16:15:54 -0500731 origk = k
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600732 mc = ""
Andrew Geisslerd1e89492021-02-12 15:35:20 -0600733 if k.startswith("mc:") and k.count(':') >= 2:
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600734 mc = k.split(":")[1]
735 k = ":".join(k.split(":")[2:])
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500736 ktask = task
737 if ":do_" in k:
738 k2 = k.split(":do_")
739 k = k2[0]
740 ktask = k2[1]
Andrew Geisslerb7d28612020-07-24 16:15:54 -0500741
742 if mc not in self.multiconfigs:
743 bb.fatal("Multiconfig dependency %s depends on nonexistent multiconfig configuration named %s" % (origk, mc))
744
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600745 taskdata[mc].add_provider(localdata[mc], self.recipecaches[mc], k)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500746 current += 1
747 if not ktask.startswith("do_"):
748 ktask = "do_%s" % ktask
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600749 if k not in taskdata[mc].build_targets or not taskdata[mc].build_targets[k]:
750 # e.g. in ASSUME_PROVIDED
751 continue
752 fn = taskdata[mc].build_targets[k][0]
753 runlist.append([mc, k, ktask, fn])
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500754 bb.event.fire(bb.event.TreeDataPreparationProgress(current, len(fulltargetlist)), self.data)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600755
Brad Bishop15ae2502019-06-18 21:44:24 -0400756 havemc = False
757 for mc in self.multiconfigs:
758 if taskdata[mc].get_mcdepends():
759 havemc = True
Brad Bishopf058f492019-01-28 23:50:33 -0500760
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800761 # No need to do check providers if there are no mcdeps or not an mc build
Brad Bishop15ae2502019-06-18 21:44:24 -0400762 if havemc or len(self.multiconfigs) > 1:
Andrew Geissler99467da2019-02-25 18:54:23 -0600763 seen = set()
764 new = True
765 # Make sure we can provide the multiconfig dependency
766 while new:
767 mcdeps = set()
768 # Add unresolved first, so we can get multiconfig indirect dependencies on time
769 for mc in self.multiconfigs:
770 taskdata[mc].add_unresolved(localdata[mc], self.recipecaches[mc])
771 mcdeps |= set(taskdata[mc].get_mcdepends())
772 new = False
Patrick Williams03907ee2022-05-01 06:28:52 -0500773 for k in mcdeps:
774 if k in seen:
775 continue
776 l = k.split(':')
777 depmc = l[2]
778 if depmc not in self.multiconfigs:
779 bb.fatal("Multiconfig dependency %s depends on nonexistent multiconfig configuration named configuration %s" % (k,depmc))
780 else:
781 logger.debug("Adding providers for multiconfig dependency %s" % l[3])
782 taskdata[depmc].add_provider(localdata[depmc], self.recipecaches[depmc], l[3])
783 seen.add(k)
784 new = True
Brad Bishopf058f492019-01-28 23:50:33 -0500785
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600786 for mc in self.multiconfigs:
787 taskdata[mc].add_unresolved(localdata[mc], self.recipecaches[mc])
788
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500789 bb.event.fire(bb.event.TreeDataPreparationCompleted(len(fulltargetlist)), self.data)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600790 return taskdata, runlist
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500791
792 def prepareTreeData(self, pkgs_to_build, task):
793 """
794 Prepare a runqueue and taskdata object for iteration over pkgs_to_build
795 """
796
Andrew Geissler7e0e3c02022-02-25 20:34:39 +0000797 # We set halt to False here to prevent unbuildable targets raising
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500798 # an exception when we're just generating data
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600799 taskdata, runlist = self.buildTaskData(pkgs_to_build, task, False, allowincomplete=True)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500800
801 return runlist, taskdata
802
803 ######## WARNING : this function requires cache_extra to be enabled ########
804
805 def generateTaskDepTreeData(self, pkgs_to_build, task):
806 """
807 Create a dependency graph of pkgs_to_build including reverse dependency
808 information.
809 """
Brad Bishop37a0e4d2017-12-04 01:01:44 -0500810 if not task.startswith("do_"):
811 task = "do_%s" % task
812
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500813 runlist, taskdata = self.prepareTreeData(pkgs_to_build, task)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600814 rq = bb.runqueue.RunQueue(self, self.data, self.recipecaches, taskdata, runlist)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500815 rq.rqdata.prepare()
816 return self.buildDependTree(rq, taskdata)
817
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600818 @staticmethod
819 def add_mc_prefix(mc, pn):
820 if mc:
Brad Bishop15ae2502019-06-18 21:44:24 -0400821 return "mc:%s:%s" % (mc, pn)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600822 return pn
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500823
824 def buildDependTree(self, rq, taskdata):
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600825 seen_fns = []
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500826 depend_tree = {}
827 depend_tree["depends"] = {}
828 depend_tree["tdepends"] = {}
829 depend_tree["pn"] = {}
830 depend_tree["rdepends-pn"] = {}
831 depend_tree["packages"] = {}
832 depend_tree["rdepends-pkg"] = {}
833 depend_tree["rrecs-pkg"] = {}
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500834 depend_tree['providermap'] = {}
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600835 depend_tree["layer-priorities"] = self.bbfile_config_priorities
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500836
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600837 for mc in taskdata:
838 for name, fn in list(taskdata[mc].get_providermap().items()):
839 pn = self.recipecaches[mc].pkg_fn[fn]
840 pn = self.add_mc_prefix(mc, pn)
841 if name != pn:
842 version = "%s:%s-%s" % self.recipecaches[mc].pkg_pepvpr[fn]
843 depend_tree['providermap'][name] = (pn, version)
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500844
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600845 for tid in rq.rqdata.runtaskentries:
846 (mc, fn, taskname, taskfn) = bb.runqueue.split_tid_mcfn(tid)
847 pn = self.recipecaches[mc].pkg_fn[taskfn]
848 pn = self.add_mc_prefix(mc, pn)
849 version = "%s:%s-%s" % self.recipecaches[mc].pkg_pepvpr[taskfn]
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500850 if pn not in depend_tree["pn"]:
851 depend_tree["pn"][pn] = {}
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600852 depend_tree["pn"][pn]["filename"] = taskfn
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500853 depend_tree["pn"][pn]["version"] = version
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600854 depend_tree["pn"][pn]["inherits"] = self.recipecaches[mc].inherits.get(taskfn, None)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500855
856 # if we have extra caches, list all attributes they bring in
857 extra_info = []
858 for cache_class in self.caches_array:
859 if type(cache_class) is type and issubclass(cache_class, bb.cache.RecipeInfoCommon) and hasattr(cache_class, 'cachefields'):
860 cachefields = getattr(cache_class, 'cachefields', [])
861 extra_info = extra_info + cachefields
862
863 # for all attributes stored, add them to the dependency tree
864 for ei in extra_info:
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600865 depend_tree["pn"][pn][ei] = vars(self.recipecaches[mc])[ei][taskfn]
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500866
867
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500868 dotname = "%s.%s" % (pn, bb.runqueue.taskname_from_tid(tid))
869 if not dotname in depend_tree["tdepends"]:
870 depend_tree["tdepends"][dotname] = []
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600871 for dep in rq.rqdata.runtaskentries[tid].depends:
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800872 (depmc, depfn, _, deptaskfn) = bb.runqueue.split_tid_mcfn(dep)
873 deppn = self.recipecaches[depmc].pkg_fn[deptaskfn]
Andrew Geissler595f6302022-01-24 19:11:47 +0000874 if depmc:
875 depmc = "mc:" + depmc + ":"
876 depend_tree["tdepends"][dotname].append("%s%s.%s" % (depmc, deppn, bb.runqueue.taskname_from_tid(dep)))
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600877 if taskfn not in seen_fns:
878 seen_fns.append(taskfn)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500879 packages = []
880
881 depend_tree["depends"][pn] = []
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600882 for dep in taskdata[mc].depids[taskfn]:
883 depend_tree["depends"][pn].append(dep)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500884
885 depend_tree["rdepends-pn"][pn] = []
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600886 for rdep in taskdata[mc].rdepids[taskfn]:
887 depend_tree["rdepends-pn"][pn].append(rdep)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500888
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600889 rdepends = self.recipecaches[mc].rundeps[taskfn]
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500890 for package in rdepends:
891 depend_tree["rdepends-pkg"][package] = []
892 for rdepend in rdepends[package]:
893 depend_tree["rdepends-pkg"][package].append(rdepend)
894 packages.append(package)
895
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600896 rrecs = self.recipecaches[mc].runrecs[taskfn]
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500897 for package in rrecs:
898 depend_tree["rrecs-pkg"][package] = []
899 for rdepend in rrecs[package]:
900 depend_tree["rrecs-pkg"][package].append(rdepend)
901 if not package in packages:
902 packages.append(package)
903
904 for package in packages:
905 if package not in depend_tree["packages"]:
906 depend_tree["packages"][package] = {}
907 depend_tree["packages"][package]["pn"] = pn
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600908 depend_tree["packages"][package]["filename"] = taskfn
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500909 depend_tree["packages"][package]["version"] = version
910
911 return depend_tree
912
913 ######## WARNING : this function requires cache_extra to be enabled ########
914 def generatePkgDepTreeData(self, pkgs_to_build, task):
915 """
916 Create a dependency tree of pkgs_to_build, returning the data.
917 """
Brad Bishop37a0e4d2017-12-04 01:01:44 -0500918 if not task.startswith("do_"):
919 task = "do_%s" % task
920
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500921 _, taskdata = self.prepareTreeData(pkgs_to_build, task)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500922
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600923 seen_fns = []
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500924 depend_tree = {}
925 depend_tree["depends"] = {}
926 depend_tree["pn"] = {}
927 depend_tree["rdepends-pn"] = {}
928 depend_tree["rdepends-pkg"] = {}
929 depend_tree["rrecs-pkg"] = {}
930
931 # if we have extra caches, list all attributes they bring in
932 extra_info = []
933 for cache_class in self.caches_array:
934 if type(cache_class) is type and issubclass(cache_class, bb.cache.RecipeInfoCommon) and hasattr(cache_class, 'cachefields'):
935 cachefields = getattr(cache_class, 'cachefields', [])
936 extra_info = extra_info + cachefields
937
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600938 tids = []
939 for mc in taskdata:
940 for tid in taskdata[mc].taskentries:
941 tids.append(tid)
942
943 for tid in tids:
944 (mc, fn, taskname, taskfn) = bb.runqueue.split_tid_mcfn(tid)
945
946 pn = self.recipecaches[mc].pkg_fn[taskfn]
947 pn = self.add_mc_prefix(mc, pn)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500948
949 if pn not in depend_tree["pn"]:
950 depend_tree["pn"][pn] = {}
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600951 depend_tree["pn"][pn]["filename"] = taskfn
952 version = "%s:%s-%s" % self.recipecaches[mc].pkg_pepvpr[taskfn]
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500953 depend_tree["pn"][pn]["version"] = version
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600954 rdepends = self.recipecaches[mc].rundeps[taskfn]
955 rrecs = self.recipecaches[mc].runrecs[taskfn]
956 depend_tree["pn"][pn]["inherits"] = self.recipecaches[mc].inherits.get(taskfn, None)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500957
958 # for all extra attributes stored, add them to the dependency tree
959 for ei in extra_info:
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600960 depend_tree["pn"][pn][ei] = vars(self.recipecaches[mc])[ei][taskfn]
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500961
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600962 if taskfn not in seen_fns:
963 seen_fns.append(taskfn)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500964
965 depend_tree["depends"][pn] = []
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500966 for dep in taskdata[mc].depids[taskfn]:
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500967 pn_provider = ""
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600968 if dep in taskdata[mc].build_targets and taskdata[mc].build_targets[dep]:
969 fn_provider = taskdata[mc].build_targets[dep][0]
970 pn_provider = self.recipecaches[mc].pkg_fn[fn_provider]
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500971 else:
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500972 pn_provider = dep
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600973 pn_provider = self.add_mc_prefix(mc, pn_provider)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500974 depend_tree["depends"][pn].append(pn_provider)
975
976 depend_tree["rdepends-pn"][pn] = []
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600977 for rdep in taskdata[mc].rdepids[taskfn]:
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500978 pn_rprovider = ""
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600979 if rdep in taskdata[mc].run_targets and taskdata[mc].run_targets[rdep]:
980 fn_rprovider = taskdata[mc].run_targets[rdep][0]
981 pn_rprovider = self.recipecaches[mc].pkg_fn[fn_rprovider]
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500982 else:
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600983 pn_rprovider = rdep
984 pn_rprovider = self.add_mc_prefix(mc, pn_rprovider)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500985 depend_tree["rdepends-pn"][pn].append(pn_rprovider)
986
987 depend_tree["rdepends-pkg"].update(rdepends)
988 depend_tree["rrecs-pkg"].update(rrecs)
989
990 return depend_tree
991
992 def generateDepTreeEvent(self, pkgs_to_build, task):
993 """
994 Create a task dependency graph of pkgs_to_build.
995 Generate an event with the result
996 """
997 depgraph = self.generateTaskDepTreeData(pkgs_to_build, task)
998 bb.event.fire(bb.event.DepTreeGenerated(depgraph), self.data)
999
1000 def generateDotGraphFiles(self, pkgs_to_build, task):
1001 """
1002 Create a task dependency graph of pkgs_to_build.
1003 Save the result to a set of .dot files.
1004 """
1005
1006 depgraph = self.generateTaskDepTreeData(pkgs_to_build, task)
1007
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001008 with open('pn-buildlist', 'w') as f:
1009 for pn in depgraph["pn"]:
1010 f.write(pn + "\n")
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001011 logger.info("PN build list saved to 'pn-buildlist'")
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001012
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001013 # Remove old format output files to ensure no confusion with stale data
1014 try:
1015 os.unlink('pn-depends.dot')
1016 except FileNotFoundError:
1017 pass
1018 try:
1019 os.unlink('package-depends.dot')
1020 except FileNotFoundError:
1021 pass
Brad Bishop79641f22019-09-10 07:20:22 -04001022 try:
1023 os.unlink('recipe-depends.dot')
1024 except FileNotFoundError:
1025 pass
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001026
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001027 with open('task-depends.dot', 'w') as f:
1028 f.write("digraph depends {\n")
Brad Bishop316dfdd2018-06-25 12:45:53 -04001029 for task in sorted(depgraph["tdepends"]):
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001030 (pn, taskname) = task.rsplit(".", 1)
1031 fn = depgraph["pn"][pn]["filename"]
1032 version = depgraph["pn"][pn]["version"]
1033 f.write('"%s.%s" [label="%s %s\\n%s\\n%s"]\n' % (pn, taskname, pn, taskname, version, fn))
Brad Bishop316dfdd2018-06-25 12:45:53 -04001034 for dep in sorted(depgraph["tdepends"][task]):
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001035 f.write('"%s" -> "%s"\n' % (task, dep))
1036 f.write("}\n")
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001037 logger.info("Task dependencies saved to 'task-depends.dot'")
1038
1039 def show_appends_with_no_recipes(self):
Andrew Geissler5a43b432020-06-13 10:46:56 -05001040 appends_without_recipes = {}
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001041 # Determine which bbappends haven't been applied
Andrew Geissler5a43b432020-06-13 10:46:56 -05001042 for mc in self.multiconfigs:
1043 # First get list of recipes, including skipped
1044 recipefns = list(self.recipecaches[mc].pkg_fn.keys())
1045 recipefns.extend(self.skiplist.keys())
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001046
Andrew Geissler5a43b432020-06-13 10:46:56 -05001047 # Work out list of bbappends that have been applied
1048 applied_appends = []
1049 for fn in recipefns:
1050 applied_appends.extend(self.collections[mc].get_file_appends(fn))
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001051
Andrew Geissler5a43b432020-06-13 10:46:56 -05001052 appends_without_recipes[mc] = []
1053 for _, appendfn in self.collections[mc].bbappends:
1054 if not appendfn in applied_appends:
1055 appends_without_recipes[mc].append(appendfn)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001056
Andrew Geissler5a43b432020-06-13 10:46:56 -05001057 msgs = []
1058 for mc in sorted(appends_without_recipes.keys()):
1059 if appends_without_recipes[mc]:
1060 msgs.append('No recipes in %s available for:\n %s' % (mc if mc else 'default',
1061 '\n '.join(appends_without_recipes[mc])))
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001062
Andrew Geissler5a43b432020-06-13 10:46:56 -05001063 if msgs:
1064 msg = "\n".join(msgs)
1065 warn_only = self.databuilder.mcdata[mc].getVar("BB_DANGLINGAPPENDS_WARNONLY", \
1066 False) or "no"
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001067 if warn_only.lower() in ("1", "yes", "true"):
1068 bb.warn(msg)
1069 else:
1070 bb.fatal(msg)
1071
1072 def handlePrefProviders(self):
1073
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001074 for mc in self.multiconfigs:
1075 localdata = data.createCopy(self.databuilder.mcdata[mc])
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001076 bb.data.expandKeys(localdata)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001077
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001078 # Handle PREFERRED_PROVIDERS
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001079 for p in (localdata.getVar('PREFERRED_PROVIDERS') or "").split():
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001080 try:
1081 (providee, provider) = p.split(':')
1082 except:
1083 providerlog.critical("Malformed option in PREFERRED_PROVIDERS variable: %s" % p)
1084 continue
1085 if providee in self.recipecaches[mc].preferred and self.recipecaches[mc].preferred[providee] != provider:
1086 providerlog.error("conflicting preferences for %s: both %s and %s specified", providee, provider, self.recipecaches[mc].preferred[providee])
1087 self.recipecaches[mc].preferred[providee] = provider
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001088
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001089 def findConfigFilePath(self, configfile):
1090 """
1091 Find the location on disk of configfile and if it exists and was parsed by BitBake
1092 emit the ConfigFilePathFound event with the path to the file.
1093 """
1094 path = bb.cookerdata.findConfigFile(configfile, self.data)
1095 if not path:
1096 return
1097
1098 # Generate a list of parsed configuration files by searching the files
1099 # listed in the __depends and __base_depends variables with a .conf suffix.
1100 conffiles = []
1101 dep_files = self.data.getVar('__base_depends', False) or []
1102 dep_files = dep_files + (self.data.getVar('__depends', False) or [])
1103
1104 for f in dep_files:
1105 if f[0].endswith(".conf"):
1106 conffiles.append(f[0])
1107
1108 _, conf, conffile = path.rpartition("conf/")
1109 match = os.path.join(conf, conffile)
1110 # Try and find matches for conf/conffilename.conf as we don't always
1111 # have the full path to the file.
1112 for cfg in conffiles:
1113 if cfg.endswith(match):
1114 bb.event.fire(bb.event.ConfigFilePathFound(path),
1115 self.data)
1116 break
1117
1118 def findFilesMatchingInDir(self, filepattern, directory):
1119 """
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001120 Searches for files containing the substring 'filepattern' which are children of
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001121 'directory' in each BBPATH. i.e. to find all rootfs package classes available
1122 to BitBake one could call findFilesMatchingInDir(self, 'rootfs_', 'classes')
1123 or to find all machine configuration files one could call:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001124 findFilesMatchingInDir(self, '.conf', 'conf/machine')
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001125 """
1126
1127 matches = []
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001128 bbpaths = self.data.getVar('BBPATH').split(':')
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001129 for path in bbpaths:
1130 dirpath = os.path.join(path, directory)
1131 if os.path.exists(dirpath):
1132 for root, dirs, files in os.walk(dirpath):
1133 for f in files:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001134 if filepattern in f:
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001135 matches.append(f)
1136
1137 if matches:
1138 bb.event.fire(bb.event.FilesMatchingFound(filepattern, matches), self.data)
1139
Patrick Williams93c203f2021-10-06 16:15:23 -05001140 def testCookerCommandEvent(self, filepattern):
1141 # Dummy command used by OEQA selftest to test tinfoil without IO
1142 matches = ["A", "B"]
1143 bb.event.fire(bb.event.FilesMatchingFound(filepattern, matches), self.data)
1144
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001145 def findProviders(self, mc=''):
Andrew Geissler82c905d2020-04-13 13:39:40 -05001146 return bb.providers.findProviders(self.databuilder.mcdata[mc], self.recipecaches[mc], self.recipecaches[mc].pkg_pn)
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001147
1148 def findBestProvider(self, pn, mc=''):
1149 if pn in self.recipecaches[mc].providers:
1150 filenames = self.recipecaches[mc].providers[pn]
Andrew Geissler82c905d2020-04-13 13:39:40 -05001151 eligible, foundUnique = bb.providers.filterProviders(filenames, pn, self.databuilder.mcdata[mc], self.recipecaches[mc])
Andrew Geissler95ac1b82021-03-31 14:34:31 -05001152 if eligible is not None:
1153 filename = eligible[0]
1154 else:
1155 filename = None
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001156 return None, None, None, filename
1157 elif pn in self.recipecaches[mc].pkg_pn:
Andrew Geissler95ac1b82021-03-31 14:34:31 -05001158 (latest, latest_f, preferred_ver, preferred_file, required) = bb.providers.findBestProvider(pn, self.databuilder.mcdata[mc], self.recipecaches[mc], self.recipecaches[mc].pkg_pn)
1159 if required and preferred_file is None:
1160 return None, None, None, None
1161 return (latest, latest_f, preferred_ver, preferred_file)
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001162 else:
1163 return None, None, None, None
1164
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001165 def findConfigFiles(self, varname):
1166 """
1167 Find config files which are appropriate values for varname.
1168 i.e. MACHINE, DISTRO
1169 """
1170 possible = []
1171 var = varname.lower()
1172
1173 data = self.data
1174 # iterate configs
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001175 bbpaths = data.getVar('BBPATH').split(':')
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001176 for path in bbpaths:
1177 confpath = os.path.join(path, "conf", var)
1178 if os.path.exists(confpath):
1179 for root, dirs, files in os.walk(confpath):
1180 # get all child files, these are appropriate values
1181 for f in files:
1182 val, sep, end = f.rpartition('.')
1183 if end == 'conf':
1184 possible.append(val)
1185
1186 if possible:
1187 bb.event.fire(bb.event.ConfigFilesFound(var, possible), self.data)
1188
1189 def findInheritsClass(self, klass):
1190 """
1191 Find all recipes which inherit the specified class
1192 """
1193 pkg_list = []
1194
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001195 for pfn in self.recipecaches[''].pkg_fn:
1196 inherits = self.recipecaches[''].inherits.get(pfn, None)
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001197 if inherits and klass in inherits:
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001198 pkg_list.append(self.recipecaches[''].pkg_fn[pfn])
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001199
1200 return pkg_list
1201
1202 def generateTargetsTree(self, klass=None, pkgs=None):
1203 """
1204 Generate a dependency tree of buildable targets
1205 Generate an event with the result
1206 """
1207 # if the caller hasn't specified a pkgs list default to universe
1208 if not pkgs:
1209 pkgs = ['universe']
1210 # if inherited_class passed ensure all recipes which inherit the
1211 # specified class are included in pkgs
1212 if klass:
1213 extra_pkgs = self.findInheritsClass(klass)
1214 pkgs = pkgs + extra_pkgs
1215
1216 # generate a dependency tree for all our packages
1217 tree = self.generatePkgDepTreeData(pkgs, 'build')
1218 bb.event.fire(bb.event.TargetsTreeGenerated(tree), self.data)
1219
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001220 def interactiveMode( self ):
1221 """Drop off into a shell"""
1222 try:
1223 from bb import shell
1224 except ImportError:
1225 parselog.exception("Interactive mode not available")
Andrew Geisslerc9f78652020-09-18 14:11:35 -05001226 raise bb.BBHandledException()
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001227 else:
1228 shell.start( self )
1229
1230
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001231 def handleCollections(self, collections):
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001232 """Handle collections"""
1233 errors = False
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001234 self.bbfile_config_priorities = []
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001235 if collections:
1236 collection_priorities = {}
1237 collection_depends = {}
1238 collection_list = collections.split()
1239 min_prio = 0
1240 for c in collection_list:
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001241 bb.debug(1,'Processing %s in collection list' % (c))
1242
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001243 # Get collection priority if defined explicitly
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001244 priority = self.data.getVar("BBFILE_PRIORITY_%s" % c)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001245 if priority:
1246 try:
1247 prio = int(priority)
1248 except ValueError:
1249 parselog.error("invalid value for BBFILE_PRIORITY_%s: \"%s\"", c, priority)
1250 errors = True
1251 if min_prio == 0 or prio < min_prio:
1252 min_prio = prio
1253 collection_priorities[c] = prio
1254 else:
1255 collection_priorities[c] = None
1256
1257 # Check dependencies and store information for priority calculation
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001258 deps = self.data.getVar("LAYERDEPENDS_%s" % c)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001259 if deps:
1260 try:
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001261 depDict = bb.utils.explode_dep_versions2(deps)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001262 except bb.utils.VersionStringException as vse:
1263 bb.fatal('Error parsing LAYERDEPENDS_%s: %s' % (c, str(vse)))
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001264 for dep, oplist in list(depDict.items()):
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001265 if dep in collection_list:
1266 for opstr in oplist:
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001267 layerver = self.data.getVar("LAYERVERSION_%s" % dep)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001268 (op, depver) = opstr.split()
1269 if layerver:
1270 try:
1271 res = bb.utils.vercmp_string_op(layerver, depver, op)
1272 except bb.utils.VersionStringException as vse:
1273 bb.fatal('Error parsing LAYERDEPENDS_%s: %s' % (c, str(vse)))
1274 if not res:
1275 parselog.error("Layer '%s' depends on version %s of layer '%s', but version %s is currently enabled in your configuration. Check that you are using the correct matching versions/branches of these two layers.", c, opstr, dep, layerver)
1276 errors = True
1277 else:
1278 parselog.error("Layer '%s' depends on version %s of layer '%s', which exists in your configuration but does not specify a version. Check that you are using the correct matching versions/branches of these two layers.", c, opstr, dep)
1279 errors = True
1280 else:
1281 parselog.error("Layer '%s' depends on layer '%s', but this layer is not enabled in your configuration", c, dep)
1282 errors = True
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001283 collection_depends[c] = list(depDict.keys())
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001284 else:
1285 collection_depends[c] = []
1286
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001287 # Check recommends and store information for priority calculation
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001288 recs = self.data.getVar("LAYERRECOMMENDS_%s" % c)
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001289 if recs:
1290 try:
1291 recDict = bb.utils.explode_dep_versions2(recs)
1292 except bb.utils.VersionStringException as vse:
1293 bb.fatal('Error parsing LAYERRECOMMENDS_%s: %s' % (c, str(vse)))
1294 for rec, oplist in list(recDict.items()):
1295 if rec in collection_list:
1296 if oplist:
1297 opstr = oplist[0]
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001298 layerver = self.data.getVar("LAYERVERSION_%s" % rec)
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001299 if layerver:
1300 (op, recver) = opstr.split()
1301 try:
1302 res = bb.utils.vercmp_string_op(layerver, recver, op)
1303 except bb.utils.VersionStringException as vse:
1304 bb.fatal('Error parsing LAYERRECOMMENDS_%s: %s' % (c, str(vse)))
1305 if not res:
Andrew Geissler87f5cff2022-09-30 13:13:31 -05001306 parselog.debug3("Layer '%s' recommends version %s of layer '%s', but version %s is currently enabled in your configuration. Check that you are using the correct matching versions/branches of these two layers.", c, opstr, rec, layerver)
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001307 continue
1308 else:
Andrew Geissler87f5cff2022-09-30 13:13:31 -05001309 parselog.debug3("Layer '%s' recommends version %s of layer '%s', which exists in your configuration but does not specify a version. Check that you are using the correct matching versions/branches of these two layers.", c, opstr, rec)
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001310 continue
Andrew Geissler87f5cff2022-09-30 13:13:31 -05001311 parselog.debug3("Layer '%s' recommends layer '%s', so we are adding it", c, rec)
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001312 collection_depends[c].append(rec)
1313 else:
Andrew Geissler87f5cff2022-09-30 13:13:31 -05001314 parselog.debug3("Layer '%s' recommends layer '%s', but this layer is not enabled in your configuration", c, rec)
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001315
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001316 # Recursively work out collection priorities based on dependencies
1317 def calc_layer_priority(collection):
1318 if not collection_priorities[collection]:
1319 max_depprio = min_prio
1320 for dep in collection_depends[collection]:
1321 calc_layer_priority(dep)
1322 depprio = collection_priorities[dep]
1323 if depprio > max_depprio:
1324 max_depprio = depprio
1325 max_depprio += 1
Andrew Geissler87f5cff2022-09-30 13:13:31 -05001326 parselog.debug("Calculated priority of layer %s as %d", collection, max_depprio)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001327 collection_priorities[collection] = max_depprio
1328
1329 # Calculate all layer priorities using calc_layer_priority and store in bbfile_config_priorities
1330 for c in collection_list:
1331 calc_layer_priority(c)
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001332 regex = self.data.getVar("BBFILE_PATTERN_%s" % c)
Andrew Geissler82c905d2020-04-13 13:39:40 -05001333 if regex is None:
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001334 parselog.error("BBFILE_PATTERN_%s not defined" % c)
1335 errors = True
1336 continue
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001337 elif regex == "":
Andrew Geissler87f5cff2022-09-30 13:13:31 -05001338 parselog.debug("BBFILE_PATTERN_%s is empty" % c)
Brad Bishop19323692019-04-05 15:28:33 -04001339 cre = re.compile('^NULL$')
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001340 errors = False
1341 else:
1342 try:
1343 cre = re.compile(regex)
1344 except re.error:
1345 parselog.error("BBFILE_PATTERN_%s \"%s\" is not a valid regular expression", c, regex)
1346 errors = True
1347 continue
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001348 self.bbfile_config_priorities.append((c, regex, cre, collection_priorities[c]))
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001349 if errors:
1350 # We've already printed the actual error(s)
1351 raise CollectionError("Errors during parsing layer configuration")
1352
1353 def buildSetVars(self):
1354 """
1355 Setup any variables needed before starting a build
1356 """
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001357 t = time.gmtime()
1358 for mc in self.databuilder.mcdata:
1359 ds = self.databuilder.mcdata[mc]
1360 if not ds.getVar("BUILDNAME", False):
1361 ds.setVar("BUILDNAME", "${DATE}${TIME}")
1362 ds.setVar("BUILDSTART", time.strftime('%m/%d/%Y %H:%M:%S', t))
1363 ds.setVar("DATE", time.strftime('%Y%m%d', t))
1364 ds.setVar("TIME", time.strftime('%H%M%S', t))
1365
1366 def reset_mtime_caches(self):
1367 """
1368 Reset mtime caches - this is particularly important when memory resident as something
1369 which is cached is not unlikely to have changed since the last invocation (e.g. a
1370 file associated with a recipe might have been modified by the user).
1371 """
1372 build.reset_cache()
1373 bb.fetch._checksum_cache.mtime_cache.clear()
1374 siggen_cache = getattr(bb.parse.siggen, 'checksum_cache', None)
1375 if siggen_cache:
1376 bb.parse.siggen.checksum_cache.mtime_cache.clear()
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001377
Andrew Geissler5a43b432020-06-13 10:46:56 -05001378 def matchFiles(self, bf, mc=''):
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001379 """
1380 Find the .bb files which match the expression in 'buildfile'.
1381 """
1382 if bf.startswith("/") or bf.startswith("../"):
1383 bf = os.path.abspath(bf)
1384
Patrick Williamse760df82023-05-26 11:10:49 -05001385 collections = {mc: CookerCollectFiles(self.bbfile_config_priorities, mc)}
1386 filelist, masked, searchdirs = collections[mc].collect_bbfiles(self.databuilder.mcdata[mc], self.databuilder.mcdata[mc])
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001387 try:
1388 os.stat(bf)
1389 bf = os.path.abspath(bf)
1390 return [bf]
1391 except OSError:
1392 regexp = re.compile(bf)
1393 matches = []
1394 for f in filelist:
1395 if regexp.search(f) and os.path.isfile(f):
1396 matches.append(f)
1397 return matches
1398
Andrew Geissler5a43b432020-06-13 10:46:56 -05001399 def matchFile(self, buildfile, mc=''):
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001400 """
1401 Find the .bb file which matches the expression in 'buildfile'.
1402 Raise an error if multiple files
1403 """
Andrew Geissler5a43b432020-06-13 10:46:56 -05001404 matches = self.matchFiles(buildfile, mc)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001405 if len(matches) != 1:
1406 if matches:
1407 msg = "Unable to match '%s' to a specific recipe file - %s matches found:" % (buildfile, len(matches))
1408 if matches:
1409 for f in matches:
1410 msg += "\n %s" % f
1411 parselog.error(msg)
1412 else:
1413 parselog.error("Unable to find any recipe file matching '%s'" % buildfile)
1414 raise NoSpecificMatch
1415 return matches[0]
1416
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001417 def buildFile(self, buildfile, task):
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001418 """
1419 Build the file matching regexp buildfile
1420 """
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001421 bb.event.fire(bb.event.BuildInit(), self.data)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001422
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001423 # Too many people use -b because they think it's how you normally
1424 # specify a target to be built, so show a warning
1425 bb.warn("Buildfile specified, dependencies will not be handled. If this is not what you want, do not use -b / --buildfile.")
1426
1427 self.buildFileInternal(buildfile, task)
1428
1429 def buildFileInternal(self, buildfile, task, fireevents=True, quietlog=False):
1430 """
1431 Build the file matching regexp buildfile
1432 """
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001433
1434 # Parse the configuration here. We need to do it explicitly here since
1435 # buildFile() doesn't use the cache
1436 self.parseConfiguration()
1437
1438 # If we are told to do the None task then query the default task
Andrew Geissler82c905d2020-04-13 13:39:40 -05001439 if task is None:
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001440 task = self.configuration.cmd
Brad Bishop37a0e4d2017-12-04 01:01:44 -05001441 if not task.startswith("do_"):
1442 task = "do_%s" % task
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001443
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001444 fn, cls, mc = bb.cache.virtualfn2realfn(buildfile)
Andrew Geissler5a43b432020-06-13 10:46:56 -05001445 fn = self.matchFile(fn, mc)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001446
1447 self.buildSetVars()
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001448 self.reset_mtime_caches()
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001449
Andrew Geissler5a43b432020-06-13 10:46:56 -05001450 bb_caches = bb.cache.MulticonfigCache(self.databuilder, self.data_hash, self.caches_array)
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001451
Patrick Williamse760df82023-05-26 11:10:49 -05001452 layername = self.collections[mc].calc_bbfile_priority(fn)[2]
1453 infos = bb_caches[mc].parse(fn, self.collections[mc].get_file_appends(fn), layername)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001454 infos = dict(infos)
1455
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001456 fn = bb.cache.realfn2virtual(fn, cls, mc)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001457 try:
1458 info_array = infos[fn]
1459 except KeyError:
1460 bb.fatal("%s does not exist" % fn)
1461
1462 if info_array[0].skipped:
1463 bb.fatal("%s was skipped: %s" % (fn, info_array[0].skipreason))
1464
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001465 self.recipecaches[mc].add_from_recipeinfo(fn, info_array)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001466
1467 # Tweak some variables
1468 item = info_array[0].pn
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001469 self.recipecaches[mc].ignored_dependencies = set()
1470 self.recipecaches[mc].bbfile_priority[fn] = 1
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001471 self.configuration.limited_deps = True
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001472
1473 # Remove external dependencies
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001474 self.recipecaches[mc].task_deps[fn]['depends'] = {}
1475 self.recipecaches[mc].deps[fn] = []
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001476 self.recipecaches[mc].rundeps[fn] = defaultdict(list)
1477 self.recipecaches[mc].runrecs[fn] = defaultdict(list)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001478
Andrew Geissler517393d2023-01-13 08:55:19 -06001479 bb.parse.siggen.setup_datacache(self.recipecaches)
1480
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001481 # Invalidate task for target if force mode active
1482 if self.configuration.force:
1483 logger.verbose("Invalidate task %s, %s", task, fn)
Andrew Geissler517393d2023-01-13 08:55:19 -06001484 bb.parse.siggen.invalidate_task(task, fn)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001485
1486 # Setup taskdata structure
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001487 taskdata = {}
Andrew Geissler7e0e3c02022-02-25 20:34:39 +00001488 taskdata[mc] = bb.taskdata.TaskData(self.configuration.halt)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001489 taskdata[mc].add_provider(self.databuilder.mcdata[mc], self.recipecaches[mc], item)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001490
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001491 if quietlog:
1492 rqloglevel = bb.runqueue.logger.getEffectiveLevel()
1493 bb.runqueue.logger.setLevel(logging.WARNING)
1494
1495 buildname = self.databuilder.mcdata[mc].getVar("BUILDNAME")
1496 if fireevents:
1497 bb.event.fire(bb.event.BuildStarted(buildname, [item]), self.databuilder.mcdata[mc])
Andrew Geissler517393d2023-01-13 08:55:19 -06001498 bb.event.enable_heartbeat()
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001499
1500 # Execute the runqueue
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001501 runlist = [[mc, item, task, fn]]
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001502
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001503 rq = bb.runqueue.RunQueue(self, self.data, self.recipecaches, taskdata, runlist)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001504
Andrew Geissler7e0e3c02022-02-25 20:34:39 +00001505 def buildFileIdle(server, rq, halt):
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001506
1507 msg = None
1508 interrupted = 0
Andrew Geissler7e0e3c02022-02-25 20:34:39 +00001509 if halt or self.state == state.forceshutdown:
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001510 rq.finish_runqueue(True)
1511 msg = "Forced shutdown"
1512 interrupted = 2
1513 elif self.state == state.shutdown:
1514 rq.finish_runqueue(False)
1515 msg = "Stopped build"
1516 interrupted = 1
1517 failures = 0
1518 try:
1519 retval = rq.execute_runqueue()
1520 except runqueue.TaskFailure as exc:
1521 failures += len(exc.args)
1522 retval = False
1523 except SystemExit as exc:
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001524 if quietlog:
1525 bb.runqueue.logger.setLevel(rqloglevel)
Andrew Geissler517393d2023-01-13 08:55:19 -06001526 return bb.server.process.idleFinish(str(exc))
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001527
1528 if not retval:
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001529 if fireevents:
1530 bb.event.fire(bb.event.BuildCompleted(len(rq.rqdata.runtaskentries), buildname, item, failures, interrupted), self.databuilder.mcdata[mc])
Andrew Geissler517393d2023-01-13 08:55:19 -06001531 bb.event.disable_heartbeat()
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001532 # We trashed self.recipecaches above
Andrew Geissler028142b2023-05-05 11:29:21 -05001533 self._parsecache_set(False)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001534 self.configuration.limited_deps = False
1535 bb.parse.siggen.reset(self.data)
1536 if quietlog:
1537 bb.runqueue.logger.setLevel(rqloglevel)
Andrew Geissler517393d2023-01-13 08:55:19 -06001538 return bb.server.process.idleFinish(msg)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001539 if retval is True:
1540 return True
1541 return retval
1542
Andrew Geissler635e0e42020-08-21 15:58:33 -05001543 self.idleCallBackRegister(buildFileIdle, rq)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001544
1545 def buildTargets(self, targets, task):
1546 """
1547 Attempt to build the targets specified
1548 """
1549
Andrew Geissler7e0e3c02022-02-25 20:34:39 +00001550 def buildTargetsIdle(server, rq, halt):
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001551 msg = None
1552 interrupted = 0
Andrew Geissler7e0e3c02022-02-25 20:34:39 +00001553 if halt or self.state == state.forceshutdown:
Andrew Geissler6aa7eec2023-03-03 12:41:14 -06001554 bb.event._should_exit.set()
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001555 rq.finish_runqueue(True)
1556 msg = "Forced shutdown"
1557 interrupted = 2
1558 elif self.state == state.shutdown:
1559 rq.finish_runqueue(False)
1560 msg = "Stopped build"
1561 interrupted = 1
1562 failures = 0
1563 try:
1564 retval = rq.execute_runqueue()
1565 except runqueue.TaskFailure as exc:
1566 failures += len(exc.args)
1567 retval = False
1568 except SystemExit as exc:
Andrew Geissler517393d2023-01-13 08:55:19 -06001569 return bb.server.process.idleFinish(str(exc))
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001570
1571 if not retval:
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001572 try:
1573 for mc in self.multiconfigs:
1574 bb.event.fire(bb.event.BuildCompleted(len(rq.rqdata.runtaskentries), buildname, targets, failures, interrupted), self.databuilder.mcdata[mc])
1575 finally:
Andrew Geissler517393d2023-01-13 08:55:19 -06001576 bb.event.disable_heartbeat()
1577 return bb.server.process.idleFinish(msg)
1578
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001579 if retval is True:
1580 return True
1581 return retval
1582
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001583 self.reset_mtime_caches()
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001584 self.buildSetVars()
1585
Patrick Williamsf1e5d692016-03-30 15:21:19 -05001586 # If we are told to do the None task then query the default task
Andrew Geissler82c905d2020-04-13 13:39:40 -05001587 if task is None:
Patrick Williamsf1e5d692016-03-30 15:21:19 -05001588 task = self.configuration.cmd
1589
1590 if not task.startswith("do_"):
1591 task = "do_%s" % task
1592
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001593 packages = [target if ':' in target else '%s:%s' % (target, task) for target in targets]
1594
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001595 bb.event.fire(bb.event.BuildInit(packages), self.data)
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001596
Andrew Geissler7e0e3c02022-02-25 20:34:39 +00001597 taskdata, runlist = self.buildTaskData(targets, task, self.configuration.halt)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001598
1599 buildname = self.data.getVar("BUILDNAME", False)
Patrick Williamsf1e5d692016-03-30 15:21:19 -05001600
1601 # make targets to always look as <target>:do_<task>
1602 ntargets = []
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001603 for target in runlist:
1604 if target[0]:
Brad Bishop15ae2502019-06-18 21:44:24 -04001605 ntargets.append("mc:%s:%s:%s" % (target[0], target[1], target[2]))
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001606 ntargets.append("%s:%s" % (target[1], target[2]))
Patrick Williamsf1e5d692016-03-30 15:21:19 -05001607
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001608 for mc in self.multiconfigs:
1609 bb.event.fire(bb.event.BuildStarted(buildname, ntargets), self.databuilder.mcdata[mc])
Andrew Geissler517393d2023-01-13 08:55:19 -06001610 bb.event.enable_heartbeat()
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001611
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001612 rq = bb.runqueue.RunQueue(self, self.data, self.recipecaches, taskdata, runlist)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001613 if 'universe' in targets:
1614 rq.rqdata.warn_multi_bb = True
1615
Andrew Geissler635e0e42020-08-21 15:58:33 -05001616 self.idleCallBackRegister(buildTargetsIdle, rq)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001617
1618
1619 def getAllKeysWithFlags(self, flaglist):
1620 dump = {}
1621 for k in self.data.keys():
1622 try:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001623 expand = True
1624 flags = self.data.getVarFlags(k)
1625 if flags and "func" in flags and "python" in flags:
1626 expand = False
1627 v = self.data.getVar(k, expand)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001628 if not k.startswith("__") and not isinstance(v, bb.data_smart.DataSmart):
1629 dump[k] = {
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001630 'v' : str(v) ,
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001631 'history' : self.data.varhistory.variable(k),
1632 }
1633 for d in flaglist:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001634 if flags and d in flags:
1635 dump[k][d] = flags[d]
1636 else:
1637 dump[k][d] = None
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001638 except Exception as e:
1639 print(e)
1640 return dump
1641
1642
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001643 def updateCacheSync(self):
1644 if self.state == state.running:
1645 return
1646
Andrew Geissler6aa7eec2023-03-03 12:41:14 -06001647 self.handle_inotify_updates()
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001648
1649 if not self.baseconfig_valid:
Andrew Geisslerd1e89492021-02-12 15:35:20 -06001650 logger.debug("Reloading base configuration data")
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001651 self.initConfigurationData()
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001652 self.handlePRServ()
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001653
1654 # This is called for all async commands when self.state != running
1655 def updateCache(self):
1656 if self.state == state.running:
1657 return
1658
1659 if self.state in (state.shutdown, state.forceshutdown, state.error):
1660 if hasattr(self.parser, 'shutdown'):
Andrew Geissler9aee5002022-03-30 16:27:02 +00001661 self.parser.shutdown(clean=False)
Andrew Geisslerc9f78652020-09-18 14:11:35 -05001662 self.parser.final_cleanup()
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001663 raise bb.BBHandledException()
1664
1665 if self.state != state.parsing:
1666 self.updateCacheSync()
1667
1668 if self.state != state.parsing and not self.parsecache_valid:
Patrick Williamsde0582f2022-04-08 10:23:27 -05001669 self.setupParserWatcher()
1670
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001671 bb.parse.siggen.reset(self.data)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001672 self.parseConfiguration ()
1673 if CookerFeatures.SEND_SANITYEVENTS in self.featureset:
Brad Bishop37a0e4d2017-12-04 01:01:44 -05001674 for mc in self.multiconfigs:
1675 bb.event.fire(bb.event.SanityCheck(False), self.databuilder.mcdata[mc])
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001676
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001677 for mc in self.multiconfigs:
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001678 ignore = self.databuilder.mcdata[mc].getVar("ASSUME_PROVIDED") or ""
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001679 self.recipecaches[mc].ignored_dependencies = set(ignore.split())
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001680
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001681 for dep in self.configuration.extra_assume_provided:
1682 self.recipecaches[mc].ignored_dependencies.add(dep)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001683
Andrew Geissler5a43b432020-06-13 10:46:56 -05001684 mcfilelist = {}
1685 total_masked = 0
1686 searchdirs = set()
1687 for mc in self.multiconfigs:
Andrew Geissler5a43b432020-06-13 10:46:56 -05001688 (filelist, masked, search) = self.collections[mc].collect_bbfiles(self.databuilder.mcdata[mc], self.databuilder.mcdata[mc])
1689
1690 mcfilelist[mc] = filelist
1691 total_masked += masked
1692 searchdirs |= set(search)
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001693
1694 # Add inotify watches for directories searched for bb/bbappend files
1695 for dirent in searchdirs:
1696 self.add_filewatch([[dirent]], dirs=True)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001697
Andrew Geissler5a43b432020-06-13 10:46:56 -05001698 self.parser = CookerParser(self, mcfilelist, total_masked)
Andrew Geissler028142b2023-05-05 11:29:21 -05001699 self._parsecache_set(True)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001700
1701 self.state = state.parsing
1702
1703 if not self.parser.parse_next():
Andrew Geissler87f5cff2022-09-30 13:13:31 -05001704 collectlog.debug("parsing complete")
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001705 if self.parser.error:
1706 raise bb.BBHandledException()
1707 self.show_appends_with_no_recipes()
1708 self.handlePrefProviders()
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001709 for mc in self.multiconfigs:
Andrew Geisslerb7d28612020-07-24 16:15:54 -05001710 self.recipecaches[mc].bbfile_priority = self.collections[mc].collection_priorities(self.recipecaches[mc].pkg_fn, self.parser.mcfilelist[mc], self.data)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001711 self.state = state.running
1712
1713 # Send an event listing all stamps reachable after parsing
1714 # which the metadata may use to clean up stale data
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001715 for mc in self.multiconfigs:
1716 event = bb.event.ReachableStamps(self.recipecaches[mc].stamp)
1717 bb.event.fire(event, self.databuilder.mcdata[mc])
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001718 return None
1719
1720 return True
1721
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001722 def checkPackages(self, pkgs_to_build, task=None):
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001723
1724 # Return a copy, don't modify the original
1725 pkgs_to_build = pkgs_to_build[:]
1726
Andrew Geissler595f6302022-01-24 19:11:47 +00001727 if not pkgs_to_build:
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001728 raise NothingToBuild
1729
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001730 ignore = (self.data.getVar("ASSUME_PROVIDED") or "").split()
Andrew Geisslerb7d28612020-07-24 16:15:54 -05001731 for pkg in pkgs_to_build.copy():
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001732 if pkg in ignore:
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001733 parselog.warning("Explicit target \"%s\" is in ASSUME_PROVIDED, ignoring" % pkg)
Brad Bishop15ae2502019-06-18 21:44:24 -04001734 if pkg.startswith("multiconfig:"):
1735 pkgs_to_build.remove(pkg)
1736 pkgs_to_build.append(pkg.replace("multiconfig:", "mc:"))
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001737
1738 if 'world' in pkgs_to_build:
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001739 pkgs_to_build.remove('world')
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001740 for mc in self.multiconfigs:
1741 bb.providers.buildWorldTargetList(self.recipecaches[mc], task)
1742 for t in self.recipecaches[mc].world_target:
1743 if mc:
Brad Bishop15ae2502019-06-18 21:44:24 -04001744 t = "mc:" + mc + ":" + t
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001745 pkgs_to_build.append(t)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001746
1747 if 'universe' in pkgs_to_build:
Brad Bishop1a4b7ee2018-12-16 17:11:34 -08001748 parselog.verbnote("The \"universe\" target is only intended for testing and may produce errors.")
Andrew Geissler87f5cff2022-09-30 13:13:31 -05001749 parselog.debug("collating packages for \"universe\"")
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001750 pkgs_to_build.remove('universe')
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001751 for mc in self.multiconfigs:
1752 for t in self.recipecaches[mc].universe_target:
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001753 if task:
1754 foundtask = False
1755 for provider_fn in self.recipecaches[mc].providers[t]:
1756 if task in self.recipecaches[mc].task_deps[provider_fn]['tasks']:
1757 foundtask = True
1758 break
1759 if not foundtask:
1760 bb.debug(1, "Skipping %s for universe tasks as task %s doesn't exist" % (t, task))
1761 continue
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001762 if mc:
Brad Bishop15ae2502019-06-18 21:44:24 -04001763 t = "mc:" + mc + ":" + t
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001764 pkgs_to_build.append(t)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001765
1766 return pkgs_to_build
1767
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001768 def pre_serve(self):
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001769 return
1770
1771 def post_serve(self):
Andrew Geisslerc9f78652020-09-18 14:11:35 -05001772 self.shutdown(force=True)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001773 prserv.serv.auto_shutdown()
Patrick Williams45852732022-04-02 08:58:32 -05001774 if hasattr(bb.parse, "siggen"):
1775 bb.parse.siggen.exit()
Brad Bishop08902b02019-08-20 09:16:51 -04001776 if self.hashserv:
1777 self.hashserv.process.terminate()
1778 self.hashserv.process.join()
Andrew Geisslerc3d88e42020-10-02 09:45:00 -05001779 if hasattr(self, "data"):
1780 bb.event.fire(CookerExit(), self.data)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001781
Andrew Geissler517393d2023-01-13 08:55:19 -06001782 def shutdown(self, force=False):
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001783 if force:
1784 self.state = state.forceshutdown
Patrick Williams8e7b46e2023-05-01 14:19:06 -05001785 bb.event._should_exit.set()
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001786 else:
1787 self.state = state.shutdown
1788
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001789 if self.parser:
Andrew Geissler517393d2023-01-13 08:55:19 -06001790 self.parser.shutdown(clean=False)
Andrew Geisslerc9f78652020-09-18 14:11:35 -05001791 self.parser.final_cleanup()
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001792
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001793 def finishcommand(self):
Andrew Geissler517393d2023-01-13 08:55:19 -06001794 if hasattr(self.parser, 'shutdown'):
1795 self.parser.shutdown(clean=False)
1796 self.parser.final_cleanup()
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001797 self.state = state.initial
Andrew Geissler6aa7eec2023-03-03 12:41:14 -06001798 bb.event._should_exit.clear()
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001799
1800 def reset(self):
Patrick Williams45852732022-04-02 08:58:32 -05001801 if hasattr(bb.parse, "siggen"):
1802 bb.parse.siggen.exit()
Andrew Geissler517393d2023-01-13 08:55:19 -06001803 self.finishcommand()
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001804 self.initConfigurationData()
Brad Bishop08902b02019-08-20 09:16:51 -04001805 self.handlePRServ()
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001806
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001807 def clientComplete(self):
1808 """Called when the client is done using the server"""
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001809 self.finishcommand()
1810 self.extraconfigdata = {}
1811 self.command.reset()
Andrew Geisslerc9f78652020-09-18 14:11:35 -05001812 if hasattr(self, "data"):
1813 self.databuilder.reset()
1814 self.data = self.databuilder.data
Andrew Geissler517393d2023-01-13 08:55:19 -06001815 # In theory tinfoil could have modified the base data before parsing,
1816 # ideally need to track if anything did modify the datastore
Andrew Geissler028142b2023-05-05 11:29:21 -05001817 self._parsecache_set(False)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001818
1819class CookerExit(bb.event.Event):
1820 """
1821 Notify clients of the Cooker shutdown
1822 """
1823
1824 def __init__(self):
1825 bb.event.Event.__init__(self)
1826
1827
1828class CookerCollectFiles(object):
Andrew Geissler5a43b432020-06-13 10:46:56 -05001829 def __init__(self, priorities, mc=''):
1830 self.mc = mc
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001831 self.bbappends = []
Andrew Geissler7e0e3c02022-02-25 20:34:39 +00001832 # Priorities is a list of tuples, with the second element as the pattern.
Brad Bishop1a4b7ee2018-12-16 17:11:34 -08001833 # We need to sort the list with the longest pattern first, and so on to
1834 # the shortest. This allows nested layers to be properly evaluated.
1835 self.bbfile_config_priorities = sorted(priorities, key=lambda tup: tup[1], reverse=True)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001836
Andrew Geisslerb7d28612020-07-24 16:15:54 -05001837 def calc_bbfile_priority(self, filename):
Patrick Williamse760df82023-05-26 11:10:49 -05001838 for layername, _, regex, pri in self.bbfile_config_priorities:
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001839 if regex.match(filename):
Patrick Williamse760df82023-05-26 11:10:49 -05001840 return pri, regex, layername
1841 return 0, None, None
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001842
1843 def get_bbfiles(self):
1844 """Get list of default .bb files by reading out the current directory"""
1845 path = os.getcwd()
1846 contents = os.listdir(path)
1847 bbfiles = []
1848 for f in contents:
1849 if f.endswith(".bb"):
1850 bbfiles.append(os.path.abspath(os.path.join(path, f)))
1851 return bbfiles
1852
1853 def find_bbfiles(self, path):
1854 """Find all the .bb and .bbappend files in a directory"""
1855 found = []
1856 for dir, dirs, files in os.walk(path):
1857 for ignored in ('SCCS', 'CVS', '.svn'):
1858 if ignored in dirs:
1859 dirs.remove(ignored)
1860 found += [os.path.join(dir, f) for f in files if (f.endswith(['.bb', '.bbappend']))]
1861
1862 return found
1863
1864 def collect_bbfiles(self, config, eventdata):
1865 """Collect all available .bb build files"""
1866 masked = 0
1867
Andrew Geissler87f5cff2022-09-30 13:13:31 -05001868 collectlog.debug("collecting .bb files")
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001869
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001870 files = (config.getVar( "BBFILES") or "").split()
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001871
1872 # Sort files by priority
Andrew Geisslerb7d28612020-07-24 16:15:54 -05001873 files.sort( key=lambda fileitem: self.calc_bbfile_priority(fileitem)[0] )
Andrew Geisslerc9f78652020-09-18 14:11:35 -05001874 config.setVar("BBFILES_PRIORITIZED", " ".join(files))
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001875
Andrew Geissler595f6302022-01-24 19:11:47 +00001876 if not files:
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001877 files = self.get_bbfiles()
1878
Andrew Geissler595f6302022-01-24 19:11:47 +00001879 if not files:
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001880 collectlog.error("no recipe files to build, check your BBPATH and BBFILES?")
1881 bb.event.fire(CookerExit(), eventdata)
1882
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001883 # We need to track where we look so that we can add inotify watches. There
1884 # is no nice way to do this, this is horrid. We intercept the os.listdir()
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001885 # (or os.scandir() for python 3.6+) calls while we run glob().
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001886 origlistdir = os.listdir
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001887 if hasattr(os, 'scandir'):
1888 origscandir = os.scandir
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001889 searchdirs = []
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001890
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001891 def ourlistdir(d):
1892 searchdirs.append(d)
1893 return origlistdir(d)
1894
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001895 def ourscandir(d):
1896 searchdirs.append(d)
1897 return origscandir(d)
1898
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001899 os.listdir = ourlistdir
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001900 if hasattr(os, 'scandir'):
1901 os.scandir = ourscandir
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001902 try:
1903 # Can't use set here as order is important
1904 newfiles = []
1905 for f in files:
1906 if os.path.isdir(f):
1907 dirfiles = self.find_bbfiles(f)
1908 for g in dirfiles:
1909 if g not in newfiles:
1910 newfiles.append(g)
1911 else:
1912 globbed = glob.glob(f)
1913 if not globbed and os.path.exists(f):
1914 globbed = [f]
1915 # glob gives files in order on disk. Sort to be deterministic.
1916 for g in sorted(globbed):
1917 if g not in newfiles:
1918 newfiles.append(g)
1919 finally:
1920 os.listdir = origlistdir
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001921 if hasattr(os, 'scandir'):
1922 os.scandir = origscandir
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001923
1924 bbmask = config.getVar('BBMASK')
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001925
1926 if bbmask:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001927 # First validate the individual regular expressions and ignore any
1928 # that do not compile
1929 bbmasks = []
1930 for mask in bbmask.split():
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001931 # When constructing an older style single regex, it's possible for BBMASK
1932 # to end up beginning with '|', which matches and masks _everything_.
1933 if mask.startswith("|"):
Andrew Geissler82c905d2020-04-13 13:39:40 -05001934 collectlog.warning("BBMASK contains regular expression beginning with '|', fixing: %s" % mask)
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001935 mask = mask[1:]
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001936 try:
1937 re.compile(mask)
1938 bbmasks.append(mask)
Andrew Geissler78b72792022-06-14 06:47:25 -05001939 except re.error:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001940 collectlog.critical("BBMASK contains an invalid regular expression, ignoring: %s" % mask)
1941
1942 # Then validate the combined regular expressions. This should never
1943 # fail, but better safe than sorry...
1944 bbmask = "|".join(bbmasks)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001945 try:
1946 bbmask_compiled = re.compile(bbmask)
Andrew Geissler78b72792022-06-14 06:47:25 -05001947 except re.error:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001948 collectlog.critical("BBMASK is not a valid regular expression, ignoring: %s" % bbmask)
1949 bbmask = None
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001950
1951 bbfiles = []
1952 bbappend = []
1953 for f in newfiles:
1954 if bbmask and bbmask_compiled.search(f):
Andrew Geissler87f5cff2022-09-30 13:13:31 -05001955 collectlog.debug("skipping masked file %s", f)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001956 masked += 1
1957 continue
1958 if f.endswith('.bb'):
1959 bbfiles.append(f)
1960 elif f.endswith('.bbappend'):
1961 bbappend.append(f)
1962 else:
Andrew Geissler87f5cff2022-09-30 13:13:31 -05001963 collectlog.debug("skipping %s: unknown file extension", f)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001964
1965 # Build a list of .bbappend files for each .bb file
1966 for f in bbappend:
1967 base = os.path.basename(f).replace('.bbappend', '.bb')
1968 self.bbappends.append((base, f))
1969
1970 # Find overlayed recipes
1971 # bbfiles will be in priority order which makes this easy
1972 bbfile_seen = dict()
1973 self.overlayed = defaultdict(list)
1974 for f in reversed(bbfiles):
1975 base = os.path.basename(f)
1976 if base not in bbfile_seen:
1977 bbfile_seen[base] = f
1978 else:
1979 topfile = bbfile_seen[base]
1980 self.overlayed[topfile].append(f)
1981
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001982 return (bbfiles, masked, searchdirs)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001983
1984 def get_file_appends(self, fn):
1985 """
1986 Returns a list of .bbappend files to apply to fn
1987 """
1988 filelist = []
1989 f = os.path.basename(fn)
1990 for b in self.bbappends:
1991 (bbappend, filename) = b
1992 if (bbappend == f) or ('%' in bbappend and bbappend.startswith(f[:bbappend.index('%')])):
1993 filelist.append(filename)
Andrew Geissler5a43b432020-06-13 10:46:56 -05001994 return tuple(filelist)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001995
Andrew Geisslerb7d28612020-07-24 16:15:54 -05001996 def collection_priorities(self, pkgfns, fns, d):
1997 # Return the priorities of the entries in pkgfns
1998 # Also check that all the regexes in self.bbfile_config_priorities are used
1999 # (but to do that we need to ensure skipped recipes aren't counted, nor
2000 # collections in BBFILE_PATTERN_IGNORE_EMPTY)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002001
2002 priorities = {}
Andrew Geisslerb7d28612020-07-24 16:15:54 -05002003 seen = set()
2004 matched = set()
2005
2006 matched_regex = set()
2007 unmatched_regex = set()
2008 for _, _, regex, _ in self.bbfile_config_priorities:
2009 unmatched_regex.add(regex)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002010
2011 # Calculate priorities for each file
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002012 for p in pkgfns:
Patrick Williamsc0f7c042017-02-23 20:41:17 -06002013 realfn, cls, mc = bb.cache.virtualfn2realfn(p)
Patrick Williamse760df82023-05-26 11:10:49 -05002014 priorities[p], regex, _ = self.calc_bbfile_priority(realfn)
Andrew Geisslerb7d28612020-07-24 16:15:54 -05002015 if regex in unmatched_regex:
2016 matched_regex.add(regex)
2017 unmatched_regex.remove(regex)
2018 seen.add(realfn)
2019 if regex:
2020 matched.add(realfn)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002021
Andrew Geisslerb7d28612020-07-24 16:15:54 -05002022 if unmatched_regex:
2023 # Account for bbappend files
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002024 for b in self.bbappends:
2025 (bbfile, append) = b
Andrew Geisslerb7d28612020-07-24 16:15:54 -05002026 seen.add(append)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002027
Andrew Geisslerb7d28612020-07-24 16:15:54 -05002028 # Account for skipped recipes
2029 seen.update(fns)
2030
2031 seen.difference_update(matched)
2032
2033 def already_matched(fn):
2034 for regex in matched_regex:
2035 if regex.match(fn):
2036 return True
2037 return False
2038
2039 for unmatch in unmatched_regex.copy():
2040 for fn in seen:
2041 if unmatch.match(fn):
2042 # If the bbappend or file was already matched by another regex, skip it
2043 # e.g. for a layer within a layer, the outer regex could match, the inner
2044 # regex may match nothing and we should warn about that
2045 if already_matched(fn):
2046 continue
2047 unmatched_regex.remove(unmatch)
2048 break
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002049
2050 for collection, pattern, regex, _ in self.bbfile_config_priorities:
Andrew Geisslerb7d28612020-07-24 16:15:54 -05002051 if regex in unmatched_regex:
Brad Bishop6e60e8b2018-02-01 10:27:11 -05002052 if d.getVar('BBFILE_PATTERN_IGNORE_EMPTY_%s' % collection) != '1':
Andrew Geissler5a43b432020-06-13 10:46:56 -05002053 collectlog.warning("No bb files in %s matched BBFILE_PATTERN_%s '%s'" % (self.mc if self.mc else 'default',
2054 collection, pattern))
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002055
2056 return priorities
2057
2058class ParsingFailure(Exception):
2059 def __init__(self, realexception, recipe):
2060 self.realexception = realexception
2061 self.recipe = recipe
2062 Exception.__init__(self, realexception, recipe)
2063
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002064class Parser(multiprocessing.Process):
Andrew Geissler9aee5002022-03-30 16:27:02 +00002065 def __init__(self, jobs, results, quit, profile):
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002066 self.jobs = jobs
2067 self.results = results
2068 self.quit = quit
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002069 multiprocessing.Process.__init__(self)
2070 self.context = bb.utils.get_context().copy()
2071 self.handlers = bb.event.get_class_handlers().copy()
2072 self.profile = profile
Andrew Geissler9aee5002022-03-30 16:27:02 +00002073 self.queue_signals = False
2074 self.signal_received = []
2075 self.signal_threadlock = threading.Lock()
2076
2077 def catch_sig(self, signum, frame):
2078 if self.queue_signals:
2079 self.signal_received.append(signum)
2080 else:
2081 self.handle_sig(signum, frame)
2082
2083 def handle_sig(self, signum, frame):
2084 if signum == signal.SIGTERM:
2085 signal.signal(signal.SIGTERM, signal.SIG_DFL)
2086 os.kill(os.getpid(), signal.SIGTERM)
2087 elif signum == signal.SIGINT:
2088 signal.default_int_handler(signum, frame)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002089
2090 def run(self):
2091
2092 if not self.profile:
2093 self.realrun()
2094 return
2095
2096 try:
2097 import cProfile as profile
2098 except:
2099 import profile
2100 prof = profile.Profile()
2101 try:
2102 profile.Profile.runcall(prof, self.realrun)
2103 finally:
2104 logfile = "profile-parse-%s.log" % multiprocessing.current_process().name
2105 prof.dump_stats(logfile)
2106
2107 def realrun(self):
Andrew Geissler9aee5002022-03-30 16:27:02 +00002108 # Signal handling here is hard. We must not terminate any process or thread holding the write
2109 # lock for the event stream as it will not be released, ever, and things will hang.
2110 # Python handles signals in the main thread/process but they can be raised from any thread and
2111 # we want to defer processing of any SIGTERM/SIGINT signal until we're outside the critical section
2112 # and don't hold the lock (see server/process.py). We therefore always catch the signals (so any
2113 # new thread should also do so) and we defer handling but we handle with the local thread lock
2114 # held (a threading lock, not a multiprocessing one) so that no other thread in the process
2115 # can be in the critical section.
2116 signal.signal(signal.SIGTERM, self.catch_sig)
2117 signal.signal(signal.SIGHUP, signal.SIG_DFL)
2118 signal.signal(signal.SIGINT, self.catch_sig)
2119 bb.utils.set_process_name(multiprocessing.current_process().name)
2120 multiprocessing.util.Finalize(None, bb.codeparser.parser_cache_save, exitpriority=1)
2121 multiprocessing.util.Finalize(None, bb.fetch.fetcher_parse_save, exitpriority=1)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002122
2123 pending = []
Andrew Geissler517393d2023-01-13 08:55:19 -06002124 havejobs = True
Andrew Geissler9aee5002022-03-30 16:27:02 +00002125 try:
Andrew Geissler517393d2023-01-13 08:55:19 -06002126 while havejobs or pending:
2127 if self.quit.is_set():
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002128 break
Andrew Geissler9aee5002022-03-30 16:27:02 +00002129
Andrew Geissler517393d2023-01-13 08:55:19 -06002130 job = None
2131 try:
2132 job = self.jobs.pop()
2133 except IndexError:
2134 havejobs = False
2135 if job:
Andrew Geissler9aee5002022-03-30 16:27:02 +00002136 result = self.parse(*job)
2137 # Clear the siggen cache after parsing to control memory usage, its huge
2138 bb.parse.siggen.postparsing_clean_cache()
Andrew Geissler9aee5002022-03-30 16:27:02 +00002139 pending.append(result)
Andrew Geissler517393d2023-01-13 08:55:19 -06002140
2141 if pending:
2142 try:
2143 result = pending.pop()
2144 self.results.put(result, timeout=0.05)
2145 except queue.Full:
2146 pending.append(result)
Andrew Geissler9aee5002022-03-30 16:27:02 +00002147 finally:
2148 self.results.close()
2149 self.results.join_thread()
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002150
Patrick Williamse760df82023-05-26 11:10:49 -05002151 def parse(self, mc, cache, filename, appends, layername):
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002152 try:
Andrew Geissler82c905d2020-04-13 13:39:40 -05002153 origfilter = bb.event.LogHandler.filter
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05002154 # Record the filename we're parsing into any events generated
2155 def parse_filter(self, record):
2156 record.taskpid = bb.event.worker_pid
2157 record.fn = filename
2158 return True
2159
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002160 # Reset our environment and handlers to the original settings
2161 bb.utils.set_context(self.context.copy())
2162 bb.event.set_class_handlers(self.handlers.copy())
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05002163 bb.event.LogHandler.filter = parse_filter
2164
Patrick Williamse760df82023-05-26 11:10:49 -05002165 return True, mc, cache.parse(filename, appends, layername)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002166 except Exception as exc:
2167 tb = sys.exc_info()[2]
2168 exc.recipe = filename
2169 exc.traceback = list(bb.exceptions.extract_traceback(tb, context=3))
Andrew Geissler9aee5002022-03-30 16:27:02 +00002170 return True, None, exc
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002171 # Need to turn BaseExceptions into Exceptions here so we gracefully shutdown
2172 # and for example a worker thread doesn't just exit on its own in response to
2173 # a SystemExit event for example.
2174 except BaseException as exc:
Andrew Geissler9aee5002022-03-30 16:27:02 +00002175 return True, None, ParsingFailure(exc, filename)
Andrew Geissler82c905d2020-04-13 13:39:40 -05002176 finally:
2177 bb.event.LogHandler.filter = origfilter
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002178
2179class CookerParser(object):
Andrew Geissler5a43b432020-06-13 10:46:56 -05002180 def __init__(self, cooker, mcfilelist, masked):
2181 self.mcfilelist = mcfilelist
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002182 self.cooker = cooker
2183 self.cfgdata = cooker.data
2184 self.cfghash = cooker.data_hash
Patrick Williamsc0f7c042017-02-23 20:41:17 -06002185 self.cfgbuilder = cooker.databuilder
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002186
2187 # Accounting statistics
2188 self.parsed = 0
2189 self.cached = 0
2190 self.error = 0
2191 self.masked = masked
2192
2193 self.skipped = 0
2194 self.virtuals = 0
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002195
2196 self.current = 0
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002197 self.process_names = []
2198
Andrew Geissler5a43b432020-06-13 10:46:56 -05002199 self.bb_caches = bb.cache.MulticonfigCache(self.cfgbuilder, self.cfghash, cooker.caches_array)
2200 self.fromcache = set()
2201 self.willparse = set()
2202 for mc in self.cooker.multiconfigs:
2203 for filename in self.mcfilelist[mc]:
2204 appends = self.cooker.collections[mc].get_file_appends(filename)
Patrick Williamse760df82023-05-26 11:10:49 -05002205 layername = self.cooker.collections[mc].calc_bbfile_priority(filename)[2]
Andrew Geissler5a43b432020-06-13 10:46:56 -05002206 if not self.bb_caches[mc].cacheValid(filename, appends):
Patrick Williamse760df82023-05-26 11:10:49 -05002207 self.willparse.add((mc, self.bb_caches[mc], filename, appends, layername))
Andrew Geissler5a43b432020-06-13 10:46:56 -05002208 else:
Patrick Williamse760df82023-05-26 11:10:49 -05002209 self.fromcache.add((mc, self.bb_caches[mc], filename, appends, layername))
Andrew Geissler5a43b432020-06-13 10:46:56 -05002210
2211 self.total = len(self.fromcache) + len(self.willparse)
2212 self.toparse = len(self.willparse)
Patrick Williamsc0f7c042017-02-23 20:41:17 -06002213 self.progress_chunk = int(max(self.toparse / 100, 1))
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002214
Brad Bishop6e60e8b2018-02-01 10:27:11 -05002215 self.num_processes = min(int(self.cfgdata.getVar("BB_NUMBER_PARSE_THREADS") or
Andrew Geissler5a43b432020-06-13 10:46:56 -05002216 multiprocessing.cpu_count()), self.toparse)
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05002217
Andrew Geisslerc5535c92023-01-27 16:10:19 -06002218 bb.cache.SiggenRecipeInfo.reset()
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002219 self.start()
2220 self.haveshutdown = False
Andrew Geisslerc9f78652020-09-18 14:11:35 -05002221 self.syncthread = None
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002222
2223 def start(self):
2224 self.results = self.load_cached()
2225 self.processes = []
2226 if self.toparse:
2227 bb.event.fire(bb.event.ParseStarted(self.toparse), self.cfgdata)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002228
Andrew Geissler517393d2023-01-13 08:55:19 -06002229 self.parser_quit = multiprocessing.Event()
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002230 self.result_queue = multiprocessing.Queue()
Brad Bishop19323692019-04-05 15:28:33 -04002231
2232 def chunkify(lst,n):
2233 return [lst[i::n] for i in range(n)]
Andrew Geissler5a43b432020-06-13 10:46:56 -05002234 self.jobs = chunkify(list(self.willparse), self.num_processes)
Brad Bishop19323692019-04-05 15:28:33 -04002235
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002236 for i in range(0, self.num_processes):
Andrew Geissler9aee5002022-03-30 16:27:02 +00002237 parser = Parser(self.jobs[i], self.result_queue, self.parser_quit, self.cooker.configuration.profile)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002238 parser.start()
2239 self.process_names.append(parser.name)
2240 self.processes.append(parser)
2241
2242 self.results = itertools.chain(self.results, self.parse_generator())
2243
Patrick Williams8e7b46e2023-05-01 14:19:06 -05002244 def shutdown(self, clean=True, eventmsg="Parsing halted due to errors"):
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002245 if not self.toparse:
2246 return
2247 if self.haveshutdown:
2248 return
2249 self.haveshutdown = True
2250
2251 if clean:
2252 event = bb.event.ParseCompleted(self.cached, self.parsed,
2253 self.skipped, self.masked,
2254 self.virtuals, self.error,
2255 self.total)
2256
2257 bb.event.fire(event, self.cfgdata)
Andrew Geissler7e0e3c02022-02-25 20:34:39 +00002258 else:
Patrick Williams8e7b46e2023-05-01 14:19:06 -05002259 bb.event.fire(bb.event.ParseError(eventmsg), self.cfgdata)
Andrew Geissler9aee5002022-03-30 16:27:02 +00002260 bb.error("Parsing halted due to errors, see error messages above")
Andrew Geisslerc9f78652020-09-18 14:11:35 -05002261
Andrew Geisslerc5535c92023-01-27 16:10:19 -06002262 # Cleanup the queue before call process.join(), otherwise there might be
2263 # deadlocks.
2264 while True:
2265 try:
2266 self.result_queue.get(timeout=0.25)
2267 except queue.Empty:
2268 break
2269
Andrew Geissler517393d2023-01-13 08:55:19 -06002270 def sync_caches():
2271 for c in self.bb_caches.values():
2272 bb.cache.SiggenRecipeInfo.reset()
2273 c.sync()
2274
2275 self.syncthread = threading.Thread(target=sync_caches, name="SyncThread")
2276 self.syncthread.start()
2277
2278 self.parser_quit.set()
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002279
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002280 for process in self.processes:
Andrew Geissler9aee5002022-03-30 16:27:02 +00002281 process.join(0.5)
2282
2283 for process in self.processes:
2284 if process.exitcode is None:
2285 os.kill(process.pid, signal.SIGINT)
2286
2287 for process in self.processes:
2288 process.join(0.5)
2289
2290 for process in self.processes:
2291 if process.exitcode is None:
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002292 process.terminate()
Andrew Geissler9aee5002022-03-30 16:27:02 +00002293
2294 for process in self.processes:
2295 process.join()
2296 # Added in 3.7, cleans up zombies
2297 if hasattr(process, "close"):
2298 process.close()
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002299
Andrew Geisslerc5535c92023-01-27 16:10:19 -06002300 bb.codeparser.parser_cache_save()
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05002301 bb.codeparser.parser_cache_savemerge()
Andrew Geissler517393d2023-01-13 08:55:19 -06002302 bb.cache.SiggenRecipeInfo.reset()
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05002303 bb.fetch.fetcher_parse_done()
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002304 if self.cooker.configuration.profile:
2305 profiles = []
2306 for i in self.process_names:
2307 logfile = "profile-parse-%s.log" % i
2308 if os.path.exists(logfile):
2309 profiles.append(logfile)
2310
2311 pout = "profile-parse.log.processed"
2312 bb.utils.process_profilelog(profiles, pout = pout)
2313 print("Processed parsing statistics saved to %s" % (pout))
2314
Andrew Geisslerc9f78652020-09-18 14:11:35 -05002315 def final_cleanup(self):
2316 if self.syncthread:
2317 self.syncthread.join()
2318
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002319 def load_cached(self):
Patrick Williamse760df82023-05-26 11:10:49 -05002320 for mc, cache, filename, appends, layername in self.fromcache:
Andrew Geissler517393d2023-01-13 08:55:19 -06002321 infos = cache.loadCached(filename, appends)
2322 yield False, mc, infos
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002323
2324 def parse_generator(self):
Andrew Geissler595f6302022-01-24 19:11:47 +00002325 empty = False
2326 while self.processes or not empty:
2327 for process in self.processes.copy():
2328 if not process.is_alive():
2329 process.join()
2330 self.processes.remove(process)
2331
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002332 if self.parsed >= self.toparse:
2333 break
2334
2335 try:
2336 result = self.result_queue.get(timeout=0.25)
Patrick Williamsc0f7c042017-02-23 20:41:17 -06002337 except queue.Empty:
Andrew Geissler595f6302022-01-24 19:11:47 +00002338 empty = True
Andrew Geissler9aee5002022-03-30 16:27:02 +00002339 yield None, None, None
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002340 else:
Andrew Geissler595f6302022-01-24 19:11:47 +00002341 empty = False
Andrew Geissler9aee5002022-03-30 16:27:02 +00002342 yield result
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002343
Andrew Geissler595f6302022-01-24 19:11:47 +00002344 if not (self.parsed >= self.toparse):
2345 raise bb.parse.ParseError("Not all recipes parsed, parser thread killed/died? Exiting.", None)
2346
2347
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002348 def parse_next(self):
2349 result = []
2350 parsed = None
2351 try:
Andrew Geissler5a43b432020-06-13 10:46:56 -05002352 parsed, mc, result = next(self.results)
Andrew Geissler9aee5002022-03-30 16:27:02 +00002353 if isinstance(result, BaseException):
2354 # Turn exceptions back into exceptions
2355 raise result
2356 if parsed is None:
2357 # Timeout, loop back through the main loop
2358 return True
2359
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002360 except StopIteration:
2361 self.shutdown()
2362 return False
2363 except bb.BBHandledException as exc:
2364 self.error += 1
Andrew Geissler7e0e3c02022-02-25 20:34:39 +00002365 logger.debug('Failed to parse recipe: %s' % exc.recipe)
Andrew Geissler9aee5002022-03-30 16:27:02 +00002366 self.shutdown(clean=False)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002367 return False
2368 except ParsingFailure as exc:
2369 self.error += 1
2370 logger.error('Unable to parse %s: %s' %
2371 (exc.recipe, bb.exceptions.to_string(exc.realexception)))
Andrew Geissler9aee5002022-03-30 16:27:02 +00002372 self.shutdown(clean=False)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002373 return False
2374 except bb.parse.ParseError as exc:
2375 self.error += 1
2376 logger.error(str(exc))
Patrick Williams8e7b46e2023-05-01 14:19:06 -05002377 self.shutdown(clean=False, eventmsg=str(exc))
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002378 return False
2379 except bb.data_smart.ExpansionError as exc:
2380 self.error += 1
Patrick Williamsc0f7c042017-02-23 20:41:17 -06002381 bbdir = os.path.dirname(__file__) + os.sep
2382 etype, value, _ = sys.exc_info()
2383 tb = list(itertools.dropwhile(lambda e: e.filename.startswith(bbdir), exc.traceback))
2384 logger.error('ExpansionError during parsing %s', value.recipe,
2385 exc_info=(etype, value, tb))
Andrew Geissler9aee5002022-03-30 16:27:02 +00002386 self.shutdown(clean=False)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002387 return False
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002388 except Exception as exc:
2389 self.error += 1
2390 etype, value, tb = sys.exc_info()
2391 if hasattr(value, "recipe"):
Patrick Williamsc0f7c042017-02-23 20:41:17 -06002392 logger.error('Unable to parse %s' % value.recipe,
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002393 exc_info=(etype, value, exc.traceback))
2394 else:
2395 # Most likely, an exception occurred during raising an exception
2396 import traceback
2397 logger.error('Exception during parse: %s' % traceback.format_exc())
Andrew Geissler9aee5002022-03-30 16:27:02 +00002398 self.shutdown(clean=False)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002399 return False
2400
2401 self.current += 1
2402 self.virtuals += len(result)
2403 if parsed:
2404 self.parsed += 1
2405 if self.parsed % self.progress_chunk == 0:
2406 bb.event.fire(bb.event.ParseProgress(self.parsed, self.toparse),
2407 self.cfgdata)
2408 else:
2409 self.cached += 1
2410
2411 for virtualfn, info_array in result:
2412 if info_array[0].skipped:
2413 self.skipped += 1
2414 self.cooker.skiplist[virtualfn] = SkippedPackage(info_array[0])
Andrew Geissler5a43b432020-06-13 10:46:56 -05002415 self.bb_caches[mc].add_info(virtualfn, info_array, self.cooker.recipecaches[mc],
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002416 parsed=parsed, watcher = self.cooker.add_filewatch)
2417 return True
2418
2419 def reparse(self, filename):
Andrew Geissler517393d2023-01-13 08:55:19 -06002420 bb.cache.SiggenRecipeInfo.reset()
Andrew Geissler5a43b432020-06-13 10:46:56 -05002421 to_reparse = set()
2422 for mc in self.cooker.multiconfigs:
Patrick Williamse760df82023-05-26 11:10:49 -05002423 layername = self.cooker.collections[mc].calc_bbfile_priority(filename)[2]
2424 to_reparse.add((mc, filename, self.cooker.collections[mc].get_file_appends(filename), layername))
Andrew Geissler5a43b432020-06-13 10:46:56 -05002425
Patrick Williamse760df82023-05-26 11:10:49 -05002426 for mc, filename, appends, layername in to_reparse:
2427 infos = self.bb_caches[mc].parse(filename, appends, layername)
Andrew Geissler5a43b432020-06-13 10:46:56 -05002428 for vfn, info_array in infos:
2429 self.cooker.recipecaches[mc].add_from_recipeinfo(vfn, info_array)