diff options
author | Paul Eggleton <paul.eggleton@linux.intel.com> | 2016-12-13 20:07:06 +1300 |
---|---|---|
committer | Richard Purdie <richard.purdie@linuxfoundation.org> | 2016-12-14 12:25:07 +0000 |
commit | 7d5c9860de05efc4272256ccefc530113f01d24e (patch) | |
tree | 659eb51c50941c2920215512e38d59da9cb85ee5 /bitbake/lib/bb/command.py | |
parent | e271d7dc606185130e0e47327205bd423490b7c2 (diff) | |
download | poky-7d5c9860de05efc4272256ccefc530113f01d24e.tar.gz |
bitbake: tinfoil: rewrite as a wrapper around the UI
Rewrite tinfoil as a wrapper around the UI, instead of the earlier
approach of starting up just enough of cooker to do what we want. This
has several advantages:
* It now works when bitbake is memory-resident instead of failing with
"ERROR: Only one copy of bitbake should be run against a build
directory".
* We can now connect an actual UI, thus you get things like the recipe
parsing / cache loading progress bar and parse error handling for free
* We can now handle events generated by the server if we wish to do so
* We can potentially extend this to do more stuff, e.g. actually running
build operations - this needs to be made more practical before we can
use it though (since you effectively have to become the UI yourself
for this at the moment.)
The downside is that tinfoil no longer has direct access to cooker, the
global datastore, or the cache. To mitigate this I have extended
data_smart to provide remote access capability for the datastore, and
created "fake" cooker and cooker.recipecache / cooker.collection adapter
objects in order to avoid breaking too many tinfoil-using scripts that
might be out there (we've never officially documented tinfoil or
BitBake's internal code, but we can still make accommodations where
practical). I've at least gone far enough to support all of the
utilities that use tinfoil in OE-Core with some changes, but I know
there are scripts such as Chris Larson's "bb" out there that do make
other calls into BitBake code that I'm not currently providing access to
through the adapters.
Part of the fix for [YOCTO #5470].
(Bitbake rev: 3bbf8d611c859f74d563778115677a04f5c4ab43)
Signed-off-by: Paul Eggleton <paul.eggleton@linux.intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
Diffstat (limited to 'bitbake/lib/bb/command.py')
-rw-r--r-- | bitbake/lib/bb/command.py | 195 |
1 files changed, 195 insertions, 0 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 |