151 lines
5.5 KiB
Python
151 lines
5.5 KiB
Python
# tinfoil: a simple wrapper around cooker for bitbake-based command-line utilities
|
|
#
|
|
# Copyright (C) 2012 Intel Corporation
|
|
# Copyright (C) 2011 Mentor Graphics Corporation
|
|
#
|
|
# This program is free software; you can redistribute it and/or modify
|
|
# it under the terms of the GNU General Public License version 2 as
|
|
# published by the Free Software Foundation.
|
|
#
|
|
# This program is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License along
|
|
# with this program; if not, write to the Free Software Foundation, Inc.,
|
|
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
|
|
import logging
|
|
import warnings
|
|
import os
|
|
import sys
|
|
|
|
import bb.cache
|
|
import bb.cooker
|
|
import bb.providers
|
|
import bb.utils
|
|
from bb.cooker import state, BBCooker, CookerFeatures
|
|
from bb.cookerdata import CookerConfiguration, ConfigParameters
|
|
import bb.fetch2
|
|
|
|
class Tinfoil:
|
|
def __init__(self, output=sys.stdout, tracking=False):
|
|
# Needed to avoid deprecation warnings with python 2.6
|
|
warnings.filterwarnings("ignore", category=DeprecationWarning)
|
|
|
|
# Set up logging
|
|
self.logger = logging.getLogger('BitBake')
|
|
self._log_hdlr = logging.StreamHandler(output)
|
|
bb.msg.addDefaultlogFilter(self._log_hdlr)
|
|
format = bb.msg.BBLogFormatter("%(levelname)s: %(message)s")
|
|
if output.isatty():
|
|
format.enable_color()
|
|
self._log_hdlr.setFormatter(format)
|
|
self.logger.addHandler(self._log_hdlr)
|
|
|
|
self.config = CookerConfiguration()
|
|
configparams = TinfoilConfigParameters(parse_only=True)
|
|
self.config.setConfigParameters(configparams)
|
|
self.config.setServerRegIdleCallback(self.register_idle_function)
|
|
features = []
|
|
if tracking:
|
|
features.append(CookerFeatures.BASEDATASTORE_TRACKING)
|
|
cleanedvars = bb.utils.clean_environment()
|
|
self.cooker = BBCooker(self.config, features)
|
|
self.config_data = self.cooker.data
|
|
bb.providers.logger.setLevel(logging.ERROR)
|
|
self.cooker_data = None
|
|
for k in cleanedvars:
|
|
os.environ[k] = cleanedvars[k]
|
|
|
|
def register_idle_function(self, function, data):
|
|
pass
|
|
|
|
def __enter__(self):
|
|
return self
|
|
|
|
def __exit__(self, type, value, traceback):
|
|
self.shutdown()
|
|
|
|
def parseRecipes(self):
|
|
sys.stderr.write("Parsing recipes..")
|
|
self.logger.setLevel(logging.WARNING)
|
|
|
|
try:
|
|
while self.cooker.state in (state.initial, state.parsing):
|
|
self.cooker.updateCache()
|
|
except KeyboardInterrupt:
|
|
self.cooker.shutdown()
|
|
self.cooker.updateCache()
|
|
sys.exit(2)
|
|
|
|
self.logger.setLevel(logging.INFO)
|
|
sys.stderr.write("done.\n")
|
|
|
|
self.cooker_data = self.cooker.recipecaches['']
|
|
|
|
def prepare(self, config_only = False):
|
|
if not self.cooker_data:
|
|
if config_only:
|
|
self.cooker.parseConfiguration()
|
|
self.cooker_data = self.cooker.recipecaches['']
|
|
else:
|
|
self.parseRecipes()
|
|
|
|
def parse_recipe_file(self, fn, appends=True, appendlist=None, config_data=None):
|
|
"""
|
|
Parse the specified recipe file (with or without bbappends)
|
|
and return a datastore object representing the environment
|
|
for the recipe.
|
|
Parameters:
|
|
fn: recipe file to parse - can be a file path or virtual
|
|
specification
|
|
appends: True to apply bbappends, False otherwise
|
|
appendlist: optional list of bbappend files to apply, if you
|
|
want to filter them
|
|
config_data: custom config datastore to use. NOTE: if you
|
|
specify config_data then you cannot use a virtual
|
|
specification for fn.
|
|
"""
|
|
if appends and appendlist == []:
|
|
appends = False
|
|
if appends:
|
|
if appendlist:
|
|
appendfiles = appendlist
|
|
else:
|
|
if not hasattr(self.cooker, 'collection'):
|
|
raise Exception('You must call tinfoil.prepare() with config_only=False in order to get bbappends')
|
|
appendfiles = self.cooker.collection.get_file_appends(fn)
|
|
else:
|
|
appendfiles = None
|
|
if config_data:
|
|
# We have to use a different function here if we're passing in a datastore
|
|
localdata = bb.data.createCopy(config_data)
|
|
envdata = bb.cache.parse_recipe(localdata, fn, appendfiles)['']
|
|
else:
|
|
# Use the standard path
|
|
parser = bb.cache.NoCache(self.cooker.databuilder)
|
|
envdata = parser.loadDataFull(fn, appendfiles)
|
|
return envdata
|
|
|
|
def shutdown(self):
|
|
self.cooker.shutdown(force=True)
|
|
self.cooker.post_serve()
|
|
self.cooker.unlockBitbake()
|
|
self.logger.removeHandler(self._log_hdlr)
|
|
|
|
class TinfoilConfigParameters(ConfigParameters):
|
|
|
|
def __init__(self, **options):
|
|
self.initial_options = options
|
|
super(TinfoilConfigParameters, self).__init__()
|
|
|
|
def parseCommandLine(self, argv=sys.argv):
|
|
class DummyOptions:
|
|
def __init__(self, initial_options):
|
|
for key, val in initial_options.items():
|
|
setattr(self, key, val)
|
|
|
|
return DummyOptions(self.initial_options), None
|