blob: 8899e861c32c07ff6d63770cf04b4a2e9215267c [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)
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
Patrick Williamsc0f7c042017-02-23 20:41:17 -060062 def __enter__(self):
63 return self
64
65 def __exit__(self, type, value, traceback):
66 self.shutdown()
67
Patrick Williamsc124f4f2015-09-15 14:41:29 -050068 def parseRecipes(self):
69 sys.stderr.write("Parsing recipes..")
70 self.logger.setLevel(logging.WARNING)
71
72 try:
73 while self.cooker.state in (state.initial, state.parsing):
74 self.cooker.updateCache()
75 except KeyboardInterrupt:
76 self.cooker.shutdown()
77 self.cooker.updateCache()
78 sys.exit(2)
79
80 self.logger.setLevel(logging.INFO)
81 sys.stderr.write("done.\n")
82
Patrick Williamsc0f7c042017-02-23 20:41:17 -060083 self.cooker_data = self.cooker.recipecaches['']
Patrick Williamsc124f4f2015-09-15 14:41:29 -050084
85 def prepare(self, config_only = False):
86 if not self.cooker_data:
87 if config_only:
88 self.cooker.parseConfiguration()
Patrick Williamsc0f7c042017-02-23 20:41:17 -060089 self.cooker_data = self.cooker.recipecaches['']
Patrick Williamsc124f4f2015-09-15 14:41:29 -050090 else:
91 self.parseRecipes()
92
Patrick Williamsc0f7c042017-02-23 20:41:17 -060093 def parse_recipe_file(self, fn, appends=True, appendlist=None, config_data=None):
94 """
95 Parse the specified recipe file (with or without bbappends)
96 and return a datastore object representing the environment
97 for the recipe.
98 Parameters:
99 fn: recipe file to parse - can be a file path or virtual
100 specification
101 appends: True to apply bbappends, False otherwise
102 appendlist: optional list of bbappend files to apply, if you
103 want to filter them
104 config_data: custom config datastore to use. NOTE: if you
105 specify config_data then you cannot use a virtual
106 specification for fn.
107 """
108 if appends and appendlist == []:
109 appends = False
110 if appends:
111 if appendlist:
112 appendfiles = appendlist
113 else:
114 if not hasattr(self.cooker, 'collection'):
115 raise Exception('You must call tinfoil.prepare() with config_only=False in order to get bbappends')
116 appendfiles = self.cooker.collection.get_file_appends(fn)
117 else:
118 appendfiles = None
119 if config_data:
120 # We have to use a different function here if we're passing in a datastore
121 localdata = bb.data.createCopy(config_data)
122 envdata = bb.cache.parse_recipe(localdata, fn, appendfiles)['']
123 else:
124 # Use the standard path
125 parser = bb.cache.NoCache(self.cooker.databuilder)
126 envdata = parser.loadDataFull(fn, appendfiles)
127 return envdata
128
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500129 def shutdown(self):
130 self.cooker.shutdown(force=True)
131 self.cooker.post_serve()
132 self.cooker.unlockBitbake()
Patrick Williamsf1e5d692016-03-30 15:21:19 -0500133 self.logger.removeHandler(self._log_hdlr)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500134
135class TinfoilConfigParameters(ConfigParameters):
136
137 def __init__(self, **options):
138 self.initial_options = options
139 super(TinfoilConfigParameters, self).__init__()
140
141 def parseCommandLine(self, argv=sys.argv):
142 class DummyOptions:
143 def __init__(self, initial_options):
144 for key, val in initial_options.items():
145 setattr(self, key, val)
146
147 return DummyOptions(self.initial_options), None