summaryrefslogtreecommitdiffstats
path: root/bitbake/lib/bb/ui/crumbs/configurator.py
diff options
context:
space:
mode:
Diffstat (limited to 'bitbake/lib/bb/ui/crumbs/configurator.py')
-rw-r--r--bitbake/lib/bb/ui/crumbs/configurator.py278
1 files changed, 278 insertions, 0 deletions
diff --git a/bitbake/lib/bb/ui/crumbs/configurator.py b/bitbake/lib/bb/ui/crumbs/configurator.py
new file mode 100644
index 0000000000..b694143d4c
--- /dev/null
+++ b/bitbake/lib/bb/ui/crumbs/configurator.py
@@ -0,0 +1,278 @@
1#
2# BitBake Graphical GTK User Interface
3#
4# Copyright (C) 2011 Intel Corporation
5#
6# Authored by Joshua Lock <josh@linux.intel.com>
7#
8# This program is free software; you can redistribute it and/or modify
9# it under the terms of the GNU General Public License version 2 as
10# published by the Free Software Foundation.
11#
12# This program is distributed in the hope that it will be useful,
13# but WITHOUT ANY WARRANTY; without even the implied warranty of
14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15# GNU General Public License for more details.
16#
17# You should have received a copy of the GNU General Public License along
18# with this program; if not, write to the Free Software Foundation, Inc.,
19# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20
21import gobject
22import copy
23import re, os
24from bb import data
25
26class Configurator(gobject.GObject):
27
28 """
29 A GObject to handle writing modified configuration values back
30 to conf files.
31 """
32 __gsignals__ = {
33 "layers-loaded" : (gobject.SIGNAL_RUN_LAST,
34 gobject.TYPE_NONE,
35 ()),
36 "layers-changed" : (gobject.SIGNAL_RUN_LAST,
37 gobject.TYPE_NONE,
38 ())
39 }
40
41 def __init__(self):
42 gobject.GObject.__init__(self)
43 self.local = None
44 self.bblayers = None
45 self.enabled_layers = {}
46 self.loaded_layers = {}
47 self.config = {}
48 self.orig_config = {}
49
50 # NOTE: cribbed from the cooker...
51 def _parse(self, f, data, include=False):
52 try:
53 return bb.parse.handle(f, data, include)
54 except (IOError, bb.parse.ParseError) as exc:
55 parselog.critical("Unable to parse %s: %s" % (f, exc))
56 sys.exit(1)
57
58 def _loadLocalConf(self, path):
59 def getString(var):
60 return bb.data.getVar(var, data, True) or ""
61
62 self.local = path
63
64 if self.orig_config:
65 del self.orig_config
66 self.orig_config = {}
67
68 data = bb.data.init()
69 data = self._parse(self.local, data)
70
71 # We only need to care about certain variables
72 mach = getString('MACHINE')
73 if mach and mach != self.config.get('MACHINE', ''):
74 self.config['MACHINE'] = mach
75 sdkmach = getString('SDKMACHINE')
76 if sdkmach and sdkmach != self.config.get('SDKMACHINE', ''):
77 self.config['SDKMACHINE'] = sdkmach
78 distro = getString('DISTRO')
79 if distro and distro != self.config.get('DISTRO', ''):
80 self.config['DISTRO'] = distro
81 bbnum = getString('BB_NUMBER_THREADS')
82 if bbnum and bbnum != self.config.get('BB_NUMBER_THREADS', ''):
83 self.config['BB_NUMBER_THREADS'] = bbnum
84 pmake = getString('PARALLEL_MAKE')
85 if pmake and pmake != self.config.get('PARALLEL_MAKE', ''):
86 self.config['PARALLEL_MAKE'] = pmake
87 incompat = getString('INCOMPATIBLE_LICENSE')
88 if incompat and incompat != self.config.get('INCOMPATIBLE_LICENSE', ''):
89 self.config['INCOMPATIBLE_LICENSE'] = incompat
90 pclass = getString('PACKAGE_CLASSES')
91 if pclass and pclass != self.config.get('PACKAGE_CLASSES', ''):
92 self.config['PACKAGE_CLASSES'] = pclass
93
94 self.orig_config = copy.deepcopy(self.config)
95
96 def setLocalConfVar(self, var, val):
97 if var in self.config:
98 self.config[var] = val
99
100 def _loadLayerConf(self, path):
101 self.bblayers = path
102 self.enabled_layers = {}
103 self.loaded_layers = {}
104 data = bb.data.init()
105 data = self._parse(self.bblayers, data)
106 layers = (bb.data.getVar('BBLAYERS', data, True) or "").split()
107 for layer in layers:
108 # TODO: we may be better off calling the layer by its
109 # BBFILE_COLLECTIONS value?
110 name = self._getLayerName(layer)
111 self.loaded_layers[name] = layer
112
113 self.enabled_layers = copy.deepcopy(self.loaded_layers)
114 self.emit("layers-loaded")
115
116 def _addConfigFile(self, path):
117 pref, sep, filename = path.rpartition("/")
118 if filename == "local.conf" or filename == "hob.local.conf":
119 self._loadLocalConf(path)
120 elif filename == "bblayers.conf":
121 self._loadLayerConf(path)
122
123 def _splitLayer(self, path):
124 # we only care about the path up to /conf/layer.conf
125 layerpath, conf, end = path.rpartition("/conf/")
126 return layerpath
127
128 def _getLayerName(self, path):
129 # Should this be the collection name?
130 layerpath, sep, name = path.rpartition("/")
131 return name
132
133 def disableLayer(self, layer):
134 if layer in self.enabled_layers:
135 del self.enabled_layers[layer]
136
137 def addLayerConf(self, confpath):
138 layerpath = self._splitLayer(confpath)
139 name = self._getLayerName(layerpath)
140 if name not in self.enabled_layers:
141 self.addLayer(name, layerpath)
142 return name, layerpath
143
144 def addLayer(self, name, path):
145 self.enabled_layers[name] = path
146
147 def _isLayerConfDirty(self):
148 # if a different number of layers enabled to what was
149 # loaded, definitely different
150 if len(self.enabled_layers) != len(self.loaded_layers):
151 return True
152
153 for layer in self.loaded_layers:
154 # if layer loaded but no longer present, definitely dirty
155 if layer not in self.enabled_layers:
156 return True
157
158 for layer in self.enabled_layers:
159 # if this layer wasn't present at load, definitely dirty
160 if layer not in self.loaded_layers:
161 return True
162 # if this layers path has changed, definitely dirty
163 if self.enabled_layers[layer] != self.loaded_layers[layer]:
164 return True
165
166 return False
167
168 def _constructLayerEntry(self):
169 """
170 Returns a string representing the new layer selection
171 """
172 layers = self.enabled_layers.copy()
173 # Construct BBLAYERS entry
174 layer_entry = "BBLAYERS = \" \\\n"
175 if 'meta' in layers:
176 layer_entry = layer_entry + " %s \\\n" % layers['meta']
177 del layers['meta']
178 for layer in layers:
179 layer_entry = layer_entry + " %s \\\n" % layers[layer]
180 layer_entry = layer_entry + " \""
181
182 return "".join(layer_entry)
183
184 def writeLocalConf(self):
185 # Dictionary containing only new or modified variables
186 changed_values = {}
187 for var in self.config:
188 val = self.config[var]
189 if self.orig_config.get(var, None) != val:
190 changed_values[var] = val
191
192 if not len(changed_values):
193 return
194
195 # Create a backup of the local.conf
196 bkup = "%s~" % self.local
197 os.rename(self.local, bkup)
198
199 # read the original conf into a list
200 with open(bkup, 'r') as config:
201 config_lines = config.readlines()
202
203 new_config_lines = ["\n"]
204 for var in changed_values:
205 # Convenience function for re.subn(). If the pattern matches
206 # return a string which contains an assignment using the same
207 # assignment operator as the old assignment.
208 def replace_val(matchobj):
209 var = matchobj.group(1) # config variable
210 op = matchobj.group(2) # assignment operator
211 val = changed_values[var] # new config value
212 return "%s %s \"%s\"" % (var, op, val)
213
214 pattern = '^\s*(%s)\s*([+=?.]+)(.*)' % re.escape(var)
215 p = re.compile(pattern)
216 cnt = 0
217 replaced = False
218
219 # Iterate over the local.conf lines and if they are a match
220 # for the pattern comment out the line and append a new line
221 # with the new VAR op "value" entry
222 for line in config_lines:
223 new_line, replacements = p.subn(replace_val, line)
224 if replacements:
225 config_lines[cnt] = "#%s" % line
226 new_config_lines.append(new_line)
227 replaced = True
228 cnt = cnt + 1
229
230 if not replaced:
231 new_config_lines.append("%s = \"%s\"" % (var, changed_values[var]))
232
233 # Add the modified variables
234 config_lines.extend(new_config_lines)
235
236 # Write the updated lines list object to the local.conf
237 with open(self.local, "w") as n:
238 n.write("".join(config_lines))
239
240 del self.orig_config
241 self.orig_config = copy.deepcopy(self.config)
242
243 def writeLayerConf(self):
244 # If we've not added/removed new layers don't write
245 if not self._isLayerConfDirty():
246 return
247
248 # This pattern should find the existing BBLAYERS
249 pattern = 'BBLAYERS\s=\s\".*\"'
250
251 # Backup the users bblayers.conf
252 bkup = "%s~" % self.bblayers
253 os.rename(self.bblayers, bkup)
254
255 replacement = self._constructLayerEntry()
256
257 with open(bkup, "r") as f:
258 contents = f.read()
259 p = re.compile(pattern, re.DOTALL)
260 new = p.sub(replacement, contents)
261
262 with open(self.bblayers, "w") as n:
263 n.write(new)
264
265 # At some stage we should remove the backup we've created
266 # though we should probably verify it first
267 #os.remove(bkup)
268
269 # set loaded_layers for dirtiness tracking
270 self.loaded_layers = copy.deepcopy(self.enabled_layers)
271
272 self.emit("layers-changed")
273
274 def configFound(self, handler, path):
275 self._addConfigFile(path)
276
277 def loadConfig(self, path):
278 self._addConfigFile(path)