blob: 064e3cae6e8d254241e1f06d3d3602b46f4cb1ee [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:
Andrew Geissler5082cc72023-09-11 08:41:39 -0400653 bb.fatal('No multiconfig named "%s" found' % mc)
Brad Bishop15ae2502019-06-18 21:44:24 -0400654 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:
Andrew Geissler8f840682023-07-21 09:09:43 -05001669 bb.server.process.serverlog("Parsing started")
Patrick Williamsde0582f2022-04-08 10:23:27 -05001670 self.setupParserWatcher()
1671
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001672 bb.parse.siggen.reset(self.data)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001673 self.parseConfiguration ()
1674 if CookerFeatures.SEND_SANITYEVENTS in self.featureset:
Brad Bishop37a0e4d2017-12-04 01:01:44 -05001675 for mc in self.multiconfigs:
1676 bb.event.fire(bb.event.SanityCheck(False), self.databuilder.mcdata[mc])
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001677
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001678 for mc in self.multiconfigs:
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001679 ignore = self.databuilder.mcdata[mc].getVar("ASSUME_PROVIDED") or ""
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001680 self.recipecaches[mc].ignored_dependencies = set(ignore.split())
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001681
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001682 for dep in self.configuration.extra_assume_provided:
1683 self.recipecaches[mc].ignored_dependencies.add(dep)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001684
Andrew Geissler5a43b432020-06-13 10:46:56 -05001685 mcfilelist = {}
1686 total_masked = 0
1687 searchdirs = set()
1688 for mc in self.multiconfigs:
Andrew Geissler5a43b432020-06-13 10:46:56 -05001689 (filelist, masked, search) = self.collections[mc].collect_bbfiles(self.databuilder.mcdata[mc], self.databuilder.mcdata[mc])
1690
1691 mcfilelist[mc] = filelist
1692 total_masked += masked
1693 searchdirs |= set(search)
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001694
1695 # Add inotify watches for directories searched for bb/bbappend files
1696 for dirent in searchdirs:
1697 self.add_filewatch([[dirent]], dirs=True)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001698
Andrew Geissler5a43b432020-06-13 10:46:56 -05001699 self.parser = CookerParser(self, mcfilelist, total_masked)
Andrew Geissler028142b2023-05-05 11:29:21 -05001700 self._parsecache_set(True)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001701
1702 self.state = state.parsing
1703
1704 if not self.parser.parse_next():
Andrew Geissler87f5cff2022-09-30 13:13:31 -05001705 collectlog.debug("parsing complete")
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001706 if self.parser.error:
1707 raise bb.BBHandledException()
1708 self.show_appends_with_no_recipes()
1709 self.handlePrefProviders()
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001710 for mc in self.multiconfigs:
Andrew Geisslerb7d28612020-07-24 16:15:54 -05001711 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 -05001712 self.state = state.running
1713
1714 # Send an event listing all stamps reachable after parsing
1715 # which the metadata may use to clean up stale data
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001716 for mc in self.multiconfigs:
1717 event = bb.event.ReachableStamps(self.recipecaches[mc].stamp)
1718 bb.event.fire(event, self.databuilder.mcdata[mc])
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001719 return None
1720
1721 return True
1722
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001723 def checkPackages(self, pkgs_to_build, task=None):
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001724
1725 # Return a copy, don't modify the original
1726 pkgs_to_build = pkgs_to_build[:]
1727
Andrew Geissler595f6302022-01-24 19:11:47 +00001728 if not pkgs_to_build:
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001729 raise NothingToBuild
1730
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001731 ignore = (self.data.getVar("ASSUME_PROVIDED") or "").split()
Andrew Geisslerb7d28612020-07-24 16:15:54 -05001732 for pkg in pkgs_to_build.copy():
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001733 if pkg in ignore:
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001734 parselog.warning("Explicit target \"%s\" is in ASSUME_PROVIDED, ignoring" % pkg)
Brad Bishop15ae2502019-06-18 21:44:24 -04001735 if pkg.startswith("multiconfig:"):
1736 pkgs_to_build.remove(pkg)
1737 pkgs_to_build.append(pkg.replace("multiconfig:", "mc:"))
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001738
1739 if 'world' in pkgs_to_build:
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001740 pkgs_to_build.remove('world')
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001741 for mc in self.multiconfigs:
1742 bb.providers.buildWorldTargetList(self.recipecaches[mc], task)
1743 for t in self.recipecaches[mc].world_target:
1744 if mc:
Brad Bishop15ae2502019-06-18 21:44:24 -04001745 t = "mc:" + mc + ":" + t
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001746 pkgs_to_build.append(t)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001747
1748 if 'universe' in pkgs_to_build:
Brad Bishop1a4b7ee2018-12-16 17:11:34 -08001749 parselog.verbnote("The \"universe\" target is only intended for testing and may produce errors.")
Andrew Geissler87f5cff2022-09-30 13:13:31 -05001750 parselog.debug("collating packages for \"universe\"")
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001751 pkgs_to_build.remove('universe')
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001752 for mc in self.multiconfigs:
1753 for t in self.recipecaches[mc].universe_target:
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001754 if task:
1755 foundtask = False
1756 for provider_fn in self.recipecaches[mc].providers[t]:
1757 if task in self.recipecaches[mc].task_deps[provider_fn]['tasks']:
1758 foundtask = True
1759 break
1760 if not foundtask:
1761 bb.debug(1, "Skipping %s for universe tasks as task %s doesn't exist" % (t, task))
1762 continue
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001763 if mc:
Brad Bishop15ae2502019-06-18 21:44:24 -04001764 t = "mc:" + mc + ":" + t
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001765 pkgs_to_build.append(t)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001766
1767 return pkgs_to_build
1768
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001769 def pre_serve(self):
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001770 return
1771
1772 def post_serve(self):
Andrew Geisslerc9f78652020-09-18 14:11:35 -05001773 self.shutdown(force=True)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001774 prserv.serv.auto_shutdown()
Patrick Williams45852732022-04-02 08:58:32 -05001775 if hasattr(bb.parse, "siggen"):
1776 bb.parse.siggen.exit()
Brad Bishop08902b02019-08-20 09:16:51 -04001777 if self.hashserv:
1778 self.hashserv.process.terminate()
1779 self.hashserv.process.join()
Andrew Geisslerc3d88e42020-10-02 09:45:00 -05001780 if hasattr(self, "data"):
1781 bb.event.fire(CookerExit(), self.data)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001782
Andrew Geissler517393d2023-01-13 08:55:19 -06001783 def shutdown(self, force=False):
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001784 if force:
1785 self.state = state.forceshutdown
Patrick Williams8e7b46e2023-05-01 14:19:06 -05001786 bb.event._should_exit.set()
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001787 else:
1788 self.state = state.shutdown
1789
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001790 if self.parser:
Andrew Geissler517393d2023-01-13 08:55:19 -06001791 self.parser.shutdown(clean=False)
Andrew Geisslerc9f78652020-09-18 14:11:35 -05001792 self.parser.final_cleanup()
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001793
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001794 def finishcommand(self):
Andrew Geissler517393d2023-01-13 08:55:19 -06001795 if hasattr(self.parser, 'shutdown'):
1796 self.parser.shutdown(clean=False)
1797 self.parser.final_cleanup()
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001798 self.state = state.initial
Andrew Geissler6aa7eec2023-03-03 12:41:14 -06001799 bb.event._should_exit.clear()
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001800
1801 def reset(self):
Patrick Williams45852732022-04-02 08:58:32 -05001802 if hasattr(bb.parse, "siggen"):
1803 bb.parse.siggen.exit()
Andrew Geissler517393d2023-01-13 08:55:19 -06001804 self.finishcommand()
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001805 self.initConfigurationData()
Brad Bishop08902b02019-08-20 09:16:51 -04001806 self.handlePRServ()
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001807
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001808 def clientComplete(self):
1809 """Called when the client is done using the server"""
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001810 self.finishcommand()
1811 self.extraconfigdata = {}
1812 self.command.reset()
Andrew Geisslerc9f78652020-09-18 14:11:35 -05001813 if hasattr(self, "data"):
1814 self.databuilder.reset()
1815 self.data = self.databuilder.data
Andrew Geissler517393d2023-01-13 08:55:19 -06001816 # In theory tinfoil could have modified the base data before parsing,
1817 # ideally need to track if anything did modify the datastore
Andrew Geissler028142b2023-05-05 11:29:21 -05001818 self._parsecache_set(False)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001819
1820class CookerExit(bb.event.Event):
1821 """
1822 Notify clients of the Cooker shutdown
1823 """
1824
1825 def __init__(self):
1826 bb.event.Event.__init__(self)
1827
1828
1829class CookerCollectFiles(object):
Andrew Geissler5a43b432020-06-13 10:46:56 -05001830 def __init__(self, priorities, mc=''):
1831 self.mc = mc
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001832 self.bbappends = []
Andrew Geissler7e0e3c02022-02-25 20:34:39 +00001833 # Priorities is a list of tuples, with the second element as the pattern.
Brad Bishop1a4b7ee2018-12-16 17:11:34 -08001834 # We need to sort the list with the longest pattern first, and so on to
1835 # the shortest. This allows nested layers to be properly evaluated.
1836 self.bbfile_config_priorities = sorted(priorities, key=lambda tup: tup[1], reverse=True)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001837
Andrew Geisslerb7d28612020-07-24 16:15:54 -05001838 def calc_bbfile_priority(self, filename):
Patrick Williamse760df82023-05-26 11:10:49 -05001839 for layername, _, regex, pri in self.bbfile_config_priorities:
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001840 if regex.match(filename):
Patrick Williamse760df82023-05-26 11:10:49 -05001841 return pri, regex, layername
1842 return 0, None, None
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001843
1844 def get_bbfiles(self):
1845 """Get list of default .bb files by reading out the current directory"""
1846 path = os.getcwd()
1847 contents = os.listdir(path)
1848 bbfiles = []
1849 for f in contents:
1850 if f.endswith(".bb"):
1851 bbfiles.append(os.path.abspath(os.path.join(path, f)))
1852 return bbfiles
1853
1854 def find_bbfiles(self, path):
1855 """Find all the .bb and .bbappend files in a directory"""
1856 found = []
1857 for dir, dirs, files in os.walk(path):
1858 for ignored in ('SCCS', 'CVS', '.svn'):
1859 if ignored in dirs:
1860 dirs.remove(ignored)
1861 found += [os.path.join(dir, f) for f in files if (f.endswith(['.bb', '.bbappend']))]
1862
1863 return found
1864
1865 def collect_bbfiles(self, config, eventdata):
1866 """Collect all available .bb build files"""
1867 masked = 0
1868
Andrew Geissler87f5cff2022-09-30 13:13:31 -05001869 collectlog.debug("collecting .bb files")
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001870
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001871 files = (config.getVar( "BBFILES") or "").split()
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001872
1873 # Sort files by priority
Andrew Geisslerb7d28612020-07-24 16:15:54 -05001874 files.sort( key=lambda fileitem: self.calc_bbfile_priority(fileitem)[0] )
Andrew Geisslerc9f78652020-09-18 14:11:35 -05001875 config.setVar("BBFILES_PRIORITIZED", " ".join(files))
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001876
Andrew Geissler595f6302022-01-24 19:11:47 +00001877 if not files:
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001878 files = self.get_bbfiles()
1879
Andrew Geissler595f6302022-01-24 19:11:47 +00001880 if not files:
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001881 collectlog.error("no recipe files to build, check your BBPATH and BBFILES?")
1882 bb.event.fire(CookerExit(), eventdata)
1883
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001884 # We need to track where we look so that we can add inotify watches. There
1885 # is no nice way to do this, this is horrid. We intercept the os.listdir()
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001886 # (or os.scandir() for python 3.6+) calls while we run glob().
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001887 origlistdir = os.listdir
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001888 if hasattr(os, 'scandir'):
1889 origscandir = os.scandir
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001890 searchdirs = []
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001891
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001892 def ourlistdir(d):
1893 searchdirs.append(d)
1894 return origlistdir(d)
1895
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001896 def ourscandir(d):
1897 searchdirs.append(d)
1898 return origscandir(d)
1899
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001900 os.listdir = ourlistdir
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001901 if hasattr(os, 'scandir'):
1902 os.scandir = ourscandir
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001903 try:
1904 # Can't use set here as order is important
1905 newfiles = []
1906 for f in files:
1907 if os.path.isdir(f):
1908 dirfiles = self.find_bbfiles(f)
1909 for g in dirfiles:
1910 if g not in newfiles:
1911 newfiles.append(g)
1912 else:
1913 globbed = glob.glob(f)
1914 if not globbed and os.path.exists(f):
1915 globbed = [f]
1916 # glob gives files in order on disk. Sort to be deterministic.
1917 for g in sorted(globbed):
1918 if g not in newfiles:
1919 newfiles.append(g)
1920 finally:
1921 os.listdir = origlistdir
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001922 if hasattr(os, 'scandir'):
1923 os.scandir = origscandir
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001924
1925 bbmask = config.getVar('BBMASK')
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001926
1927 if bbmask:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001928 # First validate the individual regular expressions and ignore any
1929 # that do not compile
1930 bbmasks = []
1931 for mask in bbmask.split():
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001932 # When constructing an older style single regex, it's possible for BBMASK
1933 # to end up beginning with '|', which matches and masks _everything_.
1934 if mask.startswith("|"):
Andrew Geissler82c905d2020-04-13 13:39:40 -05001935 collectlog.warning("BBMASK contains regular expression beginning with '|', fixing: %s" % mask)
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001936 mask = mask[1:]
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001937 try:
1938 re.compile(mask)
1939 bbmasks.append(mask)
Andrew Geissler78b72792022-06-14 06:47:25 -05001940 except re.error:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001941 collectlog.critical("BBMASK contains an invalid regular expression, ignoring: %s" % mask)
1942
1943 # Then validate the combined regular expressions. This should never
1944 # fail, but better safe than sorry...
1945 bbmask = "|".join(bbmasks)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001946 try:
1947 bbmask_compiled = re.compile(bbmask)
Andrew Geissler78b72792022-06-14 06:47:25 -05001948 except re.error:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001949 collectlog.critical("BBMASK is not a valid regular expression, ignoring: %s" % bbmask)
1950 bbmask = None
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001951
1952 bbfiles = []
1953 bbappend = []
1954 for f in newfiles:
1955 if bbmask and bbmask_compiled.search(f):
Andrew Geissler87f5cff2022-09-30 13:13:31 -05001956 collectlog.debug("skipping masked file %s", f)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001957 masked += 1
1958 continue
1959 if f.endswith('.bb'):
1960 bbfiles.append(f)
1961 elif f.endswith('.bbappend'):
1962 bbappend.append(f)
1963 else:
Andrew Geissler87f5cff2022-09-30 13:13:31 -05001964 collectlog.debug("skipping %s: unknown file extension", f)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001965
1966 # Build a list of .bbappend files for each .bb file
1967 for f in bbappend:
1968 base = os.path.basename(f).replace('.bbappend', '.bb')
1969 self.bbappends.append((base, f))
1970
1971 # Find overlayed recipes
1972 # bbfiles will be in priority order which makes this easy
1973 bbfile_seen = dict()
1974 self.overlayed = defaultdict(list)
1975 for f in reversed(bbfiles):
1976 base = os.path.basename(f)
1977 if base not in bbfile_seen:
1978 bbfile_seen[base] = f
1979 else:
1980 topfile = bbfile_seen[base]
1981 self.overlayed[topfile].append(f)
1982
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001983 return (bbfiles, masked, searchdirs)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001984
1985 def get_file_appends(self, fn):
1986 """
1987 Returns a list of .bbappend files to apply to fn
1988 """
1989 filelist = []
1990 f = os.path.basename(fn)
1991 for b in self.bbappends:
1992 (bbappend, filename) = b
1993 if (bbappend == f) or ('%' in bbappend and bbappend.startswith(f[:bbappend.index('%')])):
1994 filelist.append(filename)
Andrew Geissler5a43b432020-06-13 10:46:56 -05001995 return tuple(filelist)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001996
Andrew Geisslerb7d28612020-07-24 16:15:54 -05001997 def collection_priorities(self, pkgfns, fns, d):
1998 # Return the priorities of the entries in pkgfns
1999 # Also check that all the regexes in self.bbfile_config_priorities are used
2000 # (but to do that we need to ensure skipped recipes aren't counted, nor
2001 # collections in BBFILE_PATTERN_IGNORE_EMPTY)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002002
2003 priorities = {}
Andrew Geisslerb7d28612020-07-24 16:15:54 -05002004 seen = set()
2005 matched = set()
2006
2007 matched_regex = set()
2008 unmatched_regex = set()
2009 for _, _, regex, _ in self.bbfile_config_priorities:
2010 unmatched_regex.add(regex)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002011
2012 # Calculate priorities for each file
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002013 for p in pkgfns:
Patrick Williamsc0f7c042017-02-23 20:41:17 -06002014 realfn, cls, mc = bb.cache.virtualfn2realfn(p)
Patrick Williamse760df82023-05-26 11:10:49 -05002015 priorities[p], regex, _ = self.calc_bbfile_priority(realfn)
Andrew Geisslerb7d28612020-07-24 16:15:54 -05002016 if regex in unmatched_regex:
2017 matched_regex.add(regex)
2018 unmatched_regex.remove(regex)
2019 seen.add(realfn)
2020 if regex:
2021 matched.add(realfn)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002022
Andrew Geisslerb7d28612020-07-24 16:15:54 -05002023 if unmatched_regex:
2024 # Account for bbappend files
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002025 for b in self.bbappends:
2026 (bbfile, append) = b
Andrew Geisslerb7d28612020-07-24 16:15:54 -05002027 seen.add(append)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002028
Andrew Geisslerb7d28612020-07-24 16:15:54 -05002029 # Account for skipped recipes
2030 seen.update(fns)
2031
2032 seen.difference_update(matched)
2033
2034 def already_matched(fn):
2035 for regex in matched_regex:
2036 if regex.match(fn):
2037 return True
2038 return False
2039
2040 for unmatch in unmatched_regex.copy():
2041 for fn in seen:
2042 if unmatch.match(fn):
2043 # If the bbappend or file was already matched by another regex, skip it
2044 # e.g. for a layer within a layer, the outer regex could match, the inner
2045 # regex may match nothing and we should warn about that
2046 if already_matched(fn):
2047 continue
2048 unmatched_regex.remove(unmatch)
2049 break
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002050
2051 for collection, pattern, regex, _ in self.bbfile_config_priorities:
Andrew Geisslerb7d28612020-07-24 16:15:54 -05002052 if regex in unmatched_regex:
Brad Bishop6e60e8b2018-02-01 10:27:11 -05002053 if d.getVar('BBFILE_PATTERN_IGNORE_EMPTY_%s' % collection) != '1':
Andrew Geissler5a43b432020-06-13 10:46:56 -05002054 collectlog.warning("No bb files in %s matched BBFILE_PATTERN_%s '%s'" % (self.mc if self.mc else 'default',
2055 collection, pattern))
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002056
2057 return priorities
2058
2059class ParsingFailure(Exception):
2060 def __init__(self, realexception, recipe):
2061 self.realexception = realexception
2062 self.recipe = recipe
2063 Exception.__init__(self, realexception, recipe)
2064
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002065class Parser(multiprocessing.Process):
Andrew Geissler9aee5002022-03-30 16:27:02 +00002066 def __init__(self, jobs, results, quit, profile):
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002067 self.jobs = jobs
2068 self.results = results
2069 self.quit = quit
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002070 multiprocessing.Process.__init__(self)
2071 self.context = bb.utils.get_context().copy()
2072 self.handlers = bb.event.get_class_handlers().copy()
2073 self.profile = profile
Andrew Geissler9aee5002022-03-30 16:27:02 +00002074 self.queue_signals = False
2075 self.signal_received = []
2076 self.signal_threadlock = threading.Lock()
2077
2078 def catch_sig(self, signum, frame):
2079 if self.queue_signals:
2080 self.signal_received.append(signum)
2081 else:
2082 self.handle_sig(signum, frame)
2083
2084 def handle_sig(self, signum, frame):
2085 if signum == signal.SIGTERM:
2086 signal.signal(signal.SIGTERM, signal.SIG_DFL)
2087 os.kill(os.getpid(), signal.SIGTERM)
2088 elif signum == signal.SIGINT:
2089 signal.default_int_handler(signum, frame)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002090
2091 def run(self):
2092
2093 if not self.profile:
2094 self.realrun()
2095 return
2096
2097 try:
2098 import cProfile as profile
2099 except:
2100 import profile
2101 prof = profile.Profile()
2102 try:
2103 profile.Profile.runcall(prof, self.realrun)
2104 finally:
2105 logfile = "profile-parse-%s.log" % multiprocessing.current_process().name
2106 prof.dump_stats(logfile)
2107
2108 def realrun(self):
Andrew Geissler9aee5002022-03-30 16:27:02 +00002109 # Signal handling here is hard. We must not terminate any process or thread holding the write
2110 # lock for the event stream as it will not be released, ever, and things will hang.
2111 # Python handles signals in the main thread/process but they can be raised from any thread and
2112 # we want to defer processing of any SIGTERM/SIGINT signal until we're outside the critical section
2113 # and don't hold the lock (see server/process.py). We therefore always catch the signals (so any
2114 # new thread should also do so) and we defer handling but we handle with the local thread lock
2115 # held (a threading lock, not a multiprocessing one) so that no other thread in the process
2116 # can be in the critical section.
2117 signal.signal(signal.SIGTERM, self.catch_sig)
2118 signal.signal(signal.SIGHUP, signal.SIG_DFL)
2119 signal.signal(signal.SIGINT, self.catch_sig)
2120 bb.utils.set_process_name(multiprocessing.current_process().name)
2121 multiprocessing.util.Finalize(None, bb.codeparser.parser_cache_save, exitpriority=1)
2122 multiprocessing.util.Finalize(None, bb.fetch.fetcher_parse_save, exitpriority=1)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002123
2124 pending = []
Andrew Geissler517393d2023-01-13 08:55:19 -06002125 havejobs = True
Andrew Geissler9aee5002022-03-30 16:27:02 +00002126 try:
Andrew Geissler517393d2023-01-13 08:55:19 -06002127 while havejobs or pending:
2128 if self.quit.is_set():
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002129 break
Andrew Geissler9aee5002022-03-30 16:27:02 +00002130
Andrew Geissler517393d2023-01-13 08:55:19 -06002131 job = None
2132 try:
2133 job = self.jobs.pop()
2134 except IndexError:
2135 havejobs = False
2136 if job:
Andrew Geissler9aee5002022-03-30 16:27:02 +00002137 result = self.parse(*job)
2138 # Clear the siggen cache after parsing to control memory usage, its huge
2139 bb.parse.siggen.postparsing_clean_cache()
Andrew Geissler9aee5002022-03-30 16:27:02 +00002140 pending.append(result)
Andrew Geissler517393d2023-01-13 08:55:19 -06002141
2142 if pending:
2143 try:
2144 result = pending.pop()
2145 self.results.put(result, timeout=0.05)
2146 except queue.Full:
2147 pending.append(result)
Andrew Geissler9aee5002022-03-30 16:27:02 +00002148 finally:
2149 self.results.close()
2150 self.results.join_thread()
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002151
Patrick Williamse760df82023-05-26 11:10:49 -05002152 def parse(self, mc, cache, filename, appends, layername):
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002153 try:
Andrew Geissler82c905d2020-04-13 13:39:40 -05002154 origfilter = bb.event.LogHandler.filter
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05002155 # Record the filename we're parsing into any events generated
2156 def parse_filter(self, record):
2157 record.taskpid = bb.event.worker_pid
2158 record.fn = filename
2159 return True
2160
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002161 # Reset our environment and handlers to the original settings
2162 bb.utils.set_context(self.context.copy())
2163 bb.event.set_class_handlers(self.handlers.copy())
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05002164 bb.event.LogHandler.filter = parse_filter
2165
Patrick Williamse760df82023-05-26 11:10:49 -05002166 return True, mc, cache.parse(filename, appends, layername)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002167 except Exception as exc:
2168 tb = sys.exc_info()[2]
2169 exc.recipe = filename
2170 exc.traceback = list(bb.exceptions.extract_traceback(tb, context=3))
Andrew Geissler9aee5002022-03-30 16:27:02 +00002171 return True, None, exc
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002172 # Need to turn BaseExceptions into Exceptions here so we gracefully shutdown
2173 # and for example a worker thread doesn't just exit on its own in response to
2174 # a SystemExit event for example.
2175 except BaseException as exc:
Andrew Geissler9aee5002022-03-30 16:27:02 +00002176 return True, None, ParsingFailure(exc, filename)
Andrew Geissler82c905d2020-04-13 13:39:40 -05002177 finally:
2178 bb.event.LogHandler.filter = origfilter
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002179
2180class CookerParser(object):
Andrew Geissler5a43b432020-06-13 10:46:56 -05002181 def __init__(self, cooker, mcfilelist, masked):
2182 self.mcfilelist = mcfilelist
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002183 self.cooker = cooker
2184 self.cfgdata = cooker.data
2185 self.cfghash = cooker.data_hash
Patrick Williamsc0f7c042017-02-23 20:41:17 -06002186 self.cfgbuilder = cooker.databuilder
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002187
2188 # Accounting statistics
2189 self.parsed = 0
2190 self.cached = 0
2191 self.error = 0
2192 self.masked = masked
2193
2194 self.skipped = 0
2195 self.virtuals = 0
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002196
2197 self.current = 0
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002198 self.process_names = []
2199
Andrew Geissler5a43b432020-06-13 10:46:56 -05002200 self.bb_caches = bb.cache.MulticonfigCache(self.cfgbuilder, self.cfghash, cooker.caches_array)
2201 self.fromcache = set()
2202 self.willparse = set()
2203 for mc in self.cooker.multiconfigs:
2204 for filename in self.mcfilelist[mc]:
2205 appends = self.cooker.collections[mc].get_file_appends(filename)
Patrick Williamse760df82023-05-26 11:10:49 -05002206 layername = self.cooker.collections[mc].calc_bbfile_priority(filename)[2]
Andrew Geissler5a43b432020-06-13 10:46:56 -05002207 if not self.bb_caches[mc].cacheValid(filename, appends):
Patrick Williamse760df82023-05-26 11:10:49 -05002208 self.willparse.add((mc, self.bb_caches[mc], filename, appends, layername))
Andrew Geissler5a43b432020-06-13 10:46:56 -05002209 else:
Patrick Williamse760df82023-05-26 11:10:49 -05002210 self.fromcache.add((mc, self.bb_caches[mc], filename, appends, layername))
Andrew Geissler5a43b432020-06-13 10:46:56 -05002211
2212 self.total = len(self.fromcache) + len(self.willparse)
2213 self.toparse = len(self.willparse)
Patrick Williamsc0f7c042017-02-23 20:41:17 -06002214 self.progress_chunk = int(max(self.toparse / 100, 1))
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002215
Brad Bishop6e60e8b2018-02-01 10:27:11 -05002216 self.num_processes = min(int(self.cfgdata.getVar("BB_NUMBER_PARSE_THREADS") or
Andrew Geissler5a43b432020-06-13 10:46:56 -05002217 multiprocessing.cpu_count()), self.toparse)
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05002218
Andrew Geisslerc5535c92023-01-27 16:10:19 -06002219 bb.cache.SiggenRecipeInfo.reset()
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002220 self.start()
2221 self.haveshutdown = False
Andrew Geisslerc9f78652020-09-18 14:11:35 -05002222 self.syncthread = None
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002223
2224 def start(self):
2225 self.results = self.load_cached()
2226 self.processes = []
2227 if self.toparse:
2228 bb.event.fire(bb.event.ParseStarted(self.toparse), self.cfgdata)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002229
Andrew Geissler517393d2023-01-13 08:55:19 -06002230 self.parser_quit = multiprocessing.Event()
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002231 self.result_queue = multiprocessing.Queue()
Brad Bishop19323692019-04-05 15:28:33 -04002232
2233 def chunkify(lst,n):
2234 return [lst[i::n] for i in range(n)]
Andrew Geissler5a43b432020-06-13 10:46:56 -05002235 self.jobs = chunkify(list(self.willparse), self.num_processes)
Brad Bishop19323692019-04-05 15:28:33 -04002236
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002237 for i in range(0, self.num_processes):
Andrew Geissler9aee5002022-03-30 16:27:02 +00002238 parser = Parser(self.jobs[i], self.result_queue, self.parser_quit, self.cooker.configuration.profile)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002239 parser.start()
2240 self.process_names.append(parser.name)
2241 self.processes.append(parser)
2242
2243 self.results = itertools.chain(self.results, self.parse_generator())
2244
Patrick Williams8e7b46e2023-05-01 14:19:06 -05002245 def shutdown(self, clean=True, eventmsg="Parsing halted due to errors"):
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002246 if not self.toparse:
2247 return
2248 if self.haveshutdown:
2249 return
2250 self.haveshutdown = True
2251
2252 if clean:
2253 event = bb.event.ParseCompleted(self.cached, self.parsed,
2254 self.skipped, self.masked,
2255 self.virtuals, self.error,
2256 self.total)
2257
2258 bb.event.fire(event, self.cfgdata)
Andrew Geissler7e0e3c02022-02-25 20:34:39 +00002259 else:
Patrick Williams8e7b46e2023-05-01 14:19:06 -05002260 bb.event.fire(bb.event.ParseError(eventmsg), self.cfgdata)
Andrew Geissler9aee5002022-03-30 16:27:02 +00002261 bb.error("Parsing halted due to errors, see error messages above")
Andrew Geisslerc9f78652020-09-18 14:11:35 -05002262
Andrew Geisslerc5535c92023-01-27 16:10:19 -06002263 # Cleanup the queue before call process.join(), otherwise there might be
2264 # deadlocks.
2265 while True:
2266 try:
2267 self.result_queue.get(timeout=0.25)
2268 except queue.Empty:
2269 break
2270
Andrew Geissler517393d2023-01-13 08:55:19 -06002271 def sync_caches():
2272 for c in self.bb_caches.values():
2273 bb.cache.SiggenRecipeInfo.reset()
2274 c.sync()
2275
2276 self.syncthread = threading.Thread(target=sync_caches, name="SyncThread")
2277 self.syncthread.start()
2278
2279 self.parser_quit.set()
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002280
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002281 for process in self.processes:
Andrew Geissler9aee5002022-03-30 16:27:02 +00002282 process.join(0.5)
2283
2284 for process in self.processes:
2285 if process.exitcode is None:
2286 os.kill(process.pid, signal.SIGINT)
2287
2288 for process in self.processes:
2289 process.join(0.5)
2290
2291 for process in self.processes:
2292 if process.exitcode is None:
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002293 process.terminate()
Andrew Geissler9aee5002022-03-30 16:27:02 +00002294
2295 for process in self.processes:
2296 process.join()
2297 # Added in 3.7, cleans up zombies
2298 if hasattr(process, "close"):
2299 process.close()
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002300
Andrew Geisslerc5535c92023-01-27 16:10:19 -06002301 bb.codeparser.parser_cache_save()
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05002302 bb.codeparser.parser_cache_savemerge()
Andrew Geissler517393d2023-01-13 08:55:19 -06002303 bb.cache.SiggenRecipeInfo.reset()
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05002304 bb.fetch.fetcher_parse_done()
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002305 if self.cooker.configuration.profile:
2306 profiles = []
2307 for i in self.process_names:
2308 logfile = "profile-parse-%s.log" % i
2309 if os.path.exists(logfile):
2310 profiles.append(logfile)
2311
2312 pout = "profile-parse.log.processed"
2313 bb.utils.process_profilelog(profiles, pout = pout)
2314 print("Processed parsing statistics saved to %s" % (pout))
2315
Andrew Geisslerc9f78652020-09-18 14:11:35 -05002316 def final_cleanup(self):
2317 if self.syncthread:
2318 self.syncthread.join()
2319
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002320 def load_cached(self):
Patrick Williamse760df82023-05-26 11:10:49 -05002321 for mc, cache, filename, appends, layername in self.fromcache:
Andrew Geissler517393d2023-01-13 08:55:19 -06002322 infos = cache.loadCached(filename, appends)
2323 yield False, mc, infos
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002324
2325 def parse_generator(self):
Andrew Geissler595f6302022-01-24 19:11:47 +00002326 empty = False
2327 while self.processes or not empty:
2328 for process in self.processes.copy():
2329 if not process.is_alive():
2330 process.join()
2331 self.processes.remove(process)
2332
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002333 if self.parsed >= self.toparse:
2334 break
2335
2336 try:
2337 result = self.result_queue.get(timeout=0.25)
Patrick Williamsc0f7c042017-02-23 20:41:17 -06002338 except queue.Empty:
Andrew Geissler595f6302022-01-24 19:11:47 +00002339 empty = True
Andrew Geissler9aee5002022-03-30 16:27:02 +00002340 yield None, None, None
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002341 else:
Andrew Geissler595f6302022-01-24 19:11:47 +00002342 empty = False
Andrew Geissler9aee5002022-03-30 16:27:02 +00002343 yield result
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002344
Andrew Geissler595f6302022-01-24 19:11:47 +00002345 if not (self.parsed >= self.toparse):
2346 raise bb.parse.ParseError("Not all recipes parsed, parser thread killed/died? Exiting.", None)
2347
2348
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002349 def parse_next(self):
2350 result = []
2351 parsed = None
2352 try:
Andrew Geissler5a43b432020-06-13 10:46:56 -05002353 parsed, mc, result = next(self.results)
Andrew Geissler9aee5002022-03-30 16:27:02 +00002354 if isinstance(result, BaseException):
2355 # Turn exceptions back into exceptions
2356 raise result
2357 if parsed is None:
2358 # Timeout, loop back through the main loop
2359 return True
2360
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002361 except StopIteration:
2362 self.shutdown()
2363 return False
2364 except bb.BBHandledException as exc:
2365 self.error += 1
Andrew Geissler7e0e3c02022-02-25 20:34:39 +00002366 logger.debug('Failed to parse recipe: %s' % exc.recipe)
Andrew Geissler9aee5002022-03-30 16:27:02 +00002367 self.shutdown(clean=False)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002368 return False
2369 except ParsingFailure as exc:
2370 self.error += 1
2371 logger.error('Unable to parse %s: %s' %
2372 (exc.recipe, bb.exceptions.to_string(exc.realexception)))
Andrew Geissler9aee5002022-03-30 16:27:02 +00002373 self.shutdown(clean=False)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002374 return False
2375 except bb.parse.ParseError as exc:
2376 self.error += 1
2377 logger.error(str(exc))
Patrick Williams8e7b46e2023-05-01 14:19:06 -05002378 self.shutdown(clean=False, eventmsg=str(exc))
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002379 return False
2380 except bb.data_smart.ExpansionError as exc:
2381 self.error += 1
Patrick Williamsc0f7c042017-02-23 20:41:17 -06002382 bbdir = os.path.dirname(__file__) + os.sep
2383 etype, value, _ = sys.exc_info()
2384 tb = list(itertools.dropwhile(lambda e: e.filename.startswith(bbdir), exc.traceback))
2385 logger.error('ExpansionError during parsing %s', value.recipe,
2386 exc_info=(etype, value, tb))
Andrew Geissler9aee5002022-03-30 16:27:02 +00002387 self.shutdown(clean=False)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002388 return False
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002389 except Exception as exc:
2390 self.error += 1
2391 etype, value, tb = sys.exc_info()
2392 if hasattr(value, "recipe"):
Patrick Williamsc0f7c042017-02-23 20:41:17 -06002393 logger.error('Unable to parse %s' % value.recipe,
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002394 exc_info=(etype, value, exc.traceback))
2395 else:
2396 # Most likely, an exception occurred during raising an exception
2397 import traceback
2398 logger.error('Exception during parse: %s' % traceback.format_exc())
Andrew Geissler9aee5002022-03-30 16:27:02 +00002399 self.shutdown(clean=False)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002400 return False
2401
2402 self.current += 1
2403 self.virtuals += len(result)
2404 if parsed:
2405 self.parsed += 1
2406 if self.parsed % self.progress_chunk == 0:
2407 bb.event.fire(bb.event.ParseProgress(self.parsed, self.toparse),
2408 self.cfgdata)
2409 else:
2410 self.cached += 1
2411
2412 for virtualfn, info_array in result:
2413 if info_array[0].skipped:
2414 self.skipped += 1
2415 self.cooker.skiplist[virtualfn] = SkippedPackage(info_array[0])
Andrew Geissler5a43b432020-06-13 10:46:56 -05002416 self.bb_caches[mc].add_info(virtualfn, info_array, self.cooker.recipecaches[mc],
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002417 parsed=parsed, watcher = self.cooker.add_filewatch)
2418 return True
2419
2420 def reparse(self, filename):
Andrew Geissler517393d2023-01-13 08:55:19 -06002421 bb.cache.SiggenRecipeInfo.reset()
Andrew Geissler5a43b432020-06-13 10:46:56 -05002422 to_reparse = set()
2423 for mc in self.cooker.multiconfigs:
Patrick Williamse760df82023-05-26 11:10:49 -05002424 layername = self.cooker.collections[mc].calc_bbfile_priority(filename)[2]
2425 to_reparse.add((mc, filename, self.cooker.collections[mc].get_file_appends(filename), layername))
Andrew Geissler5a43b432020-06-13 10:46:56 -05002426
Patrick Williamse760df82023-05-26 11:10:49 -05002427 for mc, filename, appends, layername in to_reparse:
2428 infos = self.bb_caches[mc].parse(filename, appends, layername)
Andrew Geissler5a43b432020-06-13 10:46:56 -05002429 for vfn, info_array in infos:
2430 self.cooker.recipecaches[mc].add_from_recipeinfo(vfn, info_array)