diff options
-rw-r--r-- | bitbake/lib/bb/command.py | 195 | ||||
-rw-r--r-- | bitbake/lib/bb/cooker.py | 19 | ||||
-rwxr-xr-x | bitbake/lib/bb/main.py | 83 | ||||
-rw-r--r-- | bitbake/lib/bb/remotedata.py | 74 | ||||
-rw-r--r-- | bitbake/lib/bb/tinfoil.py | 385 | ||||
-rw-r--r-- | bitbake/lib/bblayers/query.py | 28 |
6 files changed, 665 insertions, 119 deletions
diff --git a/bitbake/lib/bb/command.py b/bitbake/lib/bb/command.py index 012b35faf6..d5be86dab8 100644 --- a/bitbake/lib/bb/command.py +++ b/bitbake/lib/bb/command.py | |||
@@ -28,8 +28,15 @@ and must not trigger events, directly or indirectly. | |||
28 | Commands are queued in a CommandQueue | 28 | Commands are queued in a CommandQueue |
29 | """ | 29 | """ |
30 | 30 | ||
31 | from collections import OrderedDict, defaultdict | ||
32 | |||
31 | import bb.event | 33 | import bb.event |
32 | import bb.cooker | 34 | import bb.cooker |
35 | import bb.remotedata | ||
36 | |||
37 | class DataStoreConnectionHandle(object): | ||
38 | def __init__(self, dsindex=0): | ||
39 | self.dsindex = dsindex | ||
33 | 40 | ||
34 | class CommandCompleted(bb.event.Event): | 41 | class CommandCompleted(bb.event.Event): |
35 | pass | 42 | pass |
@@ -55,6 +62,7 @@ class Command: | |||
55 | self.cooker = cooker | 62 | self.cooker = cooker |
56 | self.cmds_sync = CommandsSync() | 63 | self.cmds_sync = CommandsSync() |
57 | self.cmds_async = CommandsAsync() | 64 | self.cmds_async = CommandsAsync() |
65 | self.remotedatastores = bb.remotedata.RemoteDatastores(cooker) | ||
58 | 66 | ||
59 | # FIXME Add lock for this | 67 | # FIXME Add lock for this |
60 | self.currentAsyncCommand = None | 68 | self.currentAsyncCommand = None |
@@ -298,6 +306,193 @@ class CommandsSync: | |||
298 | command.cooker.updateConfigOpts(options, environment) | 306 | command.cooker.updateConfigOpts(options, environment) |
299 | updateConfig.needconfig = False | 307 | updateConfig.needconfig = False |
300 | 308 | ||
309 | def parseConfiguration(self, command, params): | ||
310 | """Instruct bitbake to parse its configuration | ||
311 | NOTE: it is only necessary to call this if you aren't calling any normal action | ||
312 | (otherwise parsing is taken care of automatically) | ||
313 | """ | ||
314 | command.cooker.parseConfiguration() | ||
315 | parseConfiguration.needconfig = False | ||
316 | |||
317 | def getLayerPriorities(self, command, params): | ||
318 | ret = [] | ||
319 | # regex objects cannot be marshalled by xmlrpc | ||
320 | for collection, pattern, regex, pri in command.cooker.bbfile_config_priorities: | ||
321 | ret.append((collection, pattern, regex.pattern, pri)) | ||
322 | return ret | ||
323 | getLayerPriorities.readonly = True | ||
324 | |||
325 | def getRecipes(self, command, params): | ||
326 | try: | ||
327 | mc = params[0] | ||
328 | except IndexError: | ||
329 | mc = '' | ||
330 | return list(command.cooker.recipecaches[mc].pkg_pn.items()) | ||
331 | getRecipes.readonly = True | ||
332 | |||
333 | def getRecipeDepends(self, command, params): | ||
334 | try: | ||
335 | mc = params[0] | ||
336 | except IndexError: | ||
337 | mc = '' | ||
338 | return list(command.cooker.recipecaches[mc].deps.items()) | ||
339 | getRecipeDepends.readonly = True | ||
340 | |||
341 | def getRecipeVersions(self, command, params): | ||
342 | try: | ||
343 | mc = params[0] | ||
344 | except IndexError: | ||
345 | mc = '' | ||
346 | return command.cooker.recipecaches[mc].pkg_pepvpr | ||
347 | getRecipeVersions.readonly = True | ||
348 | |||
349 | def getRuntimeDepends(self, command, params): | ||
350 | ret = [] | ||
351 | try: | ||
352 | mc = params[0] | ||
353 | except IndexError: | ||
354 | mc = '' | ||
355 | rundeps = command.cooker.recipecaches[mc].rundeps | ||
356 | for key, value in rundeps.items(): | ||
357 | if isinstance(value, defaultdict): | ||
358 | value = dict(value) | ||
359 | ret.append((key, value)) | ||
360 | return ret | ||
361 | getRuntimeDepends.readonly = True | ||
362 | |||
363 | def getRuntimeRecommends(self, command, params): | ||
364 | ret = [] | ||
365 | try: | ||
366 | mc = params[0] | ||
367 | except IndexError: | ||
368 | mc = '' | ||
369 | runrecs = command.cooker.recipecaches[mc].runrecs | ||
370 | for key, value in runrecs.items(): | ||
371 | if isinstance(value, defaultdict): | ||
372 | value = dict(value) | ||
373 | ret.append((key, value)) | ||
374 | return ret | ||
375 | getRuntimeRecommends.readonly = True | ||
376 | |||
377 | def getRecipeInherits(self, command, params): | ||
378 | try: | ||
379 | mc = params[0] | ||
380 | except IndexError: | ||
381 | mc = '' | ||
382 | return command.cooker.recipecaches[mc].inherits | ||
383 | getRecipeInherits.readonly = True | ||
384 | |||
385 | def getBbFilePriority(self, command, params): | ||
386 | try: | ||
387 | mc = params[0] | ||
388 | except IndexError: | ||
389 | mc = '' | ||
390 | return command.cooker.recipecaches[mc].bbfile_priority | ||
391 | getBbFilePriority.readonly = True | ||
392 | |||
393 | def getDefaultPreference(self, command, params): | ||
394 | try: | ||
395 | mc = params[0] | ||
396 | except IndexError: | ||
397 | mc = '' | ||
398 | return command.cooker.recipecaches[mc].pkg_dp | ||
399 | getDefaultPreference.readonly = True | ||
400 | |||
401 | def getSkippedRecipes(self, command, params): | ||
402 | # Return list sorted by reverse priority order | ||
403 | import bb.cache | ||
404 | skipdict = OrderedDict(sorted(command.cooker.skiplist.items(), | ||
405 | key=lambda x: (-command.cooker.collection.calc_bbfile_priority(bb.cache.virtualfn2realfn(x[0])[0]), x[0]))) | ||
406 | return list(skipdict.items()) | ||
407 | getSkippedRecipes.readonly = True | ||
408 | |||
409 | def getOverlayedRecipes(self, command, params): | ||
410 | return list(command.cooker.collection.overlayed.items()) | ||
411 | getOverlayedRecipes.readonly = True | ||
412 | |||
413 | def getFileAppends(self, command, params): | ||
414 | fn = params[0] | ||
415 | return command.cooker.collection.get_file_appends(fn) | ||
416 | getFileAppends.readonly = True | ||
417 | |||
418 | def getAllAppends(self, command, params): | ||
419 | return command.cooker.collection.bbappends | ||
420 | getAllAppends.readonly = True | ||
421 | |||
422 | def findProviders(self, command, params): | ||
423 | return command.cooker.findProviders() | ||
424 | findProviders.readonly = True | ||
425 | |||
426 | def findBestProvider(self, command, params): | ||
427 | pn = params[0] | ||
428 | return command.cooker.findBestProvider(pn) | ||
429 | findBestProvider.readonly = True | ||
430 | |||
431 | def allProviders(self, command, params): | ||
432 | try: | ||
433 | mc = params[0] | ||
434 | except IndexError: | ||
435 | mc = '' | ||
436 | return list(bb.providers.allProviders(command.cooker.recipecaches[mc]).items()) | ||
437 | allProviders.readonly = True | ||
438 | |||
439 | def getRuntimeProviders(self, command, params): | ||
440 | rprovide = params[0] | ||
441 | try: | ||
442 | mc = params[1] | ||
443 | except IndexError: | ||
444 | mc = '' | ||
445 | all_p = bb.providers.getRuntimeProviders(command.cooker.recipecaches[mc], rprovide) | ||
446 | if all_p: | ||
447 | best = bb.providers.filterProvidersRunTime(all_p, rprovide, | ||
448 | command.cooker.data, | ||
449 | command.cooker.recipecaches[mc])[0][0] | ||
450 | else: | ||
451 | best = None | ||
452 | return all_p, best | ||
453 | getRuntimeProviders.readonly = True | ||
454 | |||
455 | def dataStoreConnectorFindVar(self, command, params): | ||
456 | dsindex = params[0] | ||
457 | name = params[1] | ||
458 | datastore = command.remotedatastores[dsindex] | ||
459 | value = datastore._findVar(name) | ||
460 | |||
461 | if value: | ||
462 | content = value.get('_content', None) | ||
463 | if isinstance(content, bb.data_smart.DataSmart): | ||
464 | # Value is a datastore (e.g. BB_ORIGENV) - need to handle this carefully | ||
465 | idx = command.remotedatastores.check_store(content, True) | ||
466 | return {'_content': DataStoreConnectionHandle(idx), '_connector_origtype': 'DataStoreConnectionHandle'} | ||
467 | elif isinstance(content, set): | ||
468 | return {'_content': list(content), '_connector_origtype': 'set'} | ||
469 | return value | ||
470 | dataStoreConnectorFindVar.readonly = True | ||
471 | |||
472 | def dataStoreConnectorGetKeys(self, command, params): | ||
473 | dsindex = params[0] | ||
474 | datastore = command.remotedatastores[dsindex] | ||
475 | return list(datastore.keys()) | ||
476 | dataStoreConnectorGetKeys.readonly = True | ||
477 | |||
478 | def dataStoreConnectorGetVarHistory(self, command, params): | ||
479 | dsindex = params[0] | ||
480 | name = params[1] | ||
481 | datastore = command.remotedatastores[dsindex] | ||
482 | return datastore.varhistory.variable(name) | ||
483 | dataStoreConnectorGetVarHistory.readonly = True | ||
484 | |||
485 | def dataStoreConnectorExpandPythonRef(self, command, params): | ||
486 | dsindex = params[0] | ||
487 | varname = params[1] | ||
488 | expr = params[2] | ||
489 | if dsindex: | ||
490 | datastore = self.dataStores[dsindex] | ||
491 | else: | ||
492 | datastore = command.cooker.data | ||
493 | varparse = bb.data_smart.VariableParse(varname, datastore) | ||
494 | return varparse.python_sub(expr) | ||
495 | |||
301 | class CommandsAsync: | 496 | class CommandsAsync: |
302 | """ | 497 | """ |
303 | A class of asynchronous commands | 498 | A class of asynchronous commands |
diff --git a/bitbake/lib/bb/cooker.py b/bitbake/lib/bb/cooker.py index 2614c4485a..48904a52d6 100644 --- a/bitbake/lib/bb/cooker.py +++ b/bitbake/lib/bb/cooker.py | |||
@@ -583,13 +583,12 @@ class BBCooker: | |||
583 | 583 | ||
584 | def showVersions(self): | 584 | def showVersions(self): |
585 | 585 | ||
586 | pkg_pn = self.recipecaches[''].pkg_pn | 586 | (latest_versions, preferred_versions) = self.findProviders() |
587 | (latest_versions, preferred_versions) = bb.providers.findProviders(self.data, self.recipecaches[''], pkg_pn) | ||
588 | 587 | ||
589 | logger.plain("%-35s %25s %25s", "Recipe Name", "Latest Version", "Preferred Version") | 588 | logger.plain("%-35s %25s %25s", "Recipe Name", "Latest Version", "Preferred Version") |
590 | logger.plain("%-35s %25s %25s\n", "===========", "==============", "=================") | 589 | logger.plain("%-35s %25s %25s\n", "===========", "==============", "=================") |
591 | 590 | ||
592 | for p in sorted(pkg_pn): | 591 | for p in sorted(self.recipecaches[''].pkg_pn): |
593 | pref = preferred_versions[p] | 592 | pref = preferred_versions[p] |
594 | latest = latest_versions[p] | 593 | latest = latest_versions[p] |
595 | 594 | ||
@@ -1084,6 +1083,20 @@ class BBCooker: | |||
1084 | if matches: | 1083 | if matches: |
1085 | bb.event.fire(bb.event.FilesMatchingFound(filepattern, matches), self.data) | 1084 | bb.event.fire(bb.event.FilesMatchingFound(filepattern, matches), self.data) |
1086 | 1085 | ||
1086 | def findProviders(self, mc=''): | ||
1087 | return bb.providers.findProviders(self.data, self.recipecaches[mc], self.recipecaches[mc].pkg_pn) | ||
1088 | |||
1089 | def findBestProvider(self, pn, mc=''): | ||
1090 | if pn in self.recipecaches[mc].providers: | ||
1091 | filenames = self.recipecaches[mc].providers[pn] | ||
1092 | eligible, foundUnique = bb.providers.filterProviders(filenames, pn, self.expanded_data, self.recipecaches[mc]) | ||
1093 | filename = eligible[0] | ||
1094 | return None, None, None, filename | ||
1095 | elif pn in self.recipecaches[mc].pkg_pn: | ||
1096 | return bb.providers.findBestProvider(pn, self.data, self.recipecaches[mc], self.recipecaches[mc].pkg_pn) | ||
1097 | else: | ||
1098 | return None, None, None, None | ||
1099 | |||
1087 | def findConfigFiles(self, varname): | 1100 | def findConfigFiles(self, varname): |
1088 | """ | 1101 | """ |
1089 | Find config files which are appropriate values for varname. | 1102 | Find config files which are appropriate values for varname. |
diff --git a/bitbake/lib/bb/main.py b/bitbake/lib/bb/main.py index a544c0aecb..443f5ec2fd 100755 --- a/bitbake/lib/bb/main.py +++ b/bitbake/lib/bb/main.py | |||
@@ -389,12 +389,8 @@ def bitbake_main(configParams, configuration): | |||
389 | except: | 389 | except: |
390 | pass | 390 | pass |
391 | 391 | ||
392 | |||
393 | configuration.setConfigParameters(configParams) | 392 | configuration.setConfigParameters(configParams) |
394 | 393 | ||
395 | ui_module = import_extension_module(bb.ui, configParams.ui, 'main') | ||
396 | servermodule = import_extension_module(bb.server, configParams.servertype, 'BitBakeServer') | ||
397 | |||
398 | if configParams.server_only: | 394 | if configParams.server_only: |
399 | if configParams.servertype != "xmlrpc": | 395 | if configParams.servertype != "xmlrpc": |
400 | raise BBMainException("FATAL: If '--server-only' is defined, we must set the " | 396 | raise BBMainException("FATAL: If '--server-only' is defined, we must set the " |
@@ -442,6 +438,31 @@ def bitbake_main(configParams, configuration): | |||
442 | bb.msg.init_msgconfig(configParams.verbose, configuration.debug, | 438 | bb.msg.init_msgconfig(configParams.verbose, configuration.debug, |
443 | configuration.debug_domains) | 439 | configuration.debug_domains) |
444 | 440 | ||
441 | server, server_connection, ui_module = setup_bitbake(configParams, configuration) | ||
442 | if server_connection is None and configParams.kill_server: | ||
443 | return 0 | ||
444 | |||
445 | if not configParams.server_only: | ||
446 | if configParams.status_only: | ||
447 | server_connection.terminate() | ||
448 | return 0 | ||
449 | |||
450 | try: | ||
451 | return ui_module.main(server_connection.connection, server_connection.events, | ||
452 | configParams) | ||
453 | finally: | ||
454 | bb.event.ui_queue = [] | ||
455 | server_connection.terminate() | ||
456 | else: | ||
457 | print("Bitbake server address: %s, server port: %s" % (server.serverImpl.host, | ||
458 | server.serverImpl.port)) | ||
459 | if configParams.foreground: | ||
460 | server.serverImpl.serve_forever() | ||
461 | return 0 | ||
462 | |||
463 | return 1 | ||
464 | |||
465 | def setup_bitbake(configParams, configuration, extrafeatures=None): | ||
445 | # Ensure logging messages get sent to the UI as events | 466 | # Ensure logging messages get sent to the UI as events |
446 | handler = bb.event.LogHandler() | 467 | handler = bb.event.LogHandler() |
447 | if not configParams.status_only: | 468 | if not configParams.status_only: |
@@ -451,8 +472,11 @@ def bitbake_main(configParams, configuration): | |||
451 | # Clear away any spurious environment variables while we stoke up the cooker | 472 | # Clear away any spurious environment variables while we stoke up the cooker |
452 | cleanedvars = bb.utils.clean_environment() | 473 | cleanedvars = bb.utils.clean_environment() |
453 | 474 | ||
454 | featureset = [] | 475 | if configParams.server_only: |
455 | if not configParams.server_only: | 476 | featureset = [] |
477 | ui_module = None | ||
478 | else: | ||
479 | ui_module = import_extension_module(bb.ui, configParams.ui, 'main') | ||
456 | # Collect the feature set for the UI | 480 | # Collect the feature set for the UI |
457 | featureset = getattr(ui_module, "featureSet", []) | 481 | featureset = getattr(ui_module, "featureSet", []) |
458 | 482 | ||
@@ -463,11 +487,15 @@ def bitbake_main(configParams, configuration): | |||
463 | setattr(configuration, "%s_server" % param, value) | 487 | setattr(configuration, "%s_server" % param, value) |
464 | param = "%s_server" % param | 488 | param = "%s_server" % param |
465 | 489 | ||
466 | if not configParams.remote_server: | 490 | if extrafeatures: |
467 | # we start a server with a given configuration | 491 | for feature in extrafeatures: |
468 | server = start_server(servermodule, configParams, configuration, featureset) | 492 | if not feature in featureset: |
469 | bb.event.ui_queue = [] | 493 | featureset.append(feature) |
470 | else: | 494 | |
495 | servermodule = import_extension_module(bb.server, | ||
496 | configParams.servertype, | ||
497 | 'BitBakeServer') | ||
498 | if configParams.remote_server: | ||
471 | if os.getenv('BBSERVER') == 'autostart': | 499 | if os.getenv('BBSERVER') == 'autostart': |
472 | if configParams.remote_server == 'autostart' or \ | 500 | if configParams.remote_server == 'autostart' or \ |
473 | not servermodule.check_connection(configParams.remote_server, timeout=2): | 501 | not servermodule.check_connection(configParams.remote_server, timeout=2): |
@@ -475,14 +503,19 @@ def bitbake_main(configParams, configuration): | |||
475 | srv = start_server(servermodule, configParams, configuration, featureset) | 503 | srv = start_server(servermodule, configParams, configuration, featureset) |
476 | configParams.remote_server = '%s:%d' % tuple(configuration.interface) | 504 | configParams.remote_server = '%s:%d' % tuple(configuration.interface) |
477 | bb.event.ui_queue = [] | 505 | bb.event.ui_queue = [] |
478 | |||
479 | # we start a stub server that is actually a XMLRPClient that connects to a real server | 506 | # we start a stub server that is actually a XMLRPClient that connects to a real server |
507 | from bb.server.xmlrpc import BitBakeXMLRPCClient | ||
480 | server = servermodule.BitBakeXMLRPCClient(configParams.observe_only, | 508 | server = servermodule.BitBakeXMLRPCClient(configParams.observe_only, |
481 | configParams.xmlrpctoken) | 509 | configParams.xmlrpctoken) |
482 | server.saveConnectionDetails(configParams.remote_server) | 510 | server.saveConnectionDetails(configParams.remote_server) |
511 | else: | ||
512 | # we start a server with a given configuration | ||
513 | server = start_server(servermodule, configParams, configuration, featureset) | ||
514 | bb.event.ui_queue = [] | ||
483 | 515 | ||
484 | 516 | if configParams.server_only: | |
485 | if not configParams.server_only: | 517 | server_connection = None |
518 | else: | ||
486 | try: | 519 | try: |
487 | server_connection = server.establishConnection(featureset) | 520 | server_connection = server.establishConnection(featureset) |
488 | except Exception as e: | 521 | except Exception as e: |
@@ -491,7 +524,7 @@ def bitbake_main(configParams, configuration): | |||
491 | if configParams.kill_server: | 524 | if configParams.kill_server: |
492 | server_connection.connection.terminateServer() | 525 | server_connection.connection.terminateServer() |
493 | bb.event.ui_queue = [] | 526 | bb.event.ui_queue = [] |
494 | return 0 | 527 | return None, None, None |
495 | 528 | ||
496 | server_connection.setupEventQueue() | 529 | server_connection.setupEventQueue() |
497 | 530 | ||
@@ -501,22 +534,4 @@ def bitbake_main(configParams, configuration): | |||
501 | 534 | ||
502 | logger.removeHandler(handler) | 535 | logger.removeHandler(handler) |
503 | 536 | ||
504 | 537 | return server, server_connection, ui_module | |
505 | if configParams.status_only: | ||
506 | server_connection.terminate() | ||
507 | return 0 | ||
508 | |||
509 | try: | ||
510 | return ui_module.main(server_connection.connection, server_connection.events, | ||
511 | configParams) | ||
512 | finally: | ||
513 | bb.event.ui_queue = [] | ||
514 | server_connection.terminate() | ||
515 | else: | ||
516 | print("Bitbake server address: %s, server port: %s" % (server.serverImpl.host, | ||
517 | server.serverImpl.port)) | ||
518 | if configParams.foreground: | ||
519 | server.serverImpl.serve_forever() | ||
520 | return 0 | ||
521 | |||
522 | return 1 | ||
diff --git a/bitbake/lib/bb/remotedata.py b/bitbake/lib/bb/remotedata.py new file mode 100644 index 0000000000..932ee430ea --- /dev/null +++ b/bitbake/lib/bb/remotedata.py | |||
@@ -0,0 +1,74 @@ | |||
1 | """ | ||
2 | BitBake 'remotedata' module | ||
3 | |||
4 | Provides support for using a datastore from the bitbake client | ||
5 | """ | ||
6 | |||
7 | # Copyright (C) 2016 Intel Corporation | ||
8 | # | ||
9 | # This program is free software; you can redistribute it and/or modify | ||
10 | # it under the terms of the GNU General Public License version 2 as | ||
11 | # published by the Free Software Foundation. | ||
12 | # | ||
13 | # This program is distributed in the hope that it will be useful, | ||
14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | # GNU General Public License for more details. | ||
17 | # | ||
18 | # You should have received a copy of the GNU General Public License along | ||
19 | # with this program; if not, write to the Free Software Foundation, Inc., | ||
20 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
21 | |||
22 | import bb.data | ||
23 | |||
24 | class RemoteDatastores: | ||
25 | """Used on the server side to manage references to server-side datastores""" | ||
26 | def __init__(self, cooker): | ||
27 | self.cooker = cooker | ||
28 | self.datastores = {} | ||
29 | self.locked = [] | ||
30 | self.nextindex = 1 | ||
31 | |||
32 | def __len__(self): | ||
33 | return len(self.datastores) | ||
34 | |||
35 | def __getitem__(self, key): | ||
36 | if key is None: | ||
37 | return self.cooker.data | ||
38 | else: | ||
39 | return self.datastores[key] | ||
40 | |||
41 | def items(self): | ||
42 | return self.datastores.items() | ||
43 | |||
44 | def store(self, d, locked=False): | ||
45 | """ | ||
46 | Put a datastore into the collection. If locked=True then the datastore | ||
47 | is understood to be managed externally and cannot be released by calling | ||
48 | release(). | ||
49 | """ | ||
50 | idx = self.nextindex | ||
51 | self.datastores[idx] = d | ||
52 | if locked: | ||
53 | self.locked.append(idx) | ||
54 | self.nextindex += 1 | ||
55 | return idx | ||
56 | |||
57 | def check_store(self, d, locked=False): | ||
58 | """ | ||
59 | Put a datastore into the collection if it's not already in there; | ||
60 | in either case return the index | ||
61 | """ | ||
62 | for key, val in self.datastores.items(): | ||
63 | if val is d: | ||
64 | idx = key | ||
65 | break | ||
66 | else: | ||
67 | idx = self.store(d, locked) | ||
68 | return idx | ||
69 | |||
70 | def release(self, idx): | ||
71 | """Discard a datastore in the collection""" | ||
72 | if idx in self.locked: | ||
73 | raise Exception('Tried to release locked datastore %d' % idx) | ||
74 | del self.datastores[idx] | ||
diff --git a/bitbake/lib/bb/tinfoil.py b/bitbake/lib/bb/tinfoil.py index 8899e861c3..459f6c1286 100644 --- a/bitbake/lib/bb/tinfoil.py +++ b/bitbake/lib/bb/tinfoil.py | |||
@@ -1,6 +1,6 @@ | |||
1 | # tinfoil: a simple wrapper around cooker for bitbake-based command-line utilities | 1 | # tinfoil: a simple wrapper around cooker for bitbake-based command-line utilities |
2 | # | 2 | # |
3 | # Copyright (C) 2012 Intel Corporation | 3 | # Copyright (C) 2012-2016 Intel Corporation |
4 | # Copyright (C) 2011 Mentor Graphics Corporation | 4 | # Copyright (C) 2011 Mentor Graphics Corporation |
5 | # | 5 | # |
6 | # This program is free software; you can redistribute it and/or modify | 6 | # This program is free software; you can redistribute it and/or modify |
@@ -17,47 +17,172 @@ | |||
17 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | 17 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
18 | 18 | ||
19 | import logging | 19 | import logging |
20 | import warnings | ||
21 | import os | 20 | import os |
22 | import sys | 21 | import sys |
22 | import atexit | ||
23 | import re | ||
24 | from collections import OrderedDict, defaultdict | ||
23 | 25 | ||
24 | import bb.cache | 26 | import bb.cache |
25 | import bb.cooker | 27 | import bb.cooker |
26 | import bb.providers | 28 | import bb.providers |
27 | import bb.utils | 29 | import bb.utils |
28 | from bb.cooker import state, BBCooker, CookerFeatures | 30 | import bb.command |
29 | from bb.cookerdata import CookerConfiguration, ConfigParameters | 31 | from bb.cookerdata import CookerConfiguration, ConfigParameters |
32 | from bb.main import setup_bitbake, BitBakeConfigParameters, BBMainException | ||
30 | import bb.fetch2 | 33 | import bb.fetch2 |
31 | 34 | ||
35 | |||
36 | # We need this in order to shut down the connection to the bitbake server, | ||
37 | # otherwise the process will never properly exit | ||
38 | _server_connections = [] | ||
39 | def _terminate_connections(): | ||
40 | for connection in _server_connections: | ||
41 | connection.terminate() | ||
42 | atexit.register(_terminate_connections) | ||
43 | |||
44 | class TinfoilUIException(Exception): | ||
45 | """Exception raised when the UI returns non-zero from its main function""" | ||
46 | def __init__(self, returncode): | ||
47 | self.returncode = returncode | ||
48 | def __repr__(self): | ||
49 | return 'UI module main returned %d' % self.returncode | ||
50 | |||
51 | class TinfoilCommandFailed(Exception): | ||
52 | """Exception raised when run_command fails""" | ||
53 | |||
54 | class TinfoilDataStoreConnector: | ||
55 | |||
56 | def __init__(self, tinfoil, dsindex): | ||
57 | self.tinfoil = tinfoil | ||
58 | self.dsindex = dsindex | ||
59 | def getVar(self, name): | ||
60 | value = self.tinfoil.run_command('dataStoreConnectorFindVar', self.dsindex, name) | ||
61 | if isinstance(value, dict): | ||
62 | if '_connector_origtype' in value: | ||
63 | value['_content'] = self.tinfoil._reconvert_type(value['_content'], value['_connector_origtype']) | ||
64 | del value['_connector_origtype'] | ||
65 | |||
66 | return value | ||
67 | def getKeys(self): | ||
68 | return set(self.tinfoil.run_command('dataStoreConnectorGetKeys', self.dsindex)) | ||
69 | def getVarHistory(self, name): | ||
70 | return self.tinfoil.run_command('dataStoreConnectorGetVarHistory', self.dsindex, name) | ||
71 | def expandPythonRef(self, varname, expr): | ||
72 | ret = self.tinfoil.run_command('dataStoreConnectorExpandPythonRef', self.dsindex, varname, expr) | ||
73 | return ret | ||
74 | def setVar(self, varname, value): | ||
75 | if self.dsindex is None: | ||
76 | self.tinfoil.run_command('setVariable', varname, value) | ||
77 | else: | ||
78 | # Not currently implemented - indicate that setting should | ||
79 | # be redirected to local side | ||
80 | return True | ||
81 | |||
82 | class TinfoilCookerAdapter: | ||
83 | """ | ||
84 | Provide an adapter for existing code that expects to access a cooker object via Tinfoil, | ||
85 | since now Tinfoil is on the client side it no longer has direct access. | ||
86 | """ | ||
87 | |||
88 | class TinfoilCookerCollectionAdapter: | ||
89 | """ cooker.collection adapter """ | ||
90 | def __init__(self, tinfoil): | ||
91 | self.tinfoil = tinfoil | ||
92 | def get_file_appends(self, fn): | ||
93 | return self.tinfoil.run_command('getFileAppends', fn) | ||
94 | def __getattr__(self, name): | ||
95 | if name == 'overlayed': | ||
96 | return self.tinfoil.get_overlayed_recipes() | ||
97 | elif name == 'bbappends': | ||
98 | return self.tinfoil.run_command('getAllAppends') | ||
99 | else: | ||
100 | raise AttributeError("%s instance has no attribute '%s'" % (self.__class__.__name__, name)) | ||
101 | |||
102 | class TinfoilRecipeCacheAdapter: | ||
103 | """ cooker.recipecache adapter """ | ||
104 | def __init__(self, tinfoil): | ||
105 | self.tinfoil = tinfoil | ||
106 | self._cache = {} | ||
107 | |||
108 | def get_pkg_pn_fn(self): | ||
109 | pkg_pn = defaultdict(list, self.tinfoil.run_command('getRecipes') or []) | ||
110 | pkg_fn = {} | ||
111 | for pn, fnlist in pkg_pn.items(): | ||
112 | for fn in fnlist: | ||
113 | pkg_fn[fn] = pn | ||
114 | self._cache['pkg_pn'] = pkg_pn | ||
115 | self._cache['pkg_fn'] = pkg_fn | ||
116 | |||
117 | def __getattr__(self, name): | ||
118 | # Grab these only when they are requested since they aren't always used | ||
119 | if name in self._cache: | ||
120 | return self._cache[name] | ||
121 | elif name == 'pkg_pn': | ||
122 | self.get_pkg_pn_fn() | ||
123 | return self._cache[name] | ||
124 | elif name == 'pkg_fn': | ||
125 | self.get_pkg_pn_fn() | ||
126 | return self._cache[name] | ||
127 | elif name == 'deps': | ||
128 | attrvalue = defaultdict(list, self.tinfoil.run_command('getRecipeDepends') or []) | ||
129 | elif name == 'rundeps': | ||
130 | attrvalue = defaultdict(lambda: defaultdict(list), self.tinfoil.run_command('getRuntimeDepends') or []) | ||
131 | elif name == 'runrecs': | ||
132 | attrvalue = defaultdict(lambda: defaultdict(list), self.tinfoil.run_command('getRuntimeRecommends') or []) | ||
133 | elif name == 'pkg_pepvpr': | ||
134 | attrvalue = self.tinfoil.run_command('getRecipeVersions') or {} | ||
135 | elif name == 'inherits': | ||
136 | attrvalue = self.tinfoil.run_command('getRecipeInherits') or {} | ||
137 | elif name == 'bbfile_priority': | ||
138 | attrvalue = self.tinfoil.run_command('getBbFilePriority') or {} | ||
139 | elif name == 'pkg_dp': | ||
140 | attrvalue = self.tinfoil.run_command('getDefaultPreference') or {} | ||
141 | else: | ||
142 | raise AttributeError("%s instance has no attribute '%s'" % (self.__class__.__name__, name)) | ||
143 | |||
144 | self._cache[name] = attrvalue | ||
145 | return attrvalue | ||
146 | |||
147 | def __init__(self, tinfoil): | ||
148 | self.tinfoil = tinfoil | ||
149 | self.collection = self.TinfoilCookerCollectionAdapter(tinfoil) | ||
150 | self.recipecaches = {} | ||
151 | # FIXME all machines | ||
152 | self.recipecaches[''] = self.TinfoilRecipeCacheAdapter(tinfoil) | ||
153 | self._cache = {} | ||
154 | def __getattr__(self, name): | ||
155 | # Grab these only when they are requested since they aren't always used | ||
156 | if name in self._cache: | ||
157 | return self._cache[name] | ||
158 | elif name == 'skiplist': | ||
159 | attrvalue = self.tinfoil.get_skipped_recipes() | ||
160 | elif name == 'bbfile_config_priorities': | ||
161 | ret = self.tinfoil.run_command('getLayerPriorities') | ||
162 | bbfile_config_priorities = [] | ||
163 | for collection, pattern, regex, pri in ret: | ||
164 | bbfile_config_priorities.append((collection, pattern, re.compile(regex), pri)) | ||
165 | |||
166 | attrvalue = bbfile_config_priorities | ||
167 | else: | ||
168 | raise AttributeError("%s instance has no attribute '%s'" % (self.__class__.__name__, name)) | ||
169 | |||
170 | self._cache[name] = attrvalue | ||
171 | return attrvalue | ||
172 | |||
173 | def findBestProvider(self, pn): | ||
174 | return self.tinfoil.find_best_provider(pn) | ||
175 | |||
176 | |||
32 | class Tinfoil: | 177 | class Tinfoil: |
33 | def __init__(self, output=sys.stdout, tracking=False): | ||
34 | # Needed to avoid deprecation warnings with python 2.6 | ||
35 | warnings.filterwarnings("ignore", category=DeprecationWarning) | ||
36 | 178 | ||
37 | # Set up logging | 179 | def __init__(self, output=sys.stdout, tracking=False): |
38 | self.logger = logging.getLogger('BitBake') | 180 | self.logger = logging.getLogger('BitBake') |
39 | self._log_hdlr = logging.StreamHandler(output) | 181 | self.config_data = None |
40 | bb.msg.addDefaultlogFilter(self._log_hdlr) | 182 | self.cooker = None |
41 | format = bb.msg.BBLogFormatter("%(levelname)s: %(message)s") | 183 | self.tracking = tracking |
42 | if output.isatty(): | 184 | self.ui_module = None |
43 | format.enable_color() | 185 | self.server_connection = None |
44 | self._log_hdlr.setFormatter(format) | ||
45 | self.logger.addHandler(self._log_hdlr) | ||
46 | |||
47 | self.config = CookerConfiguration() | ||
48 | configparams = TinfoilConfigParameters(parse_only=True) | ||
49 | self.config.setConfigParameters(configparams) | ||
50 | self.config.setServerRegIdleCallback(self.register_idle_function) | ||
51 | features = [] | ||
52 | if tracking: | ||
53 | features.append(CookerFeatures.BASEDATASTORE_TRACKING) | ||
54 | self.cooker = BBCooker(self.config, features) | ||
55 | self.config_data = self.cooker.data | ||
56 | bb.providers.logger.setLevel(logging.ERROR) | ||
57 | self.cooker_data = None | ||
58 | |||
59 | def register_idle_function(self, function, data): | ||
60 | pass | ||
61 | 186 | ||
62 | def __enter__(self): | 187 | def __enter__(self): |
63 | return self | 188 | return self |
@@ -65,30 +190,120 @@ class Tinfoil: | |||
65 | def __exit__(self, type, value, traceback): | 190 | def __exit__(self, type, value, traceback): |
66 | self.shutdown() | 191 | self.shutdown() |
67 | 192 | ||
68 | def parseRecipes(self): | 193 | def prepare(self, config_only=False, config_params=None, quiet=0): |
69 | sys.stderr.write("Parsing recipes..") | 194 | if self.tracking: |
70 | self.logger.setLevel(logging.WARNING) | 195 | extrafeatures = [bb.cooker.CookerFeatures.BASEDATASTORE_TRACKING] |
196 | else: | ||
197 | extrafeatures = [] | ||
71 | 198 | ||
72 | try: | 199 | if not config_params: |
73 | while self.cooker.state in (state.initial, state.parsing): | 200 | config_params = TinfoilConfigParameters(config_only=config_only, quiet=quiet) |
74 | self.cooker.updateCache() | ||
75 | except KeyboardInterrupt: | ||
76 | self.cooker.shutdown() | ||
77 | self.cooker.updateCache() | ||
78 | sys.exit(2) | ||
79 | 201 | ||
80 | self.logger.setLevel(logging.INFO) | 202 | cookerconfig = CookerConfiguration() |
81 | sys.stderr.write("done.\n") | 203 | cookerconfig.setConfigParameters(config_params) |
82 | 204 | ||
83 | self.cooker_data = self.cooker.recipecaches[''] | 205 | server, self.server_connection, ui_module = setup_bitbake(config_params, |
206 | cookerconfig, | ||
207 | extrafeatures) | ||
84 | 208 | ||
85 | def prepare(self, config_only = False): | 209 | self.ui_module = ui_module |
86 | if not self.cooker_data: | 210 | |
211 | if self.server_connection: | ||
212 | _server_connections.append(self.server_connection) | ||
87 | if config_only: | 213 | if config_only: |
88 | self.cooker.parseConfiguration() | 214 | config_params.updateToServer(self.server_connection.connection, os.environ.copy()) |
89 | self.cooker_data = self.cooker.recipecaches[''] | 215 | self.run_command('parseConfiguration') |
90 | else: | 216 | else: |
91 | self.parseRecipes() | 217 | self.run_actions(config_params) |
218 | |||
219 | self.config_data = bb.data.init() | ||
220 | connector = TinfoilDataStoreConnector(self, None) | ||
221 | self.config_data.setVar('_remote_data', connector) | ||
222 | self.cooker = TinfoilCookerAdapter(self) | ||
223 | self.cooker_data = self.cooker.recipecaches[''] | ||
224 | else: | ||
225 | raise Exception('Failed to start bitbake server') | ||
226 | |||
227 | def run_actions(self, config_params): | ||
228 | """ | ||
229 | Run the actions specified in config_params through the UI. | ||
230 | """ | ||
231 | ret = self.ui_module.main(self.server_connection.connection, self.server_connection.events, config_params) | ||
232 | if ret: | ||
233 | raise TinfoilUIException(ret) | ||
234 | |||
235 | def parseRecipes(self): | ||
236 | """ | ||
237 | Force a parse of all recipes. Normally you should specify | ||
238 | config_only=False when calling prepare() instead of using this | ||
239 | function; this function is designed for situations where you need | ||
240 | to initialise Tinfoil and use it with config_only=True first and | ||
241 | then conditionally call this function to parse recipes later. | ||
242 | """ | ||
243 | config_params = TinfoilConfigParameters(config_only=False) | ||
244 | self.run_actions(config_params) | ||
245 | |||
246 | def run_command(self, command, *params): | ||
247 | """ | ||
248 | Run a command on the server (as implemented in bb.command). | ||
249 | Note that there are two types of command - synchronous and | ||
250 | asynchronous; in order to receive the results of asynchronous | ||
251 | commands you will need to set an appropriate event mask | ||
252 | using set_event_mask() and listen for the result using | ||
253 | wait_event() - with the correct event mask you'll at least get | ||
254 | bb.command.CommandCompleted and possibly other events before | ||
255 | that depending on the command. | ||
256 | """ | ||
257 | if not self.server_connection: | ||
258 | raise Exception('Not connected to server (did you call .prepare()?)') | ||
259 | |||
260 | commandline = [command] | ||
261 | if params: | ||
262 | commandline.extend(params) | ||
263 | result = self.server_connection.connection.runCommand(commandline) | ||
264 | if result[1]: | ||
265 | raise TinfoilCommandFailed(result[1]) | ||
266 | return result[0] | ||
267 | |||
268 | def set_event_mask(self, eventlist): | ||
269 | """Set the event mask which will be applied within wait_event()""" | ||
270 | if not self.server_connection: | ||
271 | raise Exception('Not connected to server (did you call .prepare()?)') | ||
272 | llevel, debug_domains = bb.msg.constructLogOptions() | ||
273 | ret = self.run_command('setEventMask', self.server_connection.connection.getEventHandle(), llevel, debug_domains, eventlist) | ||
274 | if not ret: | ||
275 | raise Exception('setEventMask failed') | ||
276 | |||
277 | def wait_event(self, timeout=0): | ||
278 | """ | ||
279 | Wait for an event from the server for the specified time. | ||
280 | A timeout of 0 means don't wait if there are no events in the queue. | ||
281 | Returns the next event in the queue or None if the timeout was | ||
282 | reached. Note that in order to recieve any events you will | ||
283 | first need to set the internal event mask using set_event_mask() | ||
284 | (otherwise whatever event mask the UI set up will be in effect). | ||
285 | """ | ||
286 | if not self.server_connection: | ||
287 | raise Exception('Not connected to server (did you call .prepare()?)') | ||
288 | return self.server_connection.events.waitEvent(timeout) | ||
289 | |||
290 | def get_overlayed_recipes(self): | ||
291 | return defaultdict(list, self.run_command('getOverlayedRecipes')) | ||
292 | |||
293 | def get_skipped_recipes(self): | ||
294 | return OrderedDict(self.run_command('getSkippedRecipes')) | ||
295 | |||
296 | def get_all_providers(self): | ||
297 | return defaultdict(list, self.run_command('allProviders')) | ||
298 | |||
299 | def find_providers(self): | ||
300 | return self.run_command('findProviders') | ||
301 | |||
302 | def find_best_provider(self, pn): | ||
303 | return self.run_command('findBestProvider', pn) | ||
304 | |||
305 | def get_runtime_providers(self, rdep): | ||
306 | return self.run_command('getRuntimeProviders', rdep) | ||
92 | 307 | ||
93 | def parse_recipe_file(self, fn, appends=True, appendlist=None, config_data=None): | 308 | def parse_recipe_file(self, fn, appends=True, appendlist=None, config_data=None): |
94 | """ | 309 | """ |
@@ -126,22 +341,72 @@ class Tinfoil: | |||
126 | envdata = parser.loadDataFull(fn, appendfiles) | 341 | envdata = parser.loadDataFull(fn, appendfiles) |
127 | return envdata | 342 | return envdata |
128 | 343 | ||
344 | def build_file(self, buildfile, task): | ||
345 | """ | ||
346 | Runs the specified task for just a single recipe (i.e. no dependencies). | ||
347 | This is equivalent to bitbake -b. | ||
348 | """ | ||
349 | return self.run_command('buildFile', buildfile, task) | ||
350 | |||
129 | def shutdown(self): | 351 | def shutdown(self): |
130 | self.cooker.shutdown(force=True) | 352 | if self.server_connection: |
131 | self.cooker.post_serve() | 353 | self.run_command('clientComplete') |
132 | self.cooker.unlockBitbake() | 354 | _server_connections.remove(self.server_connection) |
133 | self.logger.removeHandler(self._log_hdlr) | 355 | bb.event.ui_queue = [] |
356 | self.server_connection.terminate() | ||
357 | self.server_connection = None | ||
134 | 358 | ||
135 | class TinfoilConfigParameters(ConfigParameters): | 359 | def _reconvert_type(self, obj, origtypename): |
360 | """ | ||
361 | Convert an object back to the right type, in the case | ||
362 | that marshalling has changed it (especially with xmlrpc) | ||
363 | """ | ||
364 | supported_types = { | ||
365 | 'set': set, | ||
366 | 'DataStoreConnectionHandle': bb.command.DataStoreConnectionHandle, | ||
367 | } | ||
136 | 368 | ||
137 | def __init__(self, **options): | 369 | origtype = supported_types.get(origtypename, None) |
370 | if origtype is None: | ||
371 | raise Exception('Unsupported type "%s"' % origtypename) | ||
372 | if type(obj) == origtype: | ||
373 | newobj = obj | ||
374 | elif isinstance(obj, dict): | ||
375 | # New style class | ||
376 | newobj = origtype() | ||
377 | for k,v in obj.items(): | ||
378 | setattr(newobj, k, v) | ||
379 | else: | ||
380 | # Assume we can coerce the type | ||
381 | newobj = origtype(obj) | ||
382 | |||
383 | if isinstance(newobj, bb.command.DataStoreConnectionHandle): | ||
384 | connector = TinfoilDataStoreConnector(self, newobj.dsindex) | ||
385 | newobj = bb.data.init() | ||
386 | newobj.setVar('_remote_data', connector) | ||
387 | |||
388 | return newobj | ||
389 | |||
390 | |||
391 | class TinfoilConfigParameters(BitBakeConfigParameters): | ||
392 | |||
393 | def __init__(self, config_only, **options): | ||
138 | self.initial_options = options | 394 | self.initial_options = options |
139 | super(TinfoilConfigParameters, self).__init__() | 395 | # Apply some sane defaults |
396 | if not 'parse_only' in options: | ||
397 | self.initial_options['parse_only'] = not config_only | ||
398 | #if not 'status_only' in options: | ||
399 | # self.initial_options['status_only'] = config_only | ||
400 | if not 'ui' in options: | ||
401 | self.initial_options['ui'] = 'knotty' | ||
402 | if not 'argv' in options: | ||
403 | self.initial_options['argv'] = [] | ||
140 | 404 | ||
141 | def parseCommandLine(self, argv=sys.argv): | 405 | super(TinfoilConfigParameters, self).__init__() |
142 | class DummyOptions: | ||
143 | def __init__(self, initial_options): | ||
144 | for key, val in initial_options.items(): | ||
145 | setattr(self, key, val) | ||
146 | 406 | ||
147 | return DummyOptions(self.initial_options), None | 407 | def parseCommandLine(self, argv=None): |
408 | # We don't want any parameters parsed from the command line | ||
409 | opts = super(TinfoilConfigParameters, self).parseCommandLine([]) | ||
410 | for key, val in self.initial_options.items(): | ||
411 | setattr(opts[0], key, val) | ||
412 | return opts | ||
diff --git a/bitbake/lib/bblayers/query.py b/bitbake/lib/bblayers/query.py index 29491163c2..5def7179ce 100644 --- a/bitbake/lib/bblayers/query.py +++ b/bitbake/lib/bblayers/query.py | |||
@@ -5,8 +5,6 @@ import sys | |||
5 | import os | 5 | import os |
6 | import re | 6 | import re |
7 | 7 | ||
8 | import bb.cache | ||
9 | import bb.providers | ||
10 | import bb.utils | 8 | import bb.utils |
11 | 9 | ||
12 | from bblayers.common import LayerPlugin | 10 | from bblayers.common import LayerPlugin |
@@ -122,15 +120,13 @@ skipped recipes will also be listed, with a " (skipped)" suffix. | |||
122 | sys.exit(1) | 120 | sys.exit(1) |
123 | 121 | ||
124 | pkg_pn = self.tinfoil.cooker.recipecaches[''].pkg_pn | 122 | pkg_pn = self.tinfoil.cooker.recipecaches[''].pkg_pn |
125 | (latest_versions, preferred_versions) = bb.providers.findProviders(self.tinfoil.config_data, self.tinfoil.cooker.recipecaches[''], pkg_pn) | 123 | (latest_versions, preferred_versions) = self.tinfoil.find_providers() |
126 | allproviders = bb.providers.allProviders(self.tinfoil.cooker.recipecaches['']) | 124 | allproviders = self.tinfoil.get_all_providers() |
127 | 125 | ||
128 | # Ensure we list skipped recipes | 126 | # Ensure we list skipped recipes |
129 | # We are largely guessing about PN, PV and the preferred version here, | 127 | # We are largely guessing about PN, PV and the preferred version here, |
130 | # but we have no choice since skipped recipes are not fully parsed | 128 | # but we have no choice since skipped recipes are not fully parsed |
131 | skiplist = list(self.tinfoil.cooker.skiplist.keys()) | 129 | skiplist = list(self.tinfoil.cooker.skiplist.keys()) |
132 | skiplist.sort( key=lambda fileitem: self.tinfoil.cooker.collection.calc_bbfile_priority(fileitem) ) | ||
133 | skiplist.reverse() | ||
134 | for fn in skiplist: | 130 | for fn in skiplist: |
135 | recipe_parts = os.path.splitext(os.path.basename(fn))[0].split('_') | 131 | recipe_parts = os.path.splitext(os.path.basename(fn))[0].split('_') |
136 | p = recipe_parts[0] | 132 | p = recipe_parts[0] |
@@ -265,10 +261,7 @@ Lists recipes with the bbappends that apply to them as subitems. | |||
265 | def show_appends_for_pn(self, pn): | 261 | def show_appends_for_pn(self, pn): |
266 | filenames = self.tinfoil.cooker_data.pkg_pn[pn] | 262 | filenames = self.tinfoil.cooker_data.pkg_pn[pn] |
267 | 263 | ||
268 | best = bb.providers.findBestProvider(pn, | 264 | best = self.tinfoil.find_best_provider(pn) |
269 | self.tinfoil.config_data, | ||
270 | self.tinfoil.cooker_data, | ||
271 | self.tinfoil.cooker_data.pkg_pn) | ||
272 | best_filename = os.path.basename(best[3]) | 265 | best_filename = os.path.basename(best[3]) |
273 | 266 | ||
274 | return self.show_appends_output(filenames, best_filename) | 267 | return self.show_appends_output(filenames, best_filename) |
@@ -336,10 +329,7 @@ NOTE: .bbappend files can impact the dependencies. | |||
336 | deps = self.tinfoil.cooker_data.deps[f] | 329 | deps = self.tinfoil.cooker_data.deps[f] |
337 | for pn in deps: | 330 | for pn in deps: |
338 | if pn in self.tinfoil.cooker_data.pkg_pn: | 331 | if pn in self.tinfoil.cooker_data.pkg_pn: |
339 | best = bb.providers.findBestProvider(pn, | 332 | best = self.tinfoil.find_best_provider(pn) |
340 | self.tinfoil.config_data, | ||
341 | self.tinfoil.cooker_data, | ||
342 | self.tinfoil.cooker_data.pkg_pn) | ||
343 | self.check_cross_depends("DEPENDS", layername, f, best[3], args.filenames, ignore_layers) | 333 | self.check_cross_depends("DEPENDS", layername, f, best[3], args.filenames, ignore_layers) |
344 | 334 | ||
345 | # The RDPENDS | 335 | # The RDPENDS |
@@ -352,14 +342,11 @@ NOTE: .bbappend files can impact the dependencies. | |||
352 | sorted_rdeps[k2] = 1 | 342 | sorted_rdeps[k2] = 1 |
353 | all_rdeps = sorted_rdeps.keys() | 343 | all_rdeps = sorted_rdeps.keys() |
354 | for rdep in all_rdeps: | 344 | for rdep in all_rdeps: |
355 | all_p = bb.providers.getRuntimeProviders(self.tinfoil.cooker_data, rdep) | 345 | all_p, best = self.tinfoil.get_runtime_providers(rdep) |
356 | if all_p: | 346 | if all_p: |
357 | if f in all_p: | 347 | if f in all_p: |
358 | # The recipe provides this one itself, ignore | 348 | # The recipe provides this one itself, ignore |
359 | continue | 349 | continue |
360 | best = bb.providers.filterProvidersRunTime(all_p, rdep, | ||
361 | self.tinfoil.config_data, | ||
362 | self.tinfoil.cooker_data)[0][0] | ||
363 | self.check_cross_depends("RDEPENDS", layername, f, best, args.filenames, ignore_layers) | 350 | self.check_cross_depends("RDEPENDS", layername, f, best, args.filenames, ignore_layers) |
364 | 351 | ||
365 | # The RRECOMMENDS | 352 | # The RRECOMMENDS |
@@ -372,14 +359,11 @@ NOTE: .bbappend files can impact the dependencies. | |||
372 | sorted_rrecs[k2] = 1 | 359 | sorted_rrecs[k2] = 1 |
373 | all_rrecs = sorted_rrecs.keys() | 360 | all_rrecs = sorted_rrecs.keys() |
374 | for rrec in all_rrecs: | 361 | for rrec in all_rrecs: |
375 | all_p = bb.providers.getRuntimeProviders(self.tinfoil.cooker_data, rrec) | 362 | all_p, best = self.tinfoil.get_runtime_providers(rrec) |
376 | if all_p: | 363 | if all_p: |
377 | if f in all_p: | 364 | if f in all_p: |
378 | # The recipe provides this one itself, ignore | 365 | # The recipe provides this one itself, ignore |
379 | continue | 366 | continue |
380 | best = bb.providers.filterProvidersRunTime(all_p, rrec, | ||
381 | self.tinfoil.config_data, | ||
382 | self.tinfoil.cooker_data)[0][0] | ||
383 | self.check_cross_depends("RRECOMMENDS", layername, f, best, args.filenames, ignore_layers) | 367 | self.check_cross_depends("RRECOMMENDS", layername, f, best, args.filenames, ignore_layers) |
384 | 368 | ||
385 | # The inherit class | 369 | # The inherit class |