blob: 9fa5b5b3db82c1fe05c5c61ccb349e8eb453b76d [file] [log] [blame]
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001# tinfoil: a simple wrapper around cooker for bitbake-based command-line utilities
2#
3# Copyright (C) 2012 Intel Corporation
4# Copyright (C) 2011 Mentor Graphics Corporation
5#
6# This program is free software; you can redistribute it and/or modify
7# it under the terms of the GNU General Public License version 2 as
8# published by the Free Software Foundation.
9#
10# This program is distributed in the hope that it will be useful,
11# but WITHOUT ANY WARRANTY; without even the implied warranty of
12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13# GNU General Public License for more details.
14#
15# You should have received a copy of the GNU General Public License along
16# with this program; if not, write to the Free Software Foundation, Inc.,
17# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18
19import logging
20import warnings
21import os
22import sys
23
24import bb.cache
25import bb.cooker
26import bb.providers
27import bb.utils
28from bb.cooker import state, BBCooker, CookerFeatures
29from bb.cookerdata import CookerConfiguration, ConfigParameters
30import bb.fetch2
31
32class 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
37 # Set up logging
38 self.logger = logging.getLogger('BitBake')
Patrick Williamsf1e5d692016-03-30 15:21:19 -050039 self._log_hdlr = logging.StreamHandler(output)
40 bb.msg.addDefaultlogFilter(self._log_hdlr)
Patrick Williamsc124f4f2015-09-15 14:41:29 -050041 format = bb.msg.BBLogFormatter("%(levelname)s: %(message)s")
42 if output.isatty():
43 format.enable_color()
Patrick Williamsf1e5d692016-03-30 15:21:19 -050044 self._log_hdlr.setFormatter(format)
45 self.logger.addHandler(self._log_hdlr)
Patrick Williamsc124f4f2015-09-15 14:41:29 -050046
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)
Brad Bishop37a0e4d2017-12-04 01:01:44 -050054 cleanedvars = bb.utils.clean_environment()
Patrick Williamsc124f4f2015-09-15 14:41:29 -050055 self.cooker = BBCooker(self.config, features)
56 self.config_data = self.cooker.data
57 bb.providers.logger.setLevel(logging.ERROR)
58 self.cooker_data = None
Brad Bishop37a0e4d2017-12-04 01:01:44 -050059 for k in cleanedvars:
60 os.environ[k] = cleanedvars[k]
Patrick Williamsc124f4f2015-09-15 14:41:29 -050061
62 def register_idle_function(self, function, data):
63 pass
64
Patrick Williamsc0f7c042017-02-23 20:41:17 -060065 def __enter__(self):
66 return self
67
68 def __exit__(self, type, value, traceback):
69 self.shutdown()
70
Patrick Williamsc124f4f2015-09-15 14:41:29 -050071 def parseRecipes(self):
72 sys.stderr.write("Parsing recipes..")
73 self.logger.setLevel(logging.WARNING)
74
75 try:
76 while self.cooker.state in (state.initial, state.parsing):
77 self.cooker.updateCache()
78 except KeyboardInterrupt:
79 self.cooker.shutdown()
80 self.cooker.updateCache()
81 sys.exit(2)
82
83 self.logger.setLevel(logging.INFO)
84 sys.stderr.write("done.\n")
85
Patrick Williamsc0f7c042017-02-23 20:41:17 -060086 self.cooker_data = self.cooker.recipecaches['']
Patrick Williamsc124f4f2015-09-15 14:41:29 -050087
88 def prepare(self, config_only = False):
89 if not self.cooker_data:
90 if config_only:
91 self.cooker.parseConfiguration()
Patrick Williamsc0f7c042017-02-23 20:41:17 -060092 self.cooker_data = self.cooker.recipecaches['']
Patrick Williamsc124f4f2015-09-15 14:41:29 -050093 else:
94 self.parseRecipes()
95
Patrick Williamsc0f7c042017-02-23 20:41:17 -060096 def parse_recipe_file(self, fn, appends=True, appendlist=None, config_data=None):
97 """
98 Parse the specified recipe file (with or without bbappends)
99 and return a datastore object representing the environment
100 for the recipe.
101 Parameters:
102 fn: recipe file to parse - can be a file path or virtual
103 specification
104 appends: True to apply bbappends, False otherwise
105 appendlist: optional list of bbappend files to apply, if you
106 want to filter them
107 config_data: custom config datastore to use. NOTE: if you
108 specify config_data then you cannot use a virtual
109 specification for fn.
110 """
111 if appends and appendlist == []:
112 appends = False
113 if appends:
114 if appendlist:
115 appendfiles = appendlist
116 else:
117 if not hasattr(self.cooker, 'collection'):
118 raise Exception('You must call tinfoil.prepare() with config_only=False in order to get bbappends')
119 appendfiles = self.cooker.collection.get_file_appends(fn)
120 else:
121 appendfiles = None
122 if config_data:
123 # We have to use a different function here if we're passing in a datastore
124 localdata = bb.data.createCopy(config_data)
125 envdata = bb.cache.parse_recipe(localdata, fn, appendfiles)['']
126 else:
127 # Use the standard path
128 parser = bb.cache.NoCache(self.cooker.databuilder)
129 envdata = parser.loadDataFull(fn, appendfiles)
130 return envdata
131
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500132 def shutdown(self):
133 self.cooker.shutdown(force=True)
134 self.cooker.post_serve()
135 self.cooker.unlockBitbake()
Patrick Williamsf1e5d692016-03-30 15:21:19 -0500136 self.logger.removeHandler(self._log_hdlr)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500137
138class TinfoilConfigParameters(ConfigParameters):
139
140 def __init__(self, **options):
141 self.initial_options = options
142 super(TinfoilConfigParameters, self).__init__()
143
144 def parseCommandLine(self, argv=sys.argv):
145 class DummyOptions:
146 def __init__(self, initial_options):
147 for key, val in initial_options.items():
148 setattr(self, key, val)
149
150 return DummyOptions(self.initial_options), None