summaryrefslogtreecommitdiffstats
path: root/bitbake/lib/bb/ui/crumbs/configurator.py
diff options
context:
space:
mode:
authorJoshua Lock <josh@linux.intel.com>2011-07-01 15:58:50 -0700
committerRichard Purdie <richard.purdie@linuxfoundation.org>2011-07-05 14:40:30 +0100
commit4cc291c007103c19779f995e852b37dbad122293 (patch)
tree3447d62ef1ba2eca08137b8e13df58f8a337a453 /bitbake/lib/bb/ui/crumbs/configurator.py
parent7fc9c3488f7865111ec052d1cab213d216d2b414 (diff)
downloadpoky-4cc291c007103c19779f995e852b37dbad122293.tar.gz
hob: re-designed interaction and implementation
Highlights include: * Atempted GNOME HIG compliance * Simplified UI and interaction model * Sorting and type to find in tree views * Preferences dialog to modify local settings * Dialog to add and remove layers * Search in packages list * Save/Load image recipes The build model has been changed, hob will attempt to build all dependent packages of an image and then use the buildFile server method to build the created image. (Bitbake rev: 48e64acaae4a741b9f5630f426fb4e6142755c2c) Signed-off-by: Joshua Lock <josh@linux.intel.com> Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
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)