blob: 554c7f10a53781671c7eacb9daeef0ad28834ccf [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 Williamsc124f4f2015-09-15 14:41:29 -0500507
Andrew Geissler028142b2023-05-05 11:29:21 -0500508 self._parsecache_set(False)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500509
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500510 def updateConfigOpts(self, options, environment, cmdline):
511 self.ui_cmdline = cmdline
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500512 clean = True
513 for o in options:
514 if o in ['prefile', 'postfile']:
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500515 # Only these options may require a reparse
516 try:
517 if getattr(self.configuration, o) == options[o]:
518 # Value is the same, no need to mark dirty
519 continue
520 except AttributeError:
521 pass
Andrew Geisslerd1e89492021-02-12 15:35:20 -0600522 logger.debug("Marking as dirty due to '%s' option change to '%s'" % (o, options[o]))
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500523 print("Marking as dirty due to '%s' option change to '%s'" % (o, options[o]))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500524 clean = False
Andrew Geisslerc9f78652020-09-18 14:11:35 -0500525 if hasattr(self.configuration, o):
526 setattr(self.configuration, o, options[o])
527
528 if self.configuration.writeeventlog:
529 if self.eventlog and self.eventlog[0] != self.configuration.writeeventlog:
530 bb.event.unregister_UIHhandler(self.eventlog[1])
531 if not self.eventlog or self.eventlog[0] != self.configuration.writeeventlog:
532 # we log all events to a file if so directed
533 # register the log file writer as UI Handler
534 writer = EventWriter(self, self.configuration.writeeventlog)
535 EventLogWriteHandler = namedtuple('EventLogWriteHandler', ['event'])
536 self.eventlog = (self.configuration.writeeventlog, bb.event.register_UIHhandler(EventLogWriteHandler(writer)))
537
538 bb.msg.loggerDefaultLogLevel = self.configuration.default_loglevel
539 bb.msg.loggerDefaultDomains = self.configuration.debug_domains
540
541 if hasattr(self, "data"):
542 origenv = bb.data.init()
543 for k in environment:
544 origenv.setVar(k, environment[k])
545 self.data.setVar("BB_ORIGENV", origenv)
546
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500547 for k in bb.utils.approved_variables():
548 if k in environment and k not in self.configuration.env:
Andrew Geisslerd1e89492021-02-12 15:35:20 -0600549 logger.debug("Updating new environment variable %s to %s" % (k, environment[k]))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500550 self.configuration.env[k] = environment[k]
551 clean = False
552 if k in self.configuration.env and k not in environment:
Andrew Geisslerd1e89492021-02-12 15:35:20 -0600553 logger.debug("Updating environment variable %s (deleted)" % (k))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500554 del self.configuration.env[k]
555 clean = False
556 if k not in self.configuration.env and k not in environment:
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500557 continue
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500558 if environment[k] != self.configuration.env[k]:
Andrew Geisslerd1e89492021-02-12 15:35:20 -0600559 logger.debug("Updating environment variable %s from %s to %s" % (k, self.configuration.env[k], environment[k]))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500560 self.configuration.env[k] = environment[k]
561 clean = False
Andrew Geisslerc9f78652020-09-18 14:11:35 -0500562
563 # Now update all the variables not in the datastore to match
564 self.configuration.env = environment
565
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500566 if not clean:
Andrew Geisslerd1e89492021-02-12 15:35:20 -0600567 logger.debug("Base environment change, triggering reparse")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500568 self.reset()
569
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500570 def showVersions(self):
571
Andrew Geissler95ac1b82021-03-31 14:34:31 -0500572 (latest_versions, preferred_versions, required) = self.findProviders()
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500573
Andrew Geissler95ac1b82021-03-31 14:34:31 -0500574 logger.plain("%-35s %25s %25s %25s", "Recipe Name", "Latest Version", "Preferred Version", "Required Version")
575 logger.plain("%-35s %25s %25s %25s\n", "===========", "==============", "=================", "================")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500576
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500577 for p in sorted(self.recipecaches[''].pkg_pn):
Andrew Geissler95ac1b82021-03-31 14:34:31 -0500578 preferred = preferred_versions[p]
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500579 latest = latest_versions[p]
Andrew Geissler95ac1b82021-03-31 14:34:31 -0500580 requiredstr = ""
581 preferredstr = ""
582 if required[p]:
583 if preferred[0] is not None:
584 requiredstr = preferred[0][0] + ":" + preferred[0][1] + '-' + preferred[0][2]
585 else:
586 bb.fatal("REQUIRED_VERSION of package %s not available" % p)
587 else:
588 preferredstr = preferred[0][0] + ":" + preferred[0][1] + '-' + preferred[0][2]
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500589
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500590 lateststr = latest[0][0] + ":" + latest[0][1] + "-" + latest[0][2]
591
Andrew Geissler95ac1b82021-03-31 14:34:31 -0500592 if preferred == latest:
593 preferredstr = ""
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500594
Andrew Geissler95ac1b82021-03-31 14:34:31 -0500595 logger.plain("%-35s %25s %25s %25s", p, lateststr, preferredstr, requiredstr)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500596
597 def showEnvironment(self, buildfile=None, pkgs_to_build=None):
598 """
599 Show the outer or per-recipe environment
600 """
601 fn = None
602 envdata = None
Brad Bishop15ae2502019-06-18 21:44:24 -0400603 mc = ''
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500604 if not pkgs_to_build:
605 pkgs_to_build = []
606
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500607 orig_tracking = self.configuration.tracking
608 if not orig_tracking:
609 self.enableDataTracking()
610 self.reset()
Andrew Geissler9aee5002022-03-30 16:27:02 +0000611 # reset() resets to the UI requested value so we have to redo this
612 self.enableDataTracking()
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500613
Brad Bishop15ae2502019-06-18 21:44:24 -0400614 def mc_base(p):
615 if p.startswith('mc:'):
616 s = p.split(':')
617 if len(s) == 2:
618 return s[1]
619 return None
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500620
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500621 if buildfile:
622 # Parse the configuration here. We need to do it explicitly here since
623 # this showEnvironment() code path doesn't use the cache
624 self.parseConfiguration()
625
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600626 fn, cls, mc = bb.cache.virtualfn2realfn(buildfile)
Andrew Geissler5a43b432020-06-13 10:46:56 -0500627 fn = self.matchFile(fn, mc)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600628 fn = bb.cache.realfn2virtual(fn, cls, mc)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500629 elif len(pkgs_to_build) == 1:
Brad Bishop15ae2502019-06-18 21:44:24 -0400630 mc = mc_base(pkgs_to_build[0])
631 if not mc:
632 ignore = self.data.getVar("ASSUME_PROVIDED") or ""
633 if pkgs_to_build[0] in set(ignore.split()):
634 bb.fatal("%s is in ASSUME_PROVIDED" % pkgs_to_build[0])
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500635
Andrew Geissler7e0e3c02022-02-25 20:34:39 +0000636 taskdata, runlist = self.buildTaskData(pkgs_to_build, None, self.configuration.halt, allowincomplete=True)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500637
Brad Bishop15ae2502019-06-18 21:44:24 -0400638 mc = runlist[0][0]
639 fn = runlist[0][3]
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500640
641 if fn:
642 try:
Andrew Geissler517393d2023-01-13 08:55:19 -0600643 envdata = self.databuilder.parseRecipe(fn, self.collections[mc].get_file_appends(fn))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500644 except Exception as e:
645 parselog.exception("Unable to read %s", fn)
646 raise
Brad Bishop15ae2502019-06-18 21:44:24 -0400647 else:
648 if not mc in self.databuilder.mcdata:
649 bb.fatal('Not multiconfig named "%s" found' % mc)
650 envdata = self.databuilder.mcdata[mc]
651 data.expandKeys(envdata)
652 parse.ast.runAnonFuncs(envdata)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500653
654 # Display history
655 with closing(StringIO()) as env:
656 self.data.inchistory.emit(env)
657 logger.plain(env.getvalue())
658
659 # emit variables and shell functions
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500660 with closing(StringIO()) as env:
661 data.emit_env(env, envdata, True)
662 logger.plain(env.getvalue())
663
Andrew Geissler7e0e3c02022-02-25 20:34:39 +0000664 # emit the metadata which isn't valid shell
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500665 for e in sorted(envdata.keys()):
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600666 if envdata.getVarFlag(e, 'func', False) and envdata.getVarFlag(e, 'python', False):
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500667 logger.plain("\npython %s () {\n%s}\n", e, envdata.getVar(e, False))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500668
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500669 if not orig_tracking:
670 self.disableDataTracking()
671 self.reset()
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500672
Andrew Geissler7e0e3c02022-02-25 20:34:39 +0000673 def buildTaskData(self, pkgs_to_build, task, halt, allowincomplete=False):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500674 """
675 Prepare a runqueue and taskdata object for iteration over pkgs_to_build
676 """
677 bb.event.fire(bb.event.TreeDataPreparationStarted(), self.data)
678
679 # A task of None means use the default task
680 if task is None:
681 task = self.configuration.cmd
Brad Bishop37a0e4d2017-12-04 01:01:44 -0500682 if not task.startswith("do_"):
683 task = "do_%s" % task
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500684
Brad Bishop37a0e4d2017-12-04 01:01:44 -0500685 targetlist = self.checkPackages(pkgs_to_build, task)
686 fulltargetlist = []
687 defaulttask_implicit = ''
688 defaulttask_explicit = False
689 wildcard = False
690
691 # Wild card expansion:
Brad Bishop15ae2502019-06-18 21:44:24 -0400692 # Replace string such as "mc:*:bash"
693 # into "mc:A:bash mc:B:bash bash"
Brad Bishop37a0e4d2017-12-04 01:01:44 -0500694 for k in targetlist:
Andrew Geisslerd1e89492021-02-12 15:35:20 -0600695 if k.startswith("mc:") and k.count(':') >= 2:
Brad Bishop37a0e4d2017-12-04 01:01:44 -0500696 if wildcard:
697 bb.fatal('multiconfig conflict')
698 if k.split(":")[1] == "*":
699 wildcard = True
700 for mc in self.multiconfigs:
701 if mc:
702 fulltargetlist.append(k.replace('*', mc))
703 # implicit default task
704 else:
705 defaulttask_implicit = k.split(":")[2]
706 else:
707 fulltargetlist.append(k)
708 else:
709 defaulttask_explicit = True
710 fulltargetlist.append(k)
711
712 if not defaulttask_explicit and defaulttask_implicit != '':
713 fulltargetlist.append(defaulttask_implicit)
714
715 bb.debug(1,"Target list: %s" % (str(fulltargetlist)))
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600716 taskdata = {}
717 localdata = {}
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500718
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600719 for mc in self.multiconfigs:
Andrew Geissler7e0e3c02022-02-25 20:34:39 +0000720 taskdata[mc] = bb.taskdata.TaskData(halt, skiplist=self.skiplist, allowincomplete=allowincomplete)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600721 localdata[mc] = data.createCopy(self.databuilder.mcdata[mc])
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600722 bb.data.expandKeys(localdata[mc])
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500723
724 current = 0
725 runlist = []
726 for k in fulltargetlist:
Andrew Geisslerb7d28612020-07-24 16:15:54 -0500727 origk = k
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600728 mc = ""
Andrew Geisslerd1e89492021-02-12 15:35:20 -0600729 if k.startswith("mc:") and k.count(':') >= 2:
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600730 mc = k.split(":")[1]
731 k = ":".join(k.split(":")[2:])
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500732 ktask = task
733 if ":do_" in k:
734 k2 = k.split(":do_")
735 k = k2[0]
736 ktask = k2[1]
Andrew Geisslerb7d28612020-07-24 16:15:54 -0500737
738 if mc not in self.multiconfigs:
739 bb.fatal("Multiconfig dependency %s depends on nonexistent multiconfig configuration named %s" % (origk, mc))
740
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600741 taskdata[mc].add_provider(localdata[mc], self.recipecaches[mc], k)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500742 current += 1
743 if not ktask.startswith("do_"):
744 ktask = "do_%s" % ktask
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600745 if k not in taskdata[mc].build_targets or not taskdata[mc].build_targets[k]:
746 # e.g. in ASSUME_PROVIDED
747 continue
748 fn = taskdata[mc].build_targets[k][0]
749 runlist.append([mc, k, ktask, fn])
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500750 bb.event.fire(bb.event.TreeDataPreparationProgress(current, len(fulltargetlist)), self.data)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600751
Brad Bishop15ae2502019-06-18 21:44:24 -0400752 havemc = False
753 for mc in self.multiconfigs:
754 if taskdata[mc].get_mcdepends():
755 havemc = True
Brad Bishopf058f492019-01-28 23:50:33 -0500756
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800757 # No need to do check providers if there are no mcdeps or not an mc build
Brad Bishop15ae2502019-06-18 21:44:24 -0400758 if havemc or len(self.multiconfigs) > 1:
Andrew Geissler99467da2019-02-25 18:54:23 -0600759 seen = set()
760 new = True
761 # Make sure we can provide the multiconfig dependency
762 while new:
763 mcdeps = set()
764 # Add unresolved first, so we can get multiconfig indirect dependencies on time
765 for mc in self.multiconfigs:
766 taskdata[mc].add_unresolved(localdata[mc], self.recipecaches[mc])
767 mcdeps |= set(taskdata[mc].get_mcdepends())
768 new = False
Patrick Williams03907ee2022-05-01 06:28:52 -0500769 for k in mcdeps:
770 if k in seen:
771 continue
772 l = k.split(':')
773 depmc = l[2]
774 if depmc not in self.multiconfigs:
775 bb.fatal("Multiconfig dependency %s depends on nonexistent multiconfig configuration named configuration %s" % (k,depmc))
776 else:
777 logger.debug("Adding providers for multiconfig dependency %s" % l[3])
778 taskdata[depmc].add_provider(localdata[depmc], self.recipecaches[depmc], l[3])
779 seen.add(k)
780 new = True
Brad Bishopf058f492019-01-28 23:50:33 -0500781
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600782 for mc in self.multiconfigs:
783 taskdata[mc].add_unresolved(localdata[mc], self.recipecaches[mc])
784
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500785 bb.event.fire(bb.event.TreeDataPreparationCompleted(len(fulltargetlist)), self.data)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600786 return taskdata, runlist
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500787
788 def prepareTreeData(self, pkgs_to_build, task):
789 """
790 Prepare a runqueue and taskdata object for iteration over pkgs_to_build
791 """
792
Andrew Geissler7e0e3c02022-02-25 20:34:39 +0000793 # We set halt to False here to prevent unbuildable targets raising
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500794 # an exception when we're just generating data
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600795 taskdata, runlist = self.buildTaskData(pkgs_to_build, task, False, allowincomplete=True)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500796
797 return runlist, taskdata
798
799 ######## WARNING : this function requires cache_extra to be enabled ########
800
801 def generateTaskDepTreeData(self, pkgs_to_build, task):
802 """
803 Create a dependency graph of pkgs_to_build including reverse dependency
804 information.
805 """
Brad Bishop37a0e4d2017-12-04 01:01:44 -0500806 if not task.startswith("do_"):
807 task = "do_%s" % task
808
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500809 runlist, taskdata = self.prepareTreeData(pkgs_to_build, task)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600810 rq = bb.runqueue.RunQueue(self, self.data, self.recipecaches, taskdata, runlist)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500811 rq.rqdata.prepare()
812 return self.buildDependTree(rq, taskdata)
813
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600814 @staticmethod
815 def add_mc_prefix(mc, pn):
816 if mc:
Brad Bishop15ae2502019-06-18 21:44:24 -0400817 return "mc:%s:%s" % (mc, pn)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600818 return pn
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500819
820 def buildDependTree(self, rq, taskdata):
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600821 seen_fns = []
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500822 depend_tree = {}
823 depend_tree["depends"] = {}
824 depend_tree["tdepends"] = {}
825 depend_tree["pn"] = {}
826 depend_tree["rdepends-pn"] = {}
827 depend_tree["packages"] = {}
828 depend_tree["rdepends-pkg"] = {}
829 depend_tree["rrecs-pkg"] = {}
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500830 depend_tree['providermap'] = {}
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600831 depend_tree["layer-priorities"] = self.bbfile_config_priorities
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500832
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600833 for mc in taskdata:
834 for name, fn in list(taskdata[mc].get_providermap().items()):
835 pn = self.recipecaches[mc].pkg_fn[fn]
836 pn = self.add_mc_prefix(mc, pn)
837 if name != pn:
838 version = "%s:%s-%s" % self.recipecaches[mc].pkg_pepvpr[fn]
839 depend_tree['providermap'][name] = (pn, version)
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500840
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600841 for tid in rq.rqdata.runtaskentries:
842 (mc, fn, taskname, taskfn) = bb.runqueue.split_tid_mcfn(tid)
843 pn = self.recipecaches[mc].pkg_fn[taskfn]
844 pn = self.add_mc_prefix(mc, pn)
845 version = "%s:%s-%s" % self.recipecaches[mc].pkg_pepvpr[taskfn]
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500846 if pn not in depend_tree["pn"]:
847 depend_tree["pn"][pn] = {}
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600848 depend_tree["pn"][pn]["filename"] = taskfn
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500849 depend_tree["pn"][pn]["version"] = version
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600850 depend_tree["pn"][pn]["inherits"] = self.recipecaches[mc].inherits.get(taskfn, None)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500851
852 # if we have extra caches, list all attributes they bring in
853 extra_info = []
854 for cache_class in self.caches_array:
855 if type(cache_class) is type and issubclass(cache_class, bb.cache.RecipeInfoCommon) and hasattr(cache_class, 'cachefields'):
856 cachefields = getattr(cache_class, 'cachefields', [])
857 extra_info = extra_info + cachefields
858
859 # for all attributes stored, add them to the dependency tree
860 for ei in extra_info:
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600861 depend_tree["pn"][pn][ei] = vars(self.recipecaches[mc])[ei][taskfn]
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500862
863
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500864 dotname = "%s.%s" % (pn, bb.runqueue.taskname_from_tid(tid))
865 if not dotname in depend_tree["tdepends"]:
866 depend_tree["tdepends"][dotname] = []
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600867 for dep in rq.rqdata.runtaskentries[tid].depends:
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800868 (depmc, depfn, _, deptaskfn) = bb.runqueue.split_tid_mcfn(dep)
869 deppn = self.recipecaches[depmc].pkg_fn[deptaskfn]
Andrew Geissler595f6302022-01-24 19:11:47 +0000870 if depmc:
871 depmc = "mc:" + depmc + ":"
872 depend_tree["tdepends"][dotname].append("%s%s.%s" % (depmc, deppn, bb.runqueue.taskname_from_tid(dep)))
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600873 if taskfn not in seen_fns:
874 seen_fns.append(taskfn)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500875 packages = []
876
877 depend_tree["depends"][pn] = []
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600878 for dep in taskdata[mc].depids[taskfn]:
879 depend_tree["depends"][pn].append(dep)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500880
881 depend_tree["rdepends-pn"][pn] = []
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600882 for rdep in taskdata[mc].rdepids[taskfn]:
883 depend_tree["rdepends-pn"][pn].append(rdep)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500884
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600885 rdepends = self.recipecaches[mc].rundeps[taskfn]
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500886 for package in rdepends:
887 depend_tree["rdepends-pkg"][package] = []
888 for rdepend in rdepends[package]:
889 depend_tree["rdepends-pkg"][package].append(rdepend)
890 packages.append(package)
891
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600892 rrecs = self.recipecaches[mc].runrecs[taskfn]
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500893 for package in rrecs:
894 depend_tree["rrecs-pkg"][package] = []
895 for rdepend in rrecs[package]:
896 depend_tree["rrecs-pkg"][package].append(rdepend)
897 if not package in packages:
898 packages.append(package)
899
900 for package in packages:
901 if package not in depend_tree["packages"]:
902 depend_tree["packages"][package] = {}
903 depend_tree["packages"][package]["pn"] = pn
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600904 depend_tree["packages"][package]["filename"] = taskfn
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500905 depend_tree["packages"][package]["version"] = version
906
907 return depend_tree
908
909 ######## WARNING : this function requires cache_extra to be enabled ########
910 def generatePkgDepTreeData(self, pkgs_to_build, task):
911 """
912 Create a dependency tree of pkgs_to_build, returning the data.
913 """
Brad Bishop37a0e4d2017-12-04 01:01:44 -0500914 if not task.startswith("do_"):
915 task = "do_%s" % task
916
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500917 _, taskdata = self.prepareTreeData(pkgs_to_build, task)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500918
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600919 seen_fns = []
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500920 depend_tree = {}
921 depend_tree["depends"] = {}
922 depend_tree["pn"] = {}
923 depend_tree["rdepends-pn"] = {}
924 depend_tree["rdepends-pkg"] = {}
925 depend_tree["rrecs-pkg"] = {}
926
927 # if we have extra caches, list all attributes they bring in
928 extra_info = []
929 for cache_class in self.caches_array:
930 if type(cache_class) is type and issubclass(cache_class, bb.cache.RecipeInfoCommon) and hasattr(cache_class, 'cachefields'):
931 cachefields = getattr(cache_class, 'cachefields', [])
932 extra_info = extra_info + cachefields
933
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600934 tids = []
935 for mc in taskdata:
936 for tid in taskdata[mc].taskentries:
937 tids.append(tid)
938
939 for tid in tids:
940 (mc, fn, taskname, taskfn) = bb.runqueue.split_tid_mcfn(tid)
941
942 pn = self.recipecaches[mc].pkg_fn[taskfn]
943 pn = self.add_mc_prefix(mc, pn)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500944
945 if pn not in depend_tree["pn"]:
946 depend_tree["pn"][pn] = {}
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600947 depend_tree["pn"][pn]["filename"] = taskfn
948 version = "%s:%s-%s" % self.recipecaches[mc].pkg_pepvpr[taskfn]
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500949 depend_tree["pn"][pn]["version"] = version
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600950 rdepends = self.recipecaches[mc].rundeps[taskfn]
951 rrecs = self.recipecaches[mc].runrecs[taskfn]
952 depend_tree["pn"][pn]["inherits"] = self.recipecaches[mc].inherits.get(taskfn, None)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500953
954 # for all extra attributes stored, add them to the dependency tree
955 for ei in extra_info:
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600956 depend_tree["pn"][pn][ei] = vars(self.recipecaches[mc])[ei][taskfn]
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500957
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600958 if taskfn not in seen_fns:
959 seen_fns.append(taskfn)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500960
961 depend_tree["depends"][pn] = []
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500962 for dep in taskdata[mc].depids[taskfn]:
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500963 pn_provider = ""
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600964 if dep in taskdata[mc].build_targets and taskdata[mc].build_targets[dep]:
965 fn_provider = taskdata[mc].build_targets[dep][0]
966 pn_provider = self.recipecaches[mc].pkg_fn[fn_provider]
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500967 else:
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500968 pn_provider = dep
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600969 pn_provider = self.add_mc_prefix(mc, pn_provider)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500970 depend_tree["depends"][pn].append(pn_provider)
971
972 depend_tree["rdepends-pn"][pn] = []
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600973 for rdep in taskdata[mc].rdepids[taskfn]:
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500974 pn_rprovider = ""
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600975 if rdep in taskdata[mc].run_targets and taskdata[mc].run_targets[rdep]:
976 fn_rprovider = taskdata[mc].run_targets[rdep][0]
977 pn_rprovider = self.recipecaches[mc].pkg_fn[fn_rprovider]
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500978 else:
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600979 pn_rprovider = rdep
980 pn_rprovider = self.add_mc_prefix(mc, pn_rprovider)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500981 depend_tree["rdepends-pn"][pn].append(pn_rprovider)
982
983 depend_tree["rdepends-pkg"].update(rdepends)
984 depend_tree["rrecs-pkg"].update(rrecs)
985
986 return depend_tree
987
988 def generateDepTreeEvent(self, pkgs_to_build, task):
989 """
990 Create a task dependency graph of pkgs_to_build.
991 Generate an event with the result
992 """
993 depgraph = self.generateTaskDepTreeData(pkgs_to_build, task)
994 bb.event.fire(bb.event.DepTreeGenerated(depgraph), self.data)
995
996 def generateDotGraphFiles(self, pkgs_to_build, task):
997 """
998 Create a task dependency graph of pkgs_to_build.
999 Save the result to a set of .dot files.
1000 """
1001
1002 depgraph = self.generateTaskDepTreeData(pkgs_to_build, task)
1003
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001004 with open('pn-buildlist', 'w') as f:
1005 for pn in depgraph["pn"]:
1006 f.write(pn + "\n")
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001007 logger.info("PN build list saved to 'pn-buildlist'")
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001008
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001009 # Remove old format output files to ensure no confusion with stale data
1010 try:
1011 os.unlink('pn-depends.dot')
1012 except FileNotFoundError:
1013 pass
1014 try:
1015 os.unlink('package-depends.dot')
1016 except FileNotFoundError:
1017 pass
Brad Bishop79641f22019-09-10 07:20:22 -04001018 try:
1019 os.unlink('recipe-depends.dot')
1020 except FileNotFoundError:
1021 pass
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001022
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001023 with open('task-depends.dot', 'w') as f:
1024 f.write("digraph depends {\n")
Brad Bishop316dfdd2018-06-25 12:45:53 -04001025 for task in sorted(depgraph["tdepends"]):
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001026 (pn, taskname) = task.rsplit(".", 1)
1027 fn = depgraph["pn"][pn]["filename"]
1028 version = depgraph["pn"][pn]["version"]
1029 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 -04001030 for dep in sorted(depgraph["tdepends"][task]):
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001031 f.write('"%s" -> "%s"\n' % (task, dep))
1032 f.write("}\n")
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001033 logger.info("Task dependencies saved to 'task-depends.dot'")
1034
1035 def show_appends_with_no_recipes(self):
Andrew Geissler5a43b432020-06-13 10:46:56 -05001036 appends_without_recipes = {}
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001037 # Determine which bbappends haven't been applied
Andrew Geissler5a43b432020-06-13 10:46:56 -05001038 for mc in self.multiconfigs:
1039 # First get list of recipes, including skipped
1040 recipefns = list(self.recipecaches[mc].pkg_fn.keys())
1041 recipefns.extend(self.skiplist.keys())
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001042
Andrew Geissler5a43b432020-06-13 10:46:56 -05001043 # Work out list of bbappends that have been applied
1044 applied_appends = []
1045 for fn in recipefns:
1046 applied_appends.extend(self.collections[mc].get_file_appends(fn))
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001047
Andrew Geissler5a43b432020-06-13 10:46:56 -05001048 appends_without_recipes[mc] = []
1049 for _, appendfn in self.collections[mc].bbappends:
1050 if not appendfn in applied_appends:
1051 appends_without_recipes[mc].append(appendfn)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001052
Andrew Geissler5a43b432020-06-13 10:46:56 -05001053 msgs = []
1054 for mc in sorted(appends_without_recipes.keys()):
1055 if appends_without_recipes[mc]:
1056 msgs.append('No recipes in %s available for:\n %s' % (mc if mc else 'default',
1057 '\n '.join(appends_without_recipes[mc])))
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001058
Andrew Geissler5a43b432020-06-13 10:46:56 -05001059 if msgs:
1060 msg = "\n".join(msgs)
1061 warn_only = self.databuilder.mcdata[mc].getVar("BB_DANGLINGAPPENDS_WARNONLY", \
1062 False) or "no"
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001063 if warn_only.lower() in ("1", "yes", "true"):
1064 bb.warn(msg)
1065 else:
1066 bb.fatal(msg)
1067
1068 def handlePrefProviders(self):
1069
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001070 for mc in self.multiconfigs:
1071 localdata = data.createCopy(self.databuilder.mcdata[mc])
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001072 bb.data.expandKeys(localdata)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001073
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001074 # Handle PREFERRED_PROVIDERS
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001075 for p in (localdata.getVar('PREFERRED_PROVIDERS') or "").split():
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001076 try:
1077 (providee, provider) = p.split(':')
1078 except:
1079 providerlog.critical("Malformed option in PREFERRED_PROVIDERS variable: %s" % p)
1080 continue
1081 if providee in self.recipecaches[mc].preferred and self.recipecaches[mc].preferred[providee] != provider:
1082 providerlog.error("conflicting preferences for %s: both %s and %s specified", providee, provider, self.recipecaches[mc].preferred[providee])
1083 self.recipecaches[mc].preferred[providee] = provider
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001084
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001085 def findConfigFilePath(self, configfile):
1086 """
1087 Find the location on disk of configfile and if it exists and was parsed by BitBake
1088 emit the ConfigFilePathFound event with the path to the file.
1089 """
1090 path = bb.cookerdata.findConfigFile(configfile, self.data)
1091 if not path:
1092 return
1093
1094 # Generate a list of parsed configuration files by searching the files
1095 # listed in the __depends and __base_depends variables with a .conf suffix.
1096 conffiles = []
1097 dep_files = self.data.getVar('__base_depends', False) or []
1098 dep_files = dep_files + (self.data.getVar('__depends', False) or [])
1099
1100 for f in dep_files:
1101 if f[0].endswith(".conf"):
1102 conffiles.append(f[0])
1103
1104 _, conf, conffile = path.rpartition("conf/")
1105 match = os.path.join(conf, conffile)
1106 # Try and find matches for conf/conffilename.conf as we don't always
1107 # have the full path to the file.
1108 for cfg in conffiles:
1109 if cfg.endswith(match):
1110 bb.event.fire(bb.event.ConfigFilePathFound(path),
1111 self.data)
1112 break
1113
1114 def findFilesMatchingInDir(self, filepattern, directory):
1115 """
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001116 Searches for files containing the substring 'filepattern' which are children of
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001117 'directory' in each BBPATH. i.e. to find all rootfs package classes available
1118 to BitBake one could call findFilesMatchingInDir(self, 'rootfs_', 'classes')
1119 or to find all machine configuration files one could call:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001120 findFilesMatchingInDir(self, '.conf', 'conf/machine')
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001121 """
1122
1123 matches = []
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001124 bbpaths = self.data.getVar('BBPATH').split(':')
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001125 for path in bbpaths:
1126 dirpath = os.path.join(path, directory)
1127 if os.path.exists(dirpath):
1128 for root, dirs, files in os.walk(dirpath):
1129 for f in files:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001130 if filepattern in f:
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001131 matches.append(f)
1132
1133 if matches:
1134 bb.event.fire(bb.event.FilesMatchingFound(filepattern, matches), self.data)
1135
Patrick Williams93c203f2021-10-06 16:15:23 -05001136 def testCookerCommandEvent(self, filepattern):
1137 # Dummy command used by OEQA selftest to test tinfoil without IO
1138 matches = ["A", "B"]
1139 bb.event.fire(bb.event.FilesMatchingFound(filepattern, matches), self.data)
1140
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001141 def findProviders(self, mc=''):
Andrew Geissler82c905d2020-04-13 13:39:40 -05001142 return bb.providers.findProviders(self.databuilder.mcdata[mc], self.recipecaches[mc], self.recipecaches[mc].pkg_pn)
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001143
1144 def findBestProvider(self, pn, mc=''):
1145 if pn in self.recipecaches[mc].providers:
1146 filenames = self.recipecaches[mc].providers[pn]
Andrew Geissler82c905d2020-04-13 13:39:40 -05001147 eligible, foundUnique = bb.providers.filterProviders(filenames, pn, self.databuilder.mcdata[mc], self.recipecaches[mc])
Andrew Geissler95ac1b82021-03-31 14:34:31 -05001148 if eligible is not None:
1149 filename = eligible[0]
1150 else:
1151 filename = None
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001152 return None, None, None, filename
1153 elif pn in self.recipecaches[mc].pkg_pn:
Andrew Geissler95ac1b82021-03-31 14:34:31 -05001154 (latest, latest_f, preferred_ver, preferred_file, required) = bb.providers.findBestProvider(pn, self.databuilder.mcdata[mc], self.recipecaches[mc], self.recipecaches[mc].pkg_pn)
1155 if required and preferred_file is None:
1156 return None, None, None, None
1157 return (latest, latest_f, preferred_ver, preferred_file)
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001158 else:
1159 return None, None, None, None
1160
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001161 def findConfigFiles(self, varname):
1162 """
1163 Find config files which are appropriate values for varname.
1164 i.e. MACHINE, DISTRO
1165 """
1166 possible = []
1167 var = varname.lower()
1168
1169 data = self.data
1170 # iterate configs
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001171 bbpaths = data.getVar('BBPATH').split(':')
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001172 for path in bbpaths:
1173 confpath = os.path.join(path, "conf", var)
1174 if os.path.exists(confpath):
1175 for root, dirs, files in os.walk(confpath):
1176 # get all child files, these are appropriate values
1177 for f in files:
1178 val, sep, end = f.rpartition('.')
1179 if end == 'conf':
1180 possible.append(val)
1181
1182 if possible:
1183 bb.event.fire(bb.event.ConfigFilesFound(var, possible), self.data)
1184
1185 def findInheritsClass(self, klass):
1186 """
1187 Find all recipes which inherit the specified class
1188 """
1189 pkg_list = []
1190
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001191 for pfn in self.recipecaches[''].pkg_fn:
1192 inherits = self.recipecaches[''].inherits.get(pfn, None)
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001193 if inherits and klass in inherits:
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001194 pkg_list.append(self.recipecaches[''].pkg_fn[pfn])
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001195
1196 return pkg_list
1197
1198 def generateTargetsTree(self, klass=None, pkgs=None):
1199 """
1200 Generate a dependency tree of buildable targets
1201 Generate an event with the result
1202 """
1203 # if the caller hasn't specified a pkgs list default to universe
1204 if not pkgs:
1205 pkgs = ['universe']
1206 # if inherited_class passed ensure all recipes which inherit the
1207 # specified class are included in pkgs
1208 if klass:
1209 extra_pkgs = self.findInheritsClass(klass)
1210 pkgs = pkgs + extra_pkgs
1211
1212 # generate a dependency tree for all our packages
1213 tree = self.generatePkgDepTreeData(pkgs, 'build')
1214 bb.event.fire(bb.event.TargetsTreeGenerated(tree), self.data)
1215
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001216 def interactiveMode( self ):
1217 """Drop off into a shell"""
1218 try:
1219 from bb import shell
1220 except ImportError:
1221 parselog.exception("Interactive mode not available")
Andrew Geisslerc9f78652020-09-18 14:11:35 -05001222 raise bb.BBHandledException()
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001223 else:
1224 shell.start( self )
1225
1226
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001227 def handleCollections(self, collections):
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001228 """Handle collections"""
1229 errors = False
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001230 self.bbfile_config_priorities = []
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001231 if collections:
1232 collection_priorities = {}
1233 collection_depends = {}
1234 collection_list = collections.split()
1235 min_prio = 0
1236 for c in collection_list:
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001237 bb.debug(1,'Processing %s in collection list' % (c))
1238
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001239 # Get collection priority if defined explicitly
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001240 priority = self.data.getVar("BBFILE_PRIORITY_%s" % c)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001241 if priority:
1242 try:
1243 prio = int(priority)
1244 except ValueError:
1245 parselog.error("invalid value for BBFILE_PRIORITY_%s: \"%s\"", c, priority)
1246 errors = True
1247 if min_prio == 0 or prio < min_prio:
1248 min_prio = prio
1249 collection_priorities[c] = prio
1250 else:
1251 collection_priorities[c] = None
1252
1253 # Check dependencies and store information for priority calculation
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001254 deps = self.data.getVar("LAYERDEPENDS_%s" % c)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001255 if deps:
1256 try:
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001257 depDict = bb.utils.explode_dep_versions2(deps)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001258 except bb.utils.VersionStringException as vse:
1259 bb.fatal('Error parsing LAYERDEPENDS_%s: %s' % (c, str(vse)))
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001260 for dep, oplist in list(depDict.items()):
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001261 if dep in collection_list:
1262 for opstr in oplist:
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001263 layerver = self.data.getVar("LAYERVERSION_%s" % dep)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001264 (op, depver) = opstr.split()
1265 if layerver:
1266 try:
1267 res = bb.utils.vercmp_string_op(layerver, depver, op)
1268 except bb.utils.VersionStringException as vse:
1269 bb.fatal('Error parsing LAYERDEPENDS_%s: %s' % (c, str(vse)))
1270 if not res:
1271 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)
1272 errors = True
1273 else:
1274 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)
1275 errors = True
1276 else:
1277 parselog.error("Layer '%s' depends on layer '%s', but this layer is not enabled in your configuration", c, dep)
1278 errors = True
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001279 collection_depends[c] = list(depDict.keys())
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001280 else:
1281 collection_depends[c] = []
1282
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001283 # Check recommends and store information for priority calculation
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001284 recs = self.data.getVar("LAYERRECOMMENDS_%s" % c)
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001285 if recs:
1286 try:
1287 recDict = bb.utils.explode_dep_versions2(recs)
1288 except bb.utils.VersionStringException as vse:
1289 bb.fatal('Error parsing LAYERRECOMMENDS_%s: %s' % (c, str(vse)))
1290 for rec, oplist in list(recDict.items()):
1291 if rec in collection_list:
1292 if oplist:
1293 opstr = oplist[0]
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001294 layerver = self.data.getVar("LAYERVERSION_%s" % rec)
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001295 if layerver:
1296 (op, recver) = opstr.split()
1297 try:
1298 res = bb.utils.vercmp_string_op(layerver, recver, op)
1299 except bb.utils.VersionStringException as vse:
1300 bb.fatal('Error parsing LAYERRECOMMENDS_%s: %s' % (c, str(vse)))
1301 if not res:
Andrew Geissler87f5cff2022-09-30 13:13:31 -05001302 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 -06001303 continue
1304 else:
Andrew Geissler87f5cff2022-09-30 13:13:31 -05001305 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 -06001306 continue
Andrew Geissler87f5cff2022-09-30 13:13:31 -05001307 parselog.debug3("Layer '%s' recommends layer '%s', so we are adding it", c, rec)
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001308 collection_depends[c].append(rec)
1309 else:
Andrew Geissler87f5cff2022-09-30 13:13:31 -05001310 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 -06001311
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001312 # Recursively work out collection priorities based on dependencies
1313 def calc_layer_priority(collection):
1314 if not collection_priorities[collection]:
1315 max_depprio = min_prio
1316 for dep in collection_depends[collection]:
1317 calc_layer_priority(dep)
1318 depprio = collection_priorities[dep]
1319 if depprio > max_depprio:
1320 max_depprio = depprio
1321 max_depprio += 1
Andrew Geissler87f5cff2022-09-30 13:13:31 -05001322 parselog.debug("Calculated priority of layer %s as %d", collection, max_depprio)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001323 collection_priorities[collection] = max_depprio
1324
1325 # Calculate all layer priorities using calc_layer_priority and store in bbfile_config_priorities
1326 for c in collection_list:
1327 calc_layer_priority(c)
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001328 regex = self.data.getVar("BBFILE_PATTERN_%s" % c)
Andrew Geissler82c905d2020-04-13 13:39:40 -05001329 if regex is None:
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001330 parselog.error("BBFILE_PATTERN_%s not defined" % c)
1331 errors = True
1332 continue
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001333 elif regex == "":
Andrew Geissler87f5cff2022-09-30 13:13:31 -05001334 parselog.debug("BBFILE_PATTERN_%s is empty" % c)
Brad Bishop19323692019-04-05 15:28:33 -04001335 cre = re.compile('^NULL$')
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001336 errors = False
1337 else:
1338 try:
1339 cre = re.compile(regex)
1340 except re.error:
1341 parselog.error("BBFILE_PATTERN_%s \"%s\" is not a valid regular expression", c, regex)
1342 errors = True
1343 continue
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001344 self.bbfile_config_priorities.append((c, regex, cre, collection_priorities[c]))
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001345 if errors:
1346 # We've already printed the actual error(s)
1347 raise CollectionError("Errors during parsing layer configuration")
1348
1349 def buildSetVars(self):
1350 """
1351 Setup any variables needed before starting a build
1352 """
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001353 t = time.gmtime()
1354 for mc in self.databuilder.mcdata:
1355 ds = self.databuilder.mcdata[mc]
1356 if not ds.getVar("BUILDNAME", False):
1357 ds.setVar("BUILDNAME", "${DATE}${TIME}")
1358 ds.setVar("BUILDSTART", time.strftime('%m/%d/%Y %H:%M:%S', t))
1359 ds.setVar("DATE", time.strftime('%Y%m%d', t))
1360 ds.setVar("TIME", time.strftime('%H%M%S', t))
1361
1362 def reset_mtime_caches(self):
1363 """
1364 Reset mtime caches - this is particularly important when memory resident as something
1365 which is cached is not unlikely to have changed since the last invocation (e.g. a
1366 file associated with a recipe might have been modified by the user).
1367 """
1368 build.reset_cache()
1369 bb.fetch._checksum_cache.mtime_cache.clear()
1370 siggen_cache = getattr(bb.parse.siggen, 'checksum_cache', None)
1371 if siggen_cache:
1372 bb.parse.siggen.checksum_cache.mtime_cache.clear()
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001373
Andrew Geissler5a43b432020-06-13 10:46:56 -05001374 def matchFiles(self, bf, mc=''):
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001375 """
1376 Find the .bb files which match the expression in 'buildfile'.
1377 """
1378 if bf.startswith("/") or bf.startswith("../"):
1379 bf = os.path.abspath(bf)
1380
Andrew Geissler5a43b432020-06-13 10:46:56 -05001381 self.collections = {mc: CookerCollectFiles(self.bbfile_config_priorities, mc)}
1382 filelist, masked, searchdirs = self.collections[mc].collect_bbfiles(self.databuilder.mcdata[mc], self.databuilder.mcdata[mc])
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001383 try:
1384 os.stat(bf)
1385 bf = os.path.abspath(bf)
1386 return [bf]
1387 except OSError:
1388 regexp = re.compile(bf)
1389 matches = []
1390 for f in filelist:
1391 if regexp.search(f) and os.path.isfile(f):
1392 matches.append(f)
1393 return matches
1394
Andrew Geissler5a43b432020-06-13 10:46:56 -05001395 def matchFile(self, buildfile, mc=''):
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001396 """
1397 Find the .bb file which matches the expression in 'buildfile'.
1398 Raise an error if multiple files
1399 """
Andrew Geissler5a43b432020-06-13 10:46:56 -05001400 matches = self.matchFiles(buildfile, mc)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001401 if len(matches) != 1:
1402 if matches:
1403 msg = "Unable to match '%s' to a specific recipe file - %s matches found:" % (buildfile, len(matches))
1404 if matches:
1405 for f in matches:
1406 msg += "\n %s" % f
1407 parselog.error(msg)
1408 else:
1409 parselog.error("Unable to find any recipe file matching '%s'" % buildfile)
1410 raise NoSpecificMatch
1411 return matches[0]
1412
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001413 def buildFile(self, buildfile, task):
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001414 """
1415 Build the file matching regexp buildfile
1416 """
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001417 bb.event.fire(bb.event.BuildInit(), self.data)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001418
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001419 # Too many people use -b because they think it's how you normally
1420 # specify a target to be built, so show a warning
1421 bb.warn("Buildfile specified, dependencies will not be handled. If this is not what you want, do not use -b / --buildfile.")
1422
1423 self.buildFileInternal(buildfile, task)
1424
1425 def buildFileInternal(self, buildfile, task, fireevents=True, quietlog=False):
1426 """
1427 Build the file matching regexp buildfile
1428 """
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001429
1430 # Parse the configuration here. We need to do it explicitly here since
1431 # buildFile() doesn't use the cache
1432 self.parseConfiguration()
1433
1434 # If we are told to do the None task then query the default task
Andrew Geissler82c905d2020-04-13 13:39:40 -05001435 if task is None:
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001436 task = self.configuration.cmd
Brad Bishop37a0e4d2017-12-04 01:01:44 -05001437 if not task.startswith("do_"):
1438 task = "do_%s" % task
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001439
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001440 fn, cls, mc = bb.cache.virtualfn2realfn(buildfile)
Andrew Geissler5a43b432020-06-13 10:46:56 -05001441 fn = self.matchFile(fn, mc)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001442
1443 self.buildSetVars()
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001444 self.reset_mtime_caches()
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001445
Andrew Geissler5a43b432020-06-13 10:46:56 -05001446 bb_caches = bb.cache.MulticonfigCache(self.databuilder, self.data_hash, self.caches_array)
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001447
Andrew Geissler5a43b432020-06-13 10:46:56 -05001448 infos = bb_caches[mc].parse(fn, self.collections[mc].get_file_appends(fn))
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001449 infos = dict(infos)
1450
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001451 fn = bb.cache.realfn2virtual(fn, cls, mc)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001452 try:
1453 info_array = infos[fn]
1454 except KeyError:
1455 bb.fatal("%s does not exist" % fn)
1456
1457 if info_array[0].skipped:
1458 bb.fatal("%s was skipped: %s" % (fn, info_array[0].skipreason))
1459
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001460 self.recipecaches[mc].add_from_recipeinfo(fn, info_array)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001461
1462 # Tweak some variables
1463 item = info_array[0].pn
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001464 self.recipecaches[mc].ignored_dependencies = set()
1465 self.recipecaches[mc].bbfile_priority[fn] = 1
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001466 self.configuration.limited_deps = True
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001467
1468 # Remove external dependencies
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001469 self.recipecaches[mc].task_deps[fn]['depends'] = {}
1470 self.recipecaches[mc].deps[fn] = []
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001471 self.recipecaches[mc].rundeps[fn] = defaultdict(list)
1472 self.recipecaches[mc].runrecs[fn] = defaultdict(list)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001473
Andrew Geissler517393d2023-01-13 08:55:19 -06001474 bb.parse.siggen.setup_datacache(self.recipecaches)
1475
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001476 # Invalidate task for target if force mode active
1477 if self.configuration.force:
1478 logger.verbose("Invalidate task %s, %s", task, fn)
Andrew Geissler517393d2023-01-13 08:55:19 -06001479 bb.parse.siggen.invalidate_task(task, fn)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001480
1481 # Setup taskdata structure
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001482 taskdata = {}
Andrew Geissler7e0e3c02022-02-25 20:34:39 +00001483 taskdata[mc] = bb.taskdata.TaskData(self.configuration.halt)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001484 taskdata[mc].add_provider(self.databuilder.mcdata[mc], self.recipecaches[mc], item)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001485
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001486 if quietlog:
1487 rqloglevel = bb.runqueue.logger.getEffectiveLevel()
1488 bb.runqueue.logger.setLevel(logging.WARNING)
1489
1490 buildname = self.databuilder.mcdata[mc].getVar("BUILDNAME")
1491 if fireevents:
1492 bb.event.fire(bb.event.BuildStarted(buildname, [item]), self.databuilder.mcdata[mc])
Andrew Geissler517393d2023-01-13 08:55:19 -06001493 bb.event.enable_heartbeat()
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001494
1495 # Execute the runqueue
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001496 runlist = [[mc, item, task, fn]]
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001497
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001498 rq = bb.runqueue.RunQueue(self, self.data, self.recipecaches, taskdata, runlist)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001499
Andrew Geissler7e0e3c02022-02-25 20:34:39 +00001500 def buildFileIdle(server, rq, halt):
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001501
1502 msg = None
1503 interrupted = 0
Andrew Geissler7e0e3c02022-02-25 20:34:39 +00001504 if halt or self.state == state.forceshutdown:
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001505 rq.finish_runqueue(True)
1506 msg = "Forced shutdown"
1507 interrupted = 2
1508 elif self.state == state.shutdown:
1509 rq.finish_runqueue(False)
1510 msg = "Stopped build"
1511 interrupted = 1
1512 failures = 0
1513 try:
1514 retval = rq.execute_runqueue()
1515 except runqueue.TaskFailure as exc:
1516 failures += len(exc.args)
1517 retval = False
1518 except SystemExit as exc:
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001519 if quietlog:
1520 bb.runqueue.logger.setLevel(rqloglevel)
Andrew Geissler517393d2023-01-13 08:55:19 -06001521 return bb.server.process.idleFinish(str(exc))
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001522
1523 if not retval:
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001524 if fireevents:
1525 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 -06001526 bb.event.disable_heartbeat()
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001527 # We trashed self.recipecaches above
Andrew Geissler028142b2023-05-05 11:29:21 -05001528 self._parsecache_set(False)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001529 self.configuration.limited_deps = False
1530 bb.parse.siggen.reset(self.data)
1531 if quietlog:
1532 bb.runqueue.logger.setLevel(rqloglevel)
Andrew Geissler517393d2023-01-13 08:55:19 -06001533 return bb.server.process.idleFinish(msg)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001534 if retval is True:
1535 return True
1536 return retval
1537
Andrew Geissler635e0e42020-08-21 15:58:33 -05001538 self.idleCallBackRegister(buildFileIdle, rq)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001539
1540 def buildTargets(self, targets, task):
1541 """
1542 Attempt to build the targets specified
1543 """
1544
Andrew Geissler7e0e3c02022-02-25 20:34:39 +00001545 def buildTargetsIdle(server, rq, halt):
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001546 msg = None
1547 interrupted = 0
Andrew Geissler7e0e3c02022-02-25 20:34:39 +00001548 if halt or self.state == state.forceshutdown:
Andrew Geissler6aa7eec2023-03-03 12:41:14 -06001549 bb.event._should_exit.set()
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001550 rq.finish_runqueue(True)
1551 msg = "Forced shutdown"
1552 interrupted = 2
1553 elif self.state == state.shutdown:
1554 rq.finish_runqueue(False)
1555 msg = "Stopped build"
1556 interrupted = 1
1557 failures = 0
1558 try:
1559 retval = rq.execute_runqueue()
1560 except runqueue.TaskFailure as exc:
1561 failures += len(exc.args)
1562 retval = False
1563 except SystemExit as exc:
Andrew Geissler517393d2023-01-13 08:55:19 -06001564 return bb.server.process.idleFinish(str(exc))
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001565
1566 if not retval:
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001567 try:
1568 for mc in self.multiconfigs:
1569 bb.event.fire(bb.event.BuildCompleted(len(rq.rqdata.runtaskentries), buildname, targets, failures, interrupted), self.databuilder.mcdata[mc])
1570 finally:
Andrew Geissler517393d2023-01-13 08:55:19 -06001571 bb.event.disable_heartbeat()
1572 return bb.server.process.idleFinish(msg)
1573
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001574 if retval is True:
1575 return True
1576 return retval
1577
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001578 self.reset_mtime_caches()
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001579 self.buildSetVars()
1580
Patrick Williamsf1e5d692016-03-30 15:21:19 -05001581 # If we are told to do the None task then query the default task
Andrew Geissler82c905d2020-04-13 13:39:40 -05001582 if task is None:
Patrick Williamsf1e5d692016-03-30 15:21:19 -05001583 task = self.configuration.cmd
1584
1585 if not task.startswith("do_"):
1586 task = "do_%s" % task
1587
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001588 packages = [target if ':' in target else '%s:%s' % (target, task) for target in targets]
1589
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001590 bb.event.fire(bb.event.BuildInit(packages), self.data)
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001591
Andrew Geissler7e0e3c02022-02-25 20:34:39 +00001592 taskdata, runlist = self.buildTaskData(targets, task, self.configuration.halt)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001593
1594 buildname = self.data.getVar("BUILDNAME", False)
Patrick Williamsf1e5d692016-03-30 15:21:19 -05001595
1596 # make targets to always look as <target>:do_<task>
1597 ntargets = []
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001598 for target in runlist:
1599 if target[0]:
Brad Bishop15ae2502019-06-18 21:44:24 -04001600 ntargets.append("mc:%s:%s:%s" % (target[0], target[1], target[2]))
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001601 ntargets.append("%s:%s" % (target[1], target[2]))
Patrick Williamsf1e5d692016-03-30 15:21:19 -05001602
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001603 for mc in self.multiconfigs:
1604 bb.event.fire(bb.event.BuildStarted(buildname, ntargets), self.databuilder.mcdata[mc])
Andrew Geissler517393d2023-01-13 08:55:19 -06001605 bb.event.enable_heartbeat()
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001606
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001607 rq = bb.runqueue.RunQueue(self, self.data, self.recipecaches, taskdata, runlist)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001608 if 'universe' in targets:
1609 rq.rqdata.warn_multi_bb = True
1610
Andrew Geissler635e0e42020-08-21 15:58:33 -05001611 self.idleCallBackRegister(buildTargetsIdle, rq)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001612
1613
1614 def getAllKeysWithFlags(self, flaglist):
1615 dump = {}
1616 for k in self.data.keys():
1617 try:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001618 expand = True
1619 flags = self.data.getVarFlags(k)
1620 if flags and "func" in flags and "python" in flags:
1621 expand = False
1622 v = self.data.getVar(k, expand)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001623 if not k.startswith("__") and not isinstance(v, bb.data_smart.DataSmart):
1624 dump[k] = {
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001625 'v' : str(v) ,
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001626 'history' : self.data.varhistory.variable(k),
1627 }
1628 for d in flaglist:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001629 if flags and d in flags:
1630 dump[k][d] = flags[d]
1631 else:
1632 dump[k][d] = None
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001633 except Exception as e:
1634 print(e)
1635 return dump
1636
1637
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001638 def updateCacheSync(self):
1639 if self.state == state.running:
1640 return
1641
Andrew Geissler6aa7eec2023-03-03 12:41:14 -06001642 self.handle_inotify_updates()
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001643
1644 if not self.baseconfig_valid:
Andrew Geisslerd1e89492021-02-12 15:35:20 -06001645 logger.debug("Reloading base configuration data")
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001646 self.initConfigurationData()
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001647 self.handlePRServ()
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001648
1649 # This is called for all async commands when self.state != running
1650 def updateCache(self):
1651 if self.state == state.running:
1652 return
1653
1654 if self.state in (state.shutdown, state.forceshutdown, state.error):
1655 if hasattr(self.parser, 'shutdown'):
Andrew Geissler9aee5002022-03-30 16:27:02 +00001656 self.parser.shutdown(clean=False)
Andrew Geisslerc9f78652020-09-18 14:11:35 -05001657 self.parser.final_cleanup()
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001658 raise bb.BBHandledException()
1659
1660 if self.state != state.parsing:
1661 self.updateCacheSync()
1662
1663 if self.state != state.parsing and not self.parsecache_valid:
Patrick Williamsde0582f2022-04-08 10:23:27 -05001664 self.setupParserWatcher()
1665
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001666 bb.parse.siggen.reset(self.data)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001667 self.parseConfiguration ()
1668 if CookerFeatures.SEND_SANITYEVENTS in self.featureset:
Brad Bishop37a0e4d2017-12-04 01:01:44 -05001669 for mc in self.multiconfigs:
1670 bb.event.fire(bb.event.SanityCheck(False), self.databuilder.mcdata[mc])
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001671
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001672 for mc in self.multiconfigs:
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001673 ignore = self.databuilder.mcdata[mc].getVar("ASSUME_PROVIDED") or ""
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001674 self.recipecaches[mc].ignored_dependencies = set(ignore.split())
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001675
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001676 for dep in self.configuration.extra_assume_provided:
1677 self.recipecaches[mc].ignored_dependencies.add(dep)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001678
Andrew Geissler5a43b432020-06-13 10:46:56 -05001679 self.collections = {}
1680
1681 mcfilelist = {}
1682 total_masked = 0
1683 searchdirs = set()
1684 for mc in self.multiconfigs:
1685 self.collections[mc] = CookerCollectFiles(self.bbfile_config_priorities, mc)
1686 (filelist, masked, search) = self.collections[mc].collect_bbfiles(self.databuilder.mcdata[mc], self.databuilder.mcdata[mc])
1687
1688 mcfilelist[mc] = filelist
1689 total_masked += masked
1690 searchdirs |= set(search)
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001691
1692 # Add inotify watches for directories searched for bb/bbappend files
1693 for dirent in searchdirs:
1694 self.add_filewatch([[dirent]], dirs=True)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001695
Andrew Geissler5a43b432020-06-13 10:46:56 -05001696 self.parser = CookerParser(self, mcfilelist, total_masked)
Andrew Geissler028142b2023-05-05 11:29:21 -05001697 self._parsecache_set(True)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001698
1699 self.state = state.parsing
1700
1701 if not self.parser.parse_next():
Andrew Geissler87f5cff2022-09-30 13:13:31 -05001702 collectlog.debug("parsing complete")
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001703 if self.parser.error:
1704 raise bb.BBHandledException()
1705 self.show_appends_with_no_recipes()
1706 self.handlePrefProviders()
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001707 for mc in self.multiconfigs:
Andrew Geisslerb7d28612020-07-24 16:15:54 -05001708 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 -05001709 self.state = state.running
1710
1711 # Send an event listing all stamps reachable after parsing
1712 # which the metadata may use to clean up stale data
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001713 for mc in self.multiconfigs:
1714 event = bb.event.ReachableStamps(self.recipecaches[mc].stamp)
1715 bb.event.fire(event, self.databuilder.mcdata[mc])
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001716 return None
1717
1718 return True
1719
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001720 def checkPackages(self, pkgs_to_build, task=None):
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001721
1722 # Return a copy, don't modify the original
1723 pkgs_to_build = pkgs_to_build[:]
1724
Andrew Geissler595f6302022-01-24 19:11:47 +00001725 if not pkgs_to_build:
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001726 raise NothingToBuild
1727
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001728 ignore = (self.data.getVar("ASSUME_PROVIDED") or "").split()
Andrew Geisslerb7d28612020-07-24 16:15:54 -05001729 for pkg in pkgs_to_build.copy():
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001730 if pkg in ignore:
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001731 parselog.warning("Explicit target \"%s\" is in ASSUME_PROVIDED, ignoring" % pkg)
Brad Bishop15ae2502019-06-18 21:44:24 -04001732 if pkg.startswith("multiconfig:"):
1733 pkgs_to_build.remove(pkg)
1734 pkgs_to_build.append(pkg.replace("multiconfig:", "mc:"))
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001735
1736 if 'world' in pkgs_to_build:
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001737 pkgs_to_build.remove('world')
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001738 for mc in self.multiconfigs:
1739 bb.providers.buildWorldTargetList(self.recipecaches[mc], task)
1740 for t in self.recipecaches[mc].world_target:
1741 if mc:
Brad Bishop15ae2502019-06-18 21:44:24 -04001742 t = "mc:" + mc + ":" + t
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001743 pkgs_to_build.append(t)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001744
1745 if 'universe' in pkgs_to_build:
Brad Bishop1a4b7ee2018-12-16 17:11:34 -08001746 parselog.verbnote("The \"universe\" target is only intended for testing and may produce errors.")
Andrew Geissler87f5cff2022-09-30 13:13:31 -05001747 parselog.debug("collating packages for \"universe\"")
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001748 pkgs_to_build.remove('universe')
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001749 for mc in self.multiconfigs:
1750 for t in self.recipecaches[mc].universe_target:
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001751 if task:
1752 foundtask = False
1753 for provider_fn in self.recipecaches[mc].providers[t]:
1754 if task in self.recipecaches[mc].task_deps[provider_fn]['tasks']:
1755 foundtask = True
1756 break
1757 if not foundtask:
1758 bb.debug(1, "Skipping %s for universe tasks as task %s doesn't exist" % (t, task))
1759 continue
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001760 if mc:
Brad Bishop15ae2502019-06-18 21:44:24 -04001761 t = "mc:" + mc + ":" + t
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001762 pkgs_to_build.append(t)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001763
1764 return pkgs_to_build
1765
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001766 def pre_serve(self):
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001767 return
1768
1769 def post_serve(self):
Andrew Geisslerc9f78652020-09-18 14:11:35 -05001770 self.shutdown(force=True)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001771 prserv.serv.auto_shutdown()
Patrick Williams45852732022-04-02 08:58:32 -05001772 if hasattr(bb.parse, "siggen"):
1773 bb.parse.siggen.exit()
Brad Bishop08902b02019-08-20 09:16:51 -04001774 if self.hashserv:
1775 self.hashserv.process.terminate()
1776 self.hashserv.process.join()
Andrew Geisslerc3d88e42020-10-02 09:45:00 -05001777 if hasattr(self, "data"):
1778 bb.event.fire(CookerExit(), self.data)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001779
Andrew Geissler517393d2023-01-13 08:55:19 -06001780 def shutdown(self, force=False):
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001781 if force:
1782 self.state = state.forceshutdown
Patrick Williams8e7b46e2023-05-01 14:19:06 -05001783 bb.event._should_exit.set()
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001784 else:
1785 self.state = state.shutdown
1786
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001787 if self.parser:
Andrew Geissler517393d2023-01-13 08:55:19 -06001788 self.parser.shutdown(clean=False)
Andrew Geisslerc9f78652020-09-18 14:11:35 -05001789 self.parser.final_cleanup()
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001790
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001791 def finishcommand(self):
Andrew Geissler517393d2023-01-13 08:55:19 -06001792 if hasattr(self.parser, 'shutdown'):
1793 self.parser.shutdown(clean=False)
1794 self.parser.final_cleanup()
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001795 self.state = state.initial
Andrew Geissler6aa7eec2023-03-03 12:41:14 -06001796 bb.event._should_exit.clear()
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001797
1798 def reset(self):
Patrick Williams45852732022-04-02 08:58:32 -05001799 if hasattr(bb.parse, "siggen"):
1800 bb.parse.siggen.exit()
Andrew Geissler517393d2023-01-13 08:55:19 -06001801 self.finishcommand()
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001802 self.initConfigurationData()
Brad Bishop08902b02019-08-20 09:16:51 -04001803 self.handlePRServ()
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001804
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001805 def clientComplete(self):
1806 """Called when the client is done using the server"""
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001807 self.finishcommand()
1808 self.extraconfigdata = {}
1809 self.command.reset()
Andrew Geisslerc9f78652020-09-18 14:11:35 -05001810 if hasattr(self, "data"):
1811 self.databuilder.reset()
1812 self.data = self.databuilder.data
Andrew Geissler517393d2023-01-13 08:55:19 -06001813 # In theory tinfoil could have modified the base data before parsing,
1814 # ideally need to track if anything did modify the datastore
Andrew Geissler028142b2023-05-05 11:29:21 -05001815 self._parsecache_set(False)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001816
1817class CookerExit(bb.event.Event):
1818 """
1819 Notify clients of the Cooker shutdown
1820 """
1821
1822 def __init__(self):
1823 bb.event.Event.__init__(self)
1824
1825
1826class CookerCollectFiles(object):
Andrew Geissler5a43b432020-06-13 10:46:56 -05001827 def __init__(self, priorities, mc=''):
1828 self.mc = mc
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001829 self.bbappends = []
Andrew Geissler7e0e3c02022-02-25 20:34:39 +00001830 # Priorities is a list of tuples, with the second element as the pattern.
Brad Bishop1a4b7ee2018-12-16 17:11:34 -08001831 # We need to sort the list with the longest pattern first, and so on to
1832 # the shortest. This allows nested layers to be properly evaluated.
1833 self.bbfile_config_priorities = sorted(priorities, key=lambda tup: tup[1], reverse=True)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001834
Andrew Geisslerb7d28612020-07-24 16:15:54 -05001835 def calc_bbfile_priority(self, filename):
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001836 for _, _, regex, pri in self.bbfile_config_priorities:
1837 if regex.match(filename):
Andrew Geisslerb7d28612020-07-24 16:15:54 -05001838 return pri, regex
1839 return 0, None
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001840
1841 def get_bbfiles(self):
1842 """Get list of default .bb files by reading out the current directory"""
1843 path = os.getcwd()
1844 contents = os.listdir(path)
1845 bbfiles = []
1846 for f in contents:
1847 if f.endswith(".bb"):
1848 bbfiles.append(os.path.abspath(os.path.join(path, f)))
1849 return bbfiles
1850
1851 def find_bbfiles(self, path):
1852 """Find all the .bb and .bbappend files in a directory"""
1853 found = []
1854 for dir, dirs, files in os.walk(path):
1855 for ignored in ('SCCS', 'CVS', '.svn'):
1856 if ignored in dirs:
1857 dirs.remove(ignored)
1858 found += [os.path.join(dir, f) for f in files if (f.endswith(['.bb', '.bbappend']))]
1859
1860 return found
1861
1862 def collect_bbfiles(self, config, eventdata):
1863 """Collect all available .bb build files"""
1864 masked = 0
1865
Andrew Geissler87f5cff2022-09-30 13:13:31 -05001866 collectlog.debug("collecting .bb files")
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001867
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001868 files = (config.getVar( "BBFILES") or "").split()
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001869
1870 # Sort files by priority
Andrew Geisslerb7d28612020-07-24 16:15:54 -05001871 files.sort( key=lambda fileitem: self.calc_bbfile_priority(fileitem)[0] )
Andrew Geisslerc9f78652020-09-18 14:11:35 -05001872 config.setVar("BBFILES_PRIORITIZED", " ".join(files))
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001873
Andrew Geissler595f6302022-01-24 19:11:47 +00001874 if not files:
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001875 files = self.get_bbfiles()
1876
Andrew Geissler595f6302022-01-24 19:11:47 +00001877 if not files:
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001878 collectlog.error("no recipe files to build, check your BBPATH and BBFILES?")
1879 bb.event.fire(CookerExit(), eventdata)
1880
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001881 # We need to track where we look so that we can add inotify watches. There
1882 # is no nice way to do this, this is horrid. We intercept the os.listdir()
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001883 # (or os.scandir() for python 3.6+) calls while we run glob().
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001884 origlistdir = os.listdir
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001885 if hasattr(os, 'scandir'):
1886 origscandir = os.scandir
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001887 searchdirs = []
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001888
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001889 def ourlistdir(d):
1890 searchdirs.append(d)
1891 return origlistdir(d)
1892
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001893 def ourscandir(d):
1894 searchdirs.append(d)
1895 return origscandir(d)
1896
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001897 os.listdir = ourlistdir
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001898 if hasattr(os, 'scandir'):
1899 os.scandir = ourscandir
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001900 try:
1901 # Can't use set here as order is important
1902 newfiles = []
1903 for f in files:
1904 if os.path.isdir(f):
1905 dirfiles = self.find_bbfiles(f)
1906 for g in dirfiles:
1907 if g not in newfiles:
1908 newfiles.append(g)
1909 else:
1910 globbed = glob.glob(f)
1911 if not globbed and os.path.exists(f):
1912 globbed = [f]
1913 # glob gives files in order on disk. Sort to be deterministic.
1914 for g in sorted(globbed):
1915 if g not in newfiles:
1916 newfiles.append(g)
1917 finally:
1918 os.listdir = origlistdir
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001919 if hasattr(os, 'scandir'):
1920 os.scandir = origscandir
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001921
1922 bbmask = config.getVar('BBMASK')
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001923
1924 if bbmask:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001925 # First validate the individual regular expressions and ignore any
1926 # that do not compile
1927 bbmasks = []
1928 for mask in bbmask.split():
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001929 # When constructing an older style single regex, it's possible for BBMASK
1930 # to end up beginning with '|', which matches and masks _everything_.
1931 if mask.startswith("|"):
Andrew Geissler82c905d2020-04-13 13:39:40 -05001932 collectlog.warning("BBMASK contains regular expression beginning with '|', fixing: %s" % mask)
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001933 mask = mask[1:]
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001934 try:
1935 re.compile(mask)
1936 bbmasks.append(mask)
Andrew Geissler78b72792022-06-14 06:47:25 -05001937 except re.error:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001938 collectlog.critical("BBMASK contains an invalid regular expression, ignoring: %s" % mask)
1939
1940 # Then validate the combined regular expressions. This should never
1941 # fail, but better safe than sorry...
1942 bbmask = "|".join(bbmasks)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001943 try:
1944 bbmask_compiled = re.compile(bbmask)
Andrew Geissler78b72792022-06-14 06:47:25 -05001945 except re.error:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001946 collectlog.critical("BBMASK is not a valid regular expression, ignoring: %s" % bbmask)
1947 bbmask = None
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001948
1949 bbfiles = []
1950 bbappend = []
1951 for f in newfiles:
1952 if bbmask and bbmask_compiled.search(f):
Andrew Geissler87f5cff2022-09-30 13:13:31 -05001953 collectlog.debug("skipping masked file %s", f)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001954 masked += 1
1955 continue
1956 if f.endswith('.bb'):
1957 bbfiles.append(f)
1958 elif f.endswith('.bbappend'):
1959 bbappend.append(f)
1960 else:
Andrew Geissler87f5cff2022-09-30 13:13:31 -05001961 collectlog.debug("skipping %s: unknown file extension", f)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001962
1963 # Build a list of .bbappend files for each .bb file
1964 for f in bbappend:
1965 base = os.path.basename(f).replace('.bbappend', '.bb')
1966 self.bbappends.append((base, f))
1967
1968 # Find overlayed recipes
1969 # bbfiles will be in priority order which makes this easy
1970 bbfile_seen = dict()
1971 self.overlayed = defaultdict(list)
1972 for f in reversed(bbfiles):
1973 base = os.path.basename(f)
1974 if base not in bbfile_seen:
1975 bbfile_seen[base] = f
1976 else:
1977 topfile = bbfile_seen[base]
1978 self.overlayed[topfile].append(f)
1979
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001980 return (bbfiles, masked, searchdirs)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001981
1982 def get_file_appends(self, fn):
1983 """
1984 Returns a list of .bbappend files to apply to fn
1985 """
1986 filelist = []
1987 f = os.path.basename(fn)
1988 for b in self.bbappends:
1989 (bbappend, filename) = b
1990 if (bbappend == f) or ('%' in bbappend and bbappend.startswith(f[:bbappend.index('%')])):
1991 filelist.append(filename)
Andrew Geissler5a43b432020-06-13 10:46:56 -05001992 return tuple(filelist)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001993
Andrew Geisslerb7d28612020-07-24 16:15:54 -05001994 def collection_priorities(self, pkgfns, fns, d):
1995 # Return the priorities of the entries in pkgfns
1996 # Also check that all the regexes in self.bbfile_config_priorities are used
1997 # (but to do that we need to ensure skipped recipes aren't counted, nor
1998 # collections in BBFILE_PATTERN_IGNORE_EMPTY)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001999
2000 priorities = {}
Andrew Geisslerb7d28612020-07-24 16:15:54 -05002001 seen = set()
2002 matched = set()
2003
2004 matched_regex = set()
2005 unmatched_regex = set()
2006 for _, _, regex, _ in self.bbfile_config_priorities:
2007 unmatched_regex.add(regex)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002008
2009 # Calculate priorities for each file
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002010 for p in pkgfns:
Patrick Williamsc0f7c042017-02-23 20:41:17 -06002011 realfn, cls, mc = bb.cache.virtualfn2realfn(p)
Andrew Geisslerb7d28612020-07-24 16:15:54 -05002012 priorities[p], regex = self.calc_bbfile_priority(realfn)
2013 if regex in unmatched_regex:
2014 matched_regex.add(regex)
2015 unmatched_regex.remove(regex)
2016 seen.add(realfn)
2017 if regex:
2018 matched.add(realfn)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002019
Andrew Geisslerb7d28612020-07-24 16:15:54 -05002020 if unmatched_regex:
2021 # Account for bbappend files
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002022 for b in self.bbappends:
2023 (bbfile, append) = b
Andrew Geisslerb7d28612020-07-24 16:15:54 -05002024 seen.add(append)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002025
Andrew Geisslerb7d28612020-07-24 16:15:54 -05002026 # Account for skipped recipes
2027 seen.update(fns)
2028
2029 seen.difference_update(matched)
2030
2031 def already_matched(fn):
2032 for regex in matched_regex:
2033 if regex.match(fn):
2034 return True
2035 return False
2036
2037 for unmatch in unmatched_regex.copy():
2038 for fn in seen:
2039 if unmatch.match(fn):
2040 # If the bbappend or file was already matched by another regex, skip it
2041 # e.g. for a layer within a layer, the outer regex could match, the inner
2042 # regex may match nothing and we should warn about that
2043 if already_matched(fn):
2044 continue
2045 unmatched_regex.remove(unmatch)
2046 break
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002047
2048 for collection, pattern, regex, _ in self.bbfile_config_priorities:
Andrew Geisslerb7d28612020-07-24 16:15:54 -05002049 if regex in unmatched_regex:
Brad Bishop6e60e8b2018-02-01 10:27:11 -05002050 if d.getVar('BBFILE_PATTERN_IGNORE_EMPTY_%s' % collection) != '1':
Andrew Geissler5a43b432020-06-13 10:46:56 -05002051 collectlog.warning("No bb files in %s matched BBFILE_PATTERN_%s '%s'" % (self.mc if self.mc else 'default',
2052 collection, pattern))
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002053
2054 return priorities
2055
2056class ParsingFailure(Exception):
2057 def __init__(self, realexception, recipe):
2058 self.realexception = realexception
2059 self.recipe = recipe
2060 Exception.__init__(self, realexception, recipe)
2061
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002062class Parser(multiprocessing.Process):
Andrew Geissler9aee5002022-03-30 16:27:02 +00002063 def __init__(self, jobs, results, quit, profile):
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002064 self.jobs = jobs
2065 self.results = results
2066 self.quit = quit
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002067 multiprocessing.Process.__init__(self)
2068 self.context = bb.utils.get_context().copy()
2069 self.handlers = bb.event.get_class_handlers().copy()
2070 self.profile = profile
Andrew Geissler9aee5002022-03-30 16:27:02 +00002071 self.queue_signals = False
2072 self.signal_received = []
2073 self.signal_threadlock = threading.Lock()
2074
2075 def catch_sig(self, signum, frame):
2076 if self.queue_signals:
2077 self.signal_received.append(signum)
2078 else:
2079 self.handle_sig(signum, frame)
2080
2081 def handle_sig(self, signum, frame):
2082 if signum == signal.SIGTERM:
2083 signal.signal(signal.SIGTERM, signal.SIG_DFL)
2084 os.kill(os.getpid(), signal.SIGTERM)
2085 elif signum == signal.SIGINT:
2086 signal.default_int_handler(signum, frame)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002087
2088 def run(self):
2089
2090 if not self.profile:
2091 self.realrun()
2092 return
2093
2094 try:
2095 import cProfile as profile
2096 except:
2097 import profile
2098 prof = profile.Profile()
2099 try:
2100 profile.Profile.runcall(prof, self.realrun)
2101 finally:
2102 logfile = "profile-parse-%s.log" % multiprocessing.current_process().name
2103 prof.dump_stats(logfile)
2104
2105 def realrun(self):
Andrew Geissler9aee5002022-03-30 16:27:02 +00002106 # Signal handling here is hard. We must not terminate any process or thread holding the write
2107 # lock for the event stream as it will not be released, ever, and things will hang.
2108 # Python handles signals in the main thread/process but they can be raised from any thread and
2109 # we want to defer processing of any SIGTERM/SIGINT signal until we're outside the critical section
2110 # and don't hold the lock (see server/process.py). We therefore always catch the signals (so any
2111 # new thread should also do so) and we defer handling but we handle with the local thread lock
2112 # held (a threading lock, not a multiprocessing one) so that no other thread in the process
2113 # can be in the critical section.
2114 signal.signal(signal.SIGTERM, self.catch_sig)
2115 signal.signal(signal.SIGHUP, signal.SIG_DFL)
2116 signal.signal(signal.SIGINT, self.catch_sig)
2117 bb.utils.set_process_name(multiprocessing.current_process().name)
2118 multiprocessing.util.Finalize(None, bb.codeparser.parser_cache_save, exitpriority=1)
2119 multiprocessing.util.Finalize(None, bb.fetch.fetcher_parse_save, exitpriority=1)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002120
2121 pending = []
Andrew Geissler517393d2023-01-13 08:55:19 -06002122 havejobs = True
Andrew Geissler9aee5002022-03-30 16:27:02 +00002123 try:
Andrew Geissler517393d2023-01-13 08:55:19 -06002124 while havejobs or pending:
2125 if self.quit.is_set():
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002126 break
Andrew Geissler9aee5002022-03-30 16:27:02 +00002127
Andrew Geissler517393d2023-01-13 08:55:19 -06002128 job = None
2129 try:
2130 job = self.jobs.pop()
2131 except IndexError:
2132 havejobs = False
2133 if job:
Andrew Geissler9aee5002022-03-30 16:27:02 +00002134 result = self.parse(*job)
2135 # Clear the siggen cache after parsing to control memory usage, its huge
2136 bb.parse.siggen.postparsing_clean_cache()
Andrew Geissler9aee5002022-03-30 16:27:02 +00002137 pending.append(result)
Andrew Geissler517393d2023-01-13 08:55:19 -06002138
2139 if pending:
2140 try:
2141 result = pending.pop()
2142 self.results.put(result, timeout=0.05)
2143 except queue.Full:
2144 pending.append(result)
Andrew Geissler9aee5002022-03-30 16:27:02 +00002145 finally:
2146 self.results.close()
2147 self.results.join_thread()
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002148
Andrew Geissler5a43b432020-06-13 10:46:56 -05002149 def parse(self, mc, cache, filename, appends):
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002150 try:
Andrew Geissler82c905d2020-04-13 13:39:40 -05002151 origfilter = bb.event.LogHandler.filter
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05002152 # Record the filename we're parsing into any events generated
2153 def parse_filter(self, record):
2154 record.taskpid = bb.event.worker_pid
2155 record.fn = filename
2156 return True
2157
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002158 # Reset our environment and handlers to the original settings
2159 bb.utils.set_context(self.context.copy())
2160 bb.event.set_class_handlers(self.handlers.copy())
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05002161 bb.event.LogHandler.filter = parse_filter
2162
Andrew Geissler5a43b432020-06-13 10:46:56 -05002163 return True, mc, cache.parse(filename, appends)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002164 except Exception as exc:
2165 tb = sys.exc_info()[2]
2166 exc.recipe = filename
2167 exc.traceback = list(bb.exceptions.extract_traceback(tb, context=3))
Andrew Geissler9aee5002022-03-30 16:27:02 +00002168 return True, None, exc
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002169 # Need to turn BaseExceptions into Exceptions here so we gracefully shutdown
2170 # and for example a worker thread doesn't just exit on its own in response to
2171 # a SystemExit event for example.
2172 except BaseException as exc:
Andrew Geissler9aee5002022-03-30 16:27:02 +00002173 return True, None, ParsingFailure(exc, filename)
Andrew Geissler82c905d2020-04-13 13:39:40 -05002174 finally:
2175 bb.event.LogHandler.filter = origfilter
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002176
2177class CookerParser(object):
Andrew Geissler5a43b432020-06-13 10:46:56 -05002178 def __init__(self, cooker, mcfilelist, masked):
2179 self.mcfilelist = mcfilelist
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002180 self.cooker = cooker
2181 self.cfgdata = cooker.data
2182 self.cfghash = cooker.data_hash
Patrick Williamsc0f7c042017-02-23 20:41:17 -06002183 self.cfgbuilder = cooker.databuilder
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002184
2185 # Accounting statistics
2186 self.parsed = 0
2187 self.cached = 0
2188 self.error = 0
2189 self.masked = masked
2190
2191 self.skipped = 0
2192 self.virtuals = 0
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002193
2194 self.current = 0
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002195 self.process_names = []
2196
Andrew Geissler5a43b432020-06-13 10:46:56 -05002197 self.bb_caches = bb.cache.MulticonfigCache(self.cfgbuilder, self.cfghash, cooker.caches_array)
2198 self.fromcache = set()
2199 self.willparse = set()
2200 for mc in self.cooker.multiconfigs:
2201 for filename in self.mcfilelist[mc]:
2202 appends = self.cooker.collections[mc].get_file_appends(filename)
2203 if not self.bb_caches[mc].cacheValid(filename, appends):
2204 self.willparse.add((mc, self.bb_caches[mc], filename, appends))
2205 else:
2206 self.fromcache.add((mc, self.bb_caches[mc], filename, appends))
2207
2208 self.total = len(self.fromcache) + len(self.willparse)
2209 self.toparse = len(self.willparse)
Patrick Williamsc0f7c042017-02-23 20:41:17 -06002210 self.progress_chunk = int(max(self.toparse / 100, 1))
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002211
Brad Bishop6e60e8b2018-02-01 10:27:11 -05002212 self.num_processes = min(int(self.cfgdata.getVar("BB_NUMBER_PARSE_THREADS") or
Andrew Geissler5a43b432020-06-13 10:46:56 -05002213 multiprocessing.cpu_count()), self.toparse)
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05002214
Andrew Geisslerc5535c92023-01-27 16:10:19 -06002215 bb.cache.SiggenRecipeInfo.reset()
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002216 self.start()
2217 self.haveshutdown = False
Andrew Geisslerc9f78652020-09-18 14:11:35 -05002218 self.syncthread = None
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002219
2220 def start(self):
2221 self.results = self.load_cached()
2222 self.processes = []
2223 if self.toparse:
2224 bb.event.fire(bb.event.ParseStarted(self.toparse), self.cfgdata)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002225
Andrew Geissler517393d2023-01-13 08:55:19 -06002226 self.parser_quit = multiprocessing.Event()
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002227 self.result_queue = multiprocessing.Queue()
Brad Bishop19323692019-04-05 15:28:33 -04002228
2229 def chunkify(lst,n):
2230 return [lst[i::n] for i in range(n)]
Andrew Geissler5a43b432020-06-13 10:46:56 -05002231 self.jobs = chunkify(list(self.willparse), self.num_processes)
Brad Bishop19323692019-04-05 15:28:33 -04002232
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002233 for i in range(0, self.num_processes):
Andrew Geissler9aee5002022-03-30 16:27:02 +00002234 parser = Parser(self.jobs[i], self.result_queue, self.parser_quit, self.cooker.configuration.profile)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002235 parser.start()
2236 self.process_names.append(parser.name)
2237 self.processes.append(parser)
2238
2239 self.results = itertools.chain(self.results, self.parse_generator())
2240
Patrick Williams8e7b46e2023-05-01 14:19:06 -05002241 def shutdown(self, clean=True, eventmsg="Parsing halted due to errors"):
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002242 if not self.toparse:
2243 return
2244 if self.haveshutdown:
2245 return
2246 self.haveshutdown = True
2247
2248 if clean:
2249 event = bb.event.ParseCompleted(self.cached, self.parsed,
2250 self.skipped, self.masked,
2251 self.virtuals, self.error,
2252 self.total)
2253
2254 bb.event.fire(event, self.cfgdata)
Andrew Geissler7e0e3c02022-02-25 20:34:39 +00002255 else:
Patrick Williams8e7b46e2023-05-01 14:19:06 -05002256 bb.event.fire(bb.event.ParseError(eventmsg), self.cfgdata)
Andrew Geissler9aee5002022-03-30 16:27:02 +00002257 bb.error("Parsing halted due to errors, see error messages above")
Andrew Geisslerc9f78652020-09-18 14:11:35 -05002258
Andrew Geisslerc5535c92023-01-27 16:10:19 -06002259 # Cleanup the queue before call process.join(), otherwise there might be
2260 # deadlocks.
2261 while True:
2262 try:
2263 self.result_queue.get(timeout=0.25)
2264 except queue.Empty:
2265 break
2266
Andrew Geissler517393d2023-01-13 08:55:19 -06002267 def sync_caches():
2268 for c in self.bb_caches.values():
2269 bb.cache.SiggenRecipeInfo.reset()
2270 c.sync()
2271
2272 self.syncthread = threading.Thread(target=sync_caches, name="SyncThread")
2273 self.syncthread.start()
2274
2275 self.parser_quit.set()
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002276
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002277 for process in self.processes:
Andrew Geissler9aee5002022-03-30 16:27:02 +00002278 process.join(0.5)
2279
2280 for process in self.processes:
2281 if process.exitcode is None:
2282 os.kill(process.pid, signal.SIGINT)
2283
2284 for process in self.processes:
2285 process.join(0.5)
2286
2287 for process in self.processes:
2288 if process.exitcode is None:
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002289 process.terminate()
Andrew Geissler9aee5002022-03-30 16:27:02 +00002290
2291 for process in self.processes:
2292 process.join()
2293 # Added in 3.7, cleans up zombies
2294 if hasattr(process, "close"):
2295 process.close()
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002296
Andrew Geisslerc5535c92023-01-27 16:10:19 -06002297 bb.codeparser.parser_cache_save()
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05002298 bb.codeparser.parser_cache_savemerge()
Andrew Geissler517393d2023-01-13 08:55:19 -06002299 bb.cache.SiggenRecipeInfo.reset()
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05002300 bb.fetch.fetcher_parse_done()
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002301 if self.cooker.configuration.profile:
2302 profiles = []
2303 for i in self.process_names:
2304 logfile = "profile-parse-%s.log" % i
2305 if os.path.exists(logfile):
2306 profiles.append(logfile)
2307
2308 pout = "profile-parse.log.processed"
2309 bb.utils.process_profilelog(profiles, pout = pout)
2310 print("Processed parsing statistics saved to %s" % (pout))
2311
Andrew Geisslerc9f78652020-09-18 14:11:35 -05002312 def final_cleanup(self):
2313 if self.syncthread:
2314 self.syncthread.join()
2315
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002316 def load_cached(self):
Andrew Geissler5a43b432020-06-13 10:46:56 -05002317 for mc, cache, filename, appends in self.fromcache:
Andrew Geissler517393d2023-01-13 08:55:19 -06002318 infos = cache.loadCached(filename, appends)
2319 yield False, mc, infos
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002320
2321 def parse_generator(self):
Andrew Geissler595f6302022-01-24 19:11:47 +00002322 empty = False
2323 while self.processes or not empty:
2324 for process in self.processes.copy():
2325 if not process.is_alive():
2326 process.join()
2327 self.processes.remove(process)
2328
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002329 if self.parsed >= self.toparse:
2330 break
2331
2332 try:
2333 result = self.result_queue.get(timeout=0.25)
Patrick Williamsc0f7c042017-02-23 20:41:17 -06002334 except queue.Empty:
Andrew Geissler595f6302022-01-24 19:11:47 +00002335 empty = True
Andrew Geissler9aee5002022-03-30 16:27:02 +00002336 yield None, None, None
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002337 else:
Andrew Geissler595f6302022-01-24 19:11:47 +00002338 empty = False
Andrew Geissler9aee5002022-03-30 16:27:02 +00002339 yield result
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002340
Andrew Geissler595f6302022-01-24 19:11:47 +00002341 if not (self.parsed >= self.toparse):
2342 raise bb.parse.ParseError("Not all recipes parsed, parser thread killed/died? Exiting.", None)
2343
2344
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002345 def parse_next(self):
2346 result = []
2347 parsed = None
2348 try:
Andrew Geissler5a43b432020-06-13 10:46:56 -05002349 parsed, mc, result = next(self.results)
Andrew Geissler9aee5002022-03-30 16:27:02 +00002350 if isinstance(result, BaseException):
2351 # Turn exceptions back into exceptions
2352 raise result
2353 if parsed is None:
2354 # Timeout, loop back through the main loop
2355 return True
2356
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002357 except StopIteration:
2358 self.shutdown()
2359 return False
2360 except bb.BBHandledException as exc:
2361 self.error += 1
Andrew Geissler7e0e3c02022-02-25 20:34:39 +00002362 logger.debug('Failed to parse recipe: %s' % exc.recipe)
Andrew Geissler9aee5002022-03-30 16:27:02 +00002363 self.shutdown(clean=False)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002364 return False
2365 except ParsingFailure as exc:
2366 self.error += 1
2367 logger.error('Unable to parse %s: %s' %
2368 (exc.recipe, bb.exceptions.to_string(exc.realexception)))
Andrew Geissler9aee5002022-03-30 16:27:02 +00002369 self.shutdown(clean=False)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002370 return False
2371 except bb.parse.ParseError as exc:
2372 self.error += 1
2373 logger.error(str(exc))
Patrick Williams8e7b46e2023-05-01 14:19:06 -05002374 self.shutdown(clean=False, eventmsg=str(exc))
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002375 return False
2376 except bb.data_smart.ExpansionError as exc:
2377 self.error += 1
Patrick Williamsc0f7c042017-02-23 20:41:17 -06002378 bbdir = os.path.dirname(__file__) + os.sep
2379 etype, value, _ = sys.exc_info()
2380 tb = list(itertools.dropwhile(lambda e: e.filename.startswith(bbdir), exc.traceback))
2381 logger.error('ExpansionError during parsing %s', value.recipe,
2382 exc_info=(etype, value, tb))
Andrew Geissler9aee5002022-03-30 16:27:02 +00002383 self.shutdown(clean=False)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002384 return False
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002385 except Exception as exc:
2386 self.error += 1
2387 etype, value, tb = sys.exc_info()
2388 if hasattr(value, "recipe"):
Patrick Williamsc0f7c042017-02-23 20:41:17 -06002389 logger.error('Unable to parse %s' % value.recipe,
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002390 exc_info=(etype, value, exc.traceback))
2391 else:
2392 # Most likely, an exception occurred during raising an exception
2393 import traceback
2394 logger.error('Exception during parse: %s' % traceback.format_exc())
Andrew Geissler9aee5002022-03-30 16:27:02 +00002395 self.shutdown(clean=False)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002396 return False
2397
2398 self.current += 1
2399 self.virtuals += len(result)
2400 if parsed:
2401 self.parsed += 1
2402 if self.parsed % self.progress_chunk == 0:
2403 bb.event.fire(bb.event.ParseProgress(self.parsed, self.toparse),
2404 self.cfgdata)
2405 else:
2406 self.cached += 1
2407
2408 for virtualfn, info_array in result:
2409 if info_array[0].skipped:
2410 self.skipped += 1
2411 self.cooker.skiplist[virtualfn] = SkippedPackage(info_array[0])
Andrew Geissler5a43b432020-06-13 10:46:56 -05002412 self.bb_caches[mc].add_info(virtualfn, info_array, self.cooker.recipecaches[mc],
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002413 parsed=parsed, watcher = self.cooker.add_filewatch)
2414 return True
2415
2416 def reparse(self, filename):
Andrew Geissler517393d2023-01-13 08:55:19 -06002417 bb.cache.SiggenRecipeInfo.reset()
Andrew Geissler5a43b432020-06-13 10:46:56 -05002418 to_reparse = set()
2419 for mc in self.cooker.multiconfigs:
2420 to_reparse.add((mc, filename, self.cooker.collections[mc].get_file_appends(filename)))
2421
2422 for mc, filename, appends in to_reparse:
2423 infos = self.bb_caches[mc].parse(filename, appends)
2424 for vfn, info_array in infos:
2425 self.cooker.recipecaches[mc].add_from_recipeinfo(vfn, info_array)