Merge lp:~dooferlad/linaro-image-tools/fetch_image_gui into lp:linaro-image-tools/11.11
- fetch_image_gui
- Merge into trunk
Status: | Rejected |
---|---|
Rejected by: | Loïc Minier |
Proposed branch: | lp:~dooferlad/linaro-image-tools/fetch_image_gui |
Merge into: | lp:linaro-image-tools/11.11 |
Prerequisite: | lp:~dooferlad/linaro-image-tools/fetch_image_server_indexer |
Diff against target: |
1749 lines (+1740/-0) 2 files modified
fetch_image.py (+79/-0) fetch_image_ui.py (+1661/-0) |
To merge this branch: | bzr merge lp:~dooferlad/linaro-image-tools/fetch_image_gui |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
James Westby (community) | Approve | ||
Review via email: mp+66917@code.launchpad.net |
This proposal supersedes a proposal from 2011-06-17.
Commit message
Description of the change
Initial merge request of fetch_image_ui.py - a GUI with similar functionality to fetch_image.py.
The GUI guides the user through the process of creating an image for their ARM hardware. Files are pulled as required from release.linaro.org and snapshots.
--
Now with split up unit tests!
James Westby (james-w) wrote : Posted in a previous version of this proposal | # |
James Westby (james-w) : Posted in a previous version of this proposal | # |
James Tunnicliffe (dooferlad) wrote : Posted in a previous version of this proposal | # |
On 24 June 2011 21:58, James Westby <email address hidden> wrote:
> 133 + if(style != None):
> 134 + radio_button = wx.RadioButton(
> 135 + else:
> 136 + radio_button = wx.RadioButton(
>
> I think that's unnecessary isn't it? style=None is usually the default.
In this case, sadly not.
> (also we usually avoid spaces around = in method calls)
Noted and fixed.
> 226 + if "panda" in self.settings[
> 227 + default_hardware = "panda"
>
> Was this just to make your testing easier? I don't think that the choice should
> have a default until we're in a position to remember their last answer.
Mostly yes. I am sure we could have nothing selected and the next
button disabled by default. I didn't think it was too cheeky to do
since there are a lot of panda boards in the hands of Linaro engineers
:-) I am sure in the future we could remember some choices between
runs as well, which would be useful for just getting the latest build
for your board.
> 1562 + def test_url_
>
> Please break up this test in to several tests. These sort of test cases
> are a nightmare to debug. Ideally each test method should assert a single
> thing.
I have split it into three, with functions named such that if test x
requires test y to pass before it will pass, x will run first.
--
James Tunnicliffe
James Westby (james-w) : | # |
Loïc Minier (lool) wrote : | # |
This is marked as approved but not merged, but I see similar code in linaro-image-tools; I guess this really was superseded?
James Tunnicliffe (dooferlad) wrote : | # |
Indeed it was.
On 8 August 2011 22:51, Loïc Minier <email address hidden> wrote:
> This is marked as approved but not merged, but I see similar code in linaro-image-tools; I guess this really was superseded?
> --
> https:/
> You are the owner of lp:~dooferlad/linaro-image-tools/fetch_image_gui.
>
--
James Tunnicliffe
Unmerged revisions
- 362. By James Tunnicliffe
-
Slight style clean up.
- 361. By James Tunnicliffe
-
Split unit test into three cases.
Preview Diff
1 | === added file 'fetch_image.py' |
2 | --- fetch_image.py 1970-01-01 00:00:00 +0000 |
3 | +++ fetch_image.py 2011-07-05 15:28:36 +0000 |
4 | @@ -0,0 +1,79 @@ |
5 | +#!/usr/bin/env python |
6 | +# Copyright (C) 2010, 2011 Linaro |
7 | +# |
8 | +# Author: James Tunnicliffe <james.tunnicliffe@linaro.org> |
9 | +# |
10 | +# This file is part of Linaro Image Tools. |
11 | +# |
12 | +# Linaro Image Tools is free software; you can redistribute it and/or |
13 | +# modify it under the terms of the GNU General Public License |
14 | +# as published by the Free Software Foundation; either version 2 |
15 | +# of the License, or (at your option) any later version. |
16 | +# |
17 | +# Linaro Image Tools is distributed in the hope that it will be useful, |
18 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
19 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
20 | +# GNU General Public License for more details. |
21 | +# |
22 | +# You should have received a copy of the GNU General Public License |
23 | +# along with Linaro Image Tools; if not, write to the Free Software |
24 | +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, |
25 | +# USA. |
26 | + |
27 | +import sys |
28 | +import os |
29 | +import linaro_image_tools.FetchImage as FetchImage |
30 | +import logging |
31 | + |
32 | + |
33 | +def main(): |
34 | + file_handler = FetchImage.FileHandler() |
35 | + config = FetchImage.FetchImageConfig() |
36 | + |
37 | + # Unfortunately we need to do a bit of a hack here and look for some |
38 | + # options before performing a full options parse. |
39 | + clean_cache = ("--clean-cache" in sys.argv[1:] |
40 | + or "-x" in sys.argv[1:]) |
41 | + |
42 | + force_download = ("--force-download" in sys.argv[1:] |
43 | + or "-d" in sys.argv[1:]) |
44 | + |
45 | + if clean_cache: |
46 | + file_handler.clean_cache() |
47 | + |
48 | + # If the settings file and server index need updating, grab them |
49 | + file_handler.update_files_from_server(force_download) |
50 | + |
51 | + # Load settings YAML, which defines the parameters we ask for and |
52 | + # acceptable responses from the user |
53 | + config.read_config(file_handler.settings_file) |
54 | + |
55 | + # Using the settings that the YAML defines as what we need for a build, |
56 | + # generate a command line parser and parse the command line |
57 | + config.parse_args(sys.argv[1:]) |
58 | + |
59 | + if config.args['platform'] == "snapshot": |
60 | + config.args['release_or_snapshot'] = "snapshot" |
61 | + else: |
62 | + config.args['release_or_snapshot'] = "release" |
63 | + |
64 | + # Using the config we have, look up URLs to download data from in the |
65 | + # server index |
66 | + db = FetchImage.DB(file_handler.index_file) |
67 | + |
68 | + image_url, hwpack_url = db.get_image_and_hwpack_urls(config.args) |
69 | + |
70 | + if(image_url and hwpack_url): |
71 | + |
72 | + tools_dir = os.path.dirname(__file__) |
73 | + if tools_dir == '': |
74 | + tools_dir = None |
75 | + |
76 | + file_handler.create_media(image_url, hwpack_url, |
77 | + config.args, tools_dir) |
78 | + else: |
79 | + logging.error( |
80 | + "Unable to find files that match the parameters specified") |
81 | + |
82 | +if __name__ == '__main__': |
83 | + main() |
84 | |
85 | === added file 'fetch_image_ui.py' |
86 | --- fetch_image_ui.py 1970-01-01 00:00:00 +0000 |
87 | +++ fetch_image_ui.py 2011-07-05 15:28:36 +0000 |
88 | @@ -0,0 +1,1661 @@ |
89 | +#!/usr/bin/env python |
90 | +# Copyright (C) 2010, 2011 Linaro |
91 | +# |
92 | +# Author: James Tunnicliffe <james.tunnicliffe@linaro.org> |
93 | +# |
94 | +# This file is part of Linaro Image Tools. |
95 | +# |
96 | +# Linaro Image Tools is free software; you can redistribute it and/or |
97 | +# modify it under the terms of the GNU General Public License |
98 | +# as published by the Free Software Foundation; either version 2 |
99 | +# of the License, or (at your option) any later version. |
100 | +# |
101 | +# Linaro Image Tools is distributed in the hope that it will be useful, |
102 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
103 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
104 | +# GNU General Public License for more details. |
105 | +# |
106 | +# You should have received a copy of the GNU General Public License |
107 | +# along with Linaro Image Tools; if not, write to the Free Software |
108 | +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, |
109 | +# USA. |
110 | + |
111 | +import wx |
112 | +import wx.wizard |
113 | +import wx.wizard as wiz |
114 | +import sys |
115 | +import re |
116 | +import os |
117 | +import linaro_image_tools.FetchImage as FetchImage |
118 | +import string |
119 | +import unittest |
120 | +import operator |
121 | +import Queue |
122 | + |
123 | + |
124 | +def add_button(bind_to, |
125 | + sizer, |
126 | + label, |
127 | + style, |
128 | + select_event, |
129 | + hover_event, |
130 | + unhover_event): |
131 | + |
132 | + """Create a radio button with event bindings.""" |
133 | + if(style != None): |
134 | + radio_button = wx.RadioButton(bind_to, label=label, style=style) |
135 | + else: |
136 | + radio_button = wx.RadioButton(bind_to, label=label) |
137 | + |
138 | + sizer.Add(radio_button, 0, wx.ALIGN_LEFT | wx.LEFT | wx.RIGHT | wx.TOP, 5) |
139 | + bind_to.Bind(wx.EVT_RADIOBUTTON, select_event, radio_button) |
140 | + wx.EVT_ENTER_WINDOW(radio_button, hover_event) |
141 | + wx.EVT_LEAVE_WINDOW(radio_button, unhover_event) |
142 | + |
143 | + return radio_button |
144 | + |
145 | + |
146 | +class ReleaseOrSnapshotPage(wiz.PyWizardPage): |
147 | + """Ask the user if they want to use a release or a snapshot""" |
148 | + |
149 | + def __init__(self, parent, config): |
150 | + wiz.PyWizardPage.__init__(self, parent) |
151 | + self.config = config |
152 | + self.settings = self.config.settings |
153 | + self.sizer = wx.BoxSizer(wx.VERTICAL) |
154 | + self.next = None |
155 | + self.prev = None |
156 | + |
157 | + self.sizer.Add(wx.StaticText(self, -1, |
158 | +"""This Wizard will write an operating system of your choosing to |
159 | +either a disk image or to an MMC card. First we need to know if |
160 | +your priority is stability or the latest and greatest features.""")) |
161 | + |
162 | + self.box1 = wx.BoxSizer(wx.VERTICAL) |
163 | + |
164 | + self.button_text = {'release': "I would like to run stable, " |
165 | + "tested software.", |
166 | + 'snapshot': "I would like to run untested, but " |
167 | + "more up-to-date software."} |
168 | + |
169 | + add_button(self, self.box1, self.button_text['release'], |
170 | + wx.RB_GROUP, self.event_radio_button_select, None, None) |
171 | + |
172 | + # Save the setting for the default selected value |
173 | + self.settings['release_or_snapshot'] = "release" |
174 | + |
175 | + add_button(self, self.box1, self.button_text['snapshot'], None, |
176 | + self.event_radio_button_select, None, None) |
177 | + |
178 | + self.sizer.Add(self.box1, 0, wx.ALIGN_LEFT | wx.ALL, 5) |
179 | + |
180 | + self.SetSizerAndFit(self.sizer) |
181 | + self.sizer.Fit(self) |
182 | + self.Move((50, 50)) |
183 | + |
184 | + def event_radio_button_select(self, event): |
185 | + self.radio_selected = event.GetEventObject().GetLabel() |
186 | + # The radio button can be release, snapshot or "latest snapshot" |
187 | + if(self.radio_selected == self.button_text['release']): |
188 | + self.settings['release_or_snapshot'] = "release" |
189 | + else: |
190 | + self.settings['release_or_snapshot'] = "snapshot" |
191 | + |
192 | + def SetNext(self, next): |
193 | + self.next = next |
194 | + |
195 | + def GetNext(self): |
196 | + return self.next |
197 | + |
198 | + |
199 | +class AboutMyHardwarePage(wiz.WizardPageSimple): |
200 | + """Ask the user about their hardware. This only asks about the board, not |
201 | + any specific hardware packs because there can be multiple names for the |
202 | + same hardware pack or sometimes a hardware pack is only available in the |
203 | + releases or snapshots repository. We whittle down the choice as we go |
204 | + and the user can chose a hardare pack (if they don't like the default) |
205 | + under advanced options in the Linaro Media Create options |
206 | + page""" |
207 | + |
208 | + def __init__(self, parent, config, db, width): |
209 | + wiz.WizardPageSimple.__init__(self, parent) |
210 | + self.settings = config.settings |
211 | + self.db = db |
212 | + self.sizer = wx.BoxSizer(wx.VERTICAL) |
213 | + self.box1 = wx.BoxSizer(wx.VERTICAL) |
214 | + self.box2 = wx.BoxSizer(wx.VERTICAL) |
215 | + |
216 | + header = wx.StaticText(self, |
217 | + label = "Please select the hardware that you " |
218 | + "would like to build an image for from " |
219 | + "the following list") |
220 | + |
221 | + header.Wrap(width - 10) # -10 because boarder below is 5 pixels wide |
222 | + |
223 | + #--- Hardware Combo Box --- |
224 | + # Make sure that the displayed release is the one set in settings if |
225 | + # no selection is made |
226 | + if "panda" in self.settings['choice']['hardware'].keys(): |
227 | + default_hardware = "panda" |
228 | + else: |
229 | + default_hardware = self.settings['choice']['hardware'].keys()[-1] |
230 | + |
231 | + self.settings['hardware'] = default_hardware |
232 | + self.settings['compatable_hwpacks'] = ( |
233 | + self.settings['choice']['hwpack'][self.settings['hardware']]) |
234 | + |
235 | + self.cb_hardware = wx.ComboBox(self, |
236 | + value = |
237 | + self.settings['choice']['hardware'][default_hardware], |
238 | + style = wx.CB_DROPDOWN | wx.CB_READONLY) |
239 | + |
240 | + self.Bind(wx.EVT_COMBOBOX, |
241 | + self.event_combo_box_hardware, |
242 | + self.cb_hardware) |
243 | + self.box1.Add(self.cb_hardware, 0, |
244 | + wx.ALIGN_LEFT | wx.LEFT | wx.RIGHT | wx.TOP, 5) |
245 | + |
246 | + self.sizer.Add(header) |
247 | + self.sizer.Add(self.box1, 0, wx.ALIGN_LEFT | wx.ALL, 5) |
248 | + self.sizer.Add(self.box2, 0, wx.ALIGN_LEFT | wx.ALL, 5) |
249 | + self.SetSizerAndFit(self.sizer) |
250 | + self.sizer.Fit(self) |
251 | + self.Move((50, 50)) |
252 | + |
253 | + def on_page_changing(self): |
254 | + self.update_hardware_box() |
255 | + |
256 | + def update_hardware_box(self): |
257 | + self.cb_hardware.Clear() |
258 | + |
259 | + sorted_hardware_names = sorted(self.settings['choice']['hardware'] |
260 | + .iteritems(), |
261 | + key=operator.itemgetter(1)) |
262 | + |
263 | + table = self.settings['release_or_snapshot'] + "_hwpacks" |
264 | + |
265 | + for device_name, human_readable_name in sorted_hardware_names: |
266 | + for hwpack in self.settings['choice']['hwpack'][device_name]: |
267 | + if self.db.hardware_is_available_in_table(table, hwpack): |
268 | + self.cb_hardware.Append(human_readable_name, device_name) |
269 | + break |
270 | + |
271 | + #--- Event(s) --- |
272 | + def event_combo_box_hardware(self, event): |
273 | + self.settings['hardware'] = (event |
274 | + .GetEventObject() |
275 | + .GetClientData(event.GetSelection()) |
276 | + .encode('ascii')) |
277 | + |
278 | + self.settings['compatable_hwpacks'] = ( |
279 | + self.settings['choice']['hwpack'][self.settings['hardware']]) |
280 | + #--- END event(s) --- |
281 | + |
282 | + |
283 | +class SelectStableRelease(wiz.WizardPageSimple): |
284 | + """Ask the user which Linaro release they would like to run.""" |
285 | + def __init__(self, parent, config, db, width): |
286 | + wiz.WizardPageSimple.__init__(self, parent) |
287 | + self.settings = config.settings |
288 | + self.db = db |
289 | + self.sizer = wx.BoxSizer(wx.VERTICAL) |
290 | + self.wizard = parent |
291 | + |
292 | + header = wx.StaticText(self, label = "Please select the stable Linaro " |
293 | + "release you would like to use") |
294 | + |
295 | + header.Wrap(width - 10) # -10 because boarder below is 5 pixels wide |
296 | + |
297 | + self.sizer.Add(header) |
298 | + self.box1 = wx.BoxSizer(wx.VERTICAL) |
299 | + |
300 | + platforms = [] |
301 | + for key, value in self.settings['choice']['platform'].items(): |
302 | + platforms.append(key) |
303 | + |
304 | + default_release = self.settings['UI']['translate'][platforms[-1]] |
305 | + self.cb_release = wx.ComboBox(self, |
306 | + value = default_release, |
307 | + style = wx.CB_DROPDOWN | wx.CB_READONLY) |
308 | + self.Bind(wx.EVT_COMBOBOX, |
309 | + self.event_combo_box_release, |
310 | + self.cb_release) |
311 | + |
312 | + if(default_release in self.settings['UI']['translate']): |
313 | + default_release = self.settings['UI']['translate'][default_release] |
314 | + self.settings['platform'] = ( |
315 | + self.settings['UI']['reverse-translate'][default_release]) |
316 | + |
317 | + for item in platforms: |
318 | + if(item in self.settings['UI']['translate']): |
319 | + new_item = self.settings['UI']['translate'][item] |
320 | + item = new_item |
321 | + |
322 | + self.cb_release.Append(item, item.upper()) |
323 | + |
324 | + self.cb_build = wx.ComboBox(self, |
325 | + style = wx.CB_DROPDOWN | wx.CB_READONLY) |
326 | + self.Bind(wx.EVT_COMBOBOX, self.event_combo_box_build, self.cb_build) |
327 | + |
328 | + self.box1.Add(self.cb_release, 0, |
329 | + wx.ALIGN_LEFT | wx.LEFT | wx.RIGHT | wx.TOP, 5) |
330 | + self.box1.Add(self.cb_build, 0, |
331 | + wx.ALIGN_LEFT | wx.LEFT | wx.RIGHT | wx.TOP, 5) |
332 | + self.sizer.Add(self.box1, 0, wx.ALIGN_LEFT | wx.ALL, 5) |
333 | + self.SetSizerAndFit(self.sizer) |
334 | + self.sizer.Fit(self) |
335 | + self.Move((50, 50)) |
336 | + |
337 | + def update_build_box(self): |
338 | + """Depending on what hardware has been chosen, the OS list may be |
339 | + restricted. Filter out anything that is unavailable.""" |
340 | + self.cb_build.Clear() |
341 | + |
342 | + builds = self.db.get_builds(self.settings['platform']) |
343 | + self.cb_build.SetValue("No build available") |
344 | + |
345 | + for build in builds: |
346 | + if( self.db.hardware_is_available_for_platform_build( |
347 | + self.settings['compatable_hwpacks'], |
348 | + self.settings['platform'], |
349 | + build) |
350 | + and self.db.build_is_available_for_platform_image( |
351 | + "release_binaries", |
352 | + self.settings['platform'], |
353 | + self.settings['image'], |
354 | + build)): |
355 | + |
356 | + self.cb_build.Append(build) |
357 | + self.cb_build.SetValue(build) |
358 | + self.settings['release_build'] = build |
359 | + |
360 | + available_hwpacks = ( |
361 | + self.db.get_available_hwpacks_for_hardware_build_plaform( |
362 | + self.settings['compatable_hwpacks'], |
363 | + self.settings['platform'], |
364 | + self.settings['release_build'])) |
365 | + |
366 | + if len(available_hwpacks): |
367 | + self.settings['hwpack'] = available_hwpacks[0] |
368 | + self.wizard.FindWindowById(wx.ID_FORWARD).Enable() |
369 | + else: |
370 | + self.wizard.FindWindowById(wx.ID_FORWARD).Disable() |
371 | + |
372 | + def update_release_and_build_boxes(self): |
373 | + """Depending on what hardware has been chosen, some builds may be |
374 | + unavailable...""" |
375 | + self.cb_release.Clear() |
376 | + |
377 | + default_release = None |
378 | + for platform, value in self.settings['choice']['platform'].items(): |
379 | + if(self.db.hardware_is_available_for_platform( |
380 | + self.settings['compatable_hwpacks'], |
381 | + platform) |
382 | + and len(self.db.execute_return_list( |
383 | + 'select * from release_binaries ' |
384 | + 'where platform == ? and image == ?', |
385 | + (platform, self.settings['image'])))): |
386 | + |
387 | + if(platform in self.settings['UI']['translate']): |
388 | + platform = self.settings['UI']['translate'][platform] |
389 | + |
390 | + self.cb_release.Append(platform, platform.upper()) |
391 | + if not default_release or default_release < platform: |
392 | + default_release = platform |
393 | + |
394 | + self.settings['platform'] = ( |
395 | + self.settings['UI']['reverse-translate'][default_release]) |
396 | + self.cb_release.SetValue(default_release) |
397 | + self.update_build_box() |
398 | + |
399 | + #--- Event(s) --- |
400 | + def event_combo_box_release(self, evt): |
401 | + str = evt.GetString().encode('ascii').lower() |
402 | + if(str in self.settings['UI']['reverse-translate']): |
403 | + str = self.settings['UI']['reverse-translate'][str] |
404 | + self.settings['platform'] = str |
405 | + |
406 | + self.update_build_box() |
407 | + |
408 | + def event_combo_box_build(self, evt): |
409 | + self.settings['release_build'] = evt.GetString().encode('ascii') |
410 | + #--- END event(s) --- |
411 | + |
412 | + |
413 | +class SelectSnapshot(wiz.WizardPageSimple): |
414 | + """Present the user with a calendar widget and a list of builds available |
415 | + on the selected date so they can chose a snapshot. Filter out days when |
416 | + their chosen hardware does not have an available build.""" |
417 | + |
418 | + def __init__(self, parent, config, db, width): |
419 | + wiz.WizardPageSimple.__init__(self, parent) |
420 | + self.settings = config.settings |
421 | + self.db = db |
422 | + self.wizard = parent |
423 | + self.width = width |
424 | + self.sizer = wx.BoxSizer(wx.VERTICAL) |
425 | + |
426 | + header = wx.StaticText(self, |
427 | + label = "Builds are created most days. First " |
428 | + "please select the day on which the " |
429 | + "build you would like to use was built," |
430 | + " then, if there was more than one " |
431 | + "build that day you will be able to " |
432 | + "select the build number.") |
433 | + header.Wrap(width - 10) # -10 because boarder below is 5 pixels wide |
434 | + |
435 | + box1 = wx.BoxSizer(wx.VERTICAL) |
436 | + self.sizer.Add(header) |
437 | + |
438 | + # Set today as the default build date in settings |
439 | + # (matches the date picker) |
440 | + self.today = wx.DateTime() |
441 | + self.today.SetToCurrent() |
442 | + self.settings['build_date'] = self.today.FormatISODate().encode('ascii') |
443 | + |
444 | + dpc = wx.DatePickerCtrl(self, size = (120, -1), |
445 | + style = wx.DP_DEFAULT) |
446 | + self.Bind(wx.EVT_DATE_CHANGED, self.on_date_changed, dpc) |
447 | + |
448 | + #--- Build number Combo Box --- |
449 | + # Make sure that the displayed build is the one set in settings if no |
450 | + # selection is made |
451 | + self.settings['build_number'] = 0 |
452 | + self.update_build() |
453 | + self.cb_build = wx.ComboBox(self, |
454 | + style = wx.CB_DROPDOWN | wx.CB_READONLY) |
455 | + self.Bind(wx.EVT_COMBOBOX, self.event_combo_box_build, self.cb_build) |
456 | + |
457 | + #--- Layout --- |
458 | + # -- Combo boxes for hardware and image selection -- |
459 | + |
460 | + grid2 = wx.FlexGridSizer(0, 2, 0, 0) |
461 | + grid2.Add(dpc, 0, wx.ALIGN_LEFT | wx.ALL, 5) |
462 | + grid2.Add(self.cb_build, 0, wx.ALIGN_LEFT | wx.ALL, 5) |
463 | + |
464 | + box1.Add(grid2, 0, wx.ALIGN_LEFT | wx.ALL, 5) |
465 | + |
466 | + self.sizer.Add(box1, 0, wx.ALIGN_LEFT | wx.ALL, 5) |
467 | + |
468 | + self.help_text = wx.StaticText(self) |
469 | + self.sizer.Add(self.help_text, 1, wx.EXPAND, 5) |
470 | + |
471 | + self.SetSizer(self.sizer) |
472 | + self.sizer.Fit(self) |
473 | + self.Move((50, 50)) |
474 | + |
475 | + def update_platform(self): |
476 | + build_and_date = self.settings['snapshot_build'].split(":") |
477 | + |
478 | + if len(build_and_date) == 2: |
479 | + self.settings['platform'] = ( |
480 | + self.db.execute_return_list( |
481 | + "select platform from snapshot_binaries " |
482 | + "where date == ? and build == ?", |
483 | + (build_and_date[0], build_and_date[1]))) |
484 | + |
485 | + if len(self.settings['platform']) > 0: |
486 | + self.settings['platform'] = self.settings['platform'][0][0] |
487 | + |
488 | + def update_build(self): |
489 | + small_date = re.sub('-', '', self.settings['build_date']) |
490 | + self.settings['snapshot_build'] = (small_date |
491 | + + ":" |
492 | + + str(self.settings['build_number'])) |
493 | + |
494 | + def fill_build_combo_box_for_date(self, date): |
495 | + """Every time a date is chosen, this function should be called. It will |
496 | + check to see if a compatible build is available. If there isn't, it |
497 | + will search for one and provide some help text to tell the user when |
498 | + compatable builds were built.""" |
499 | + # Re-populate the build combo box |
500 | + |
501 | + self.cb_build.Clear() |
502 | + |
503 | + builds = self.db.get_binary_builds_on_day_from_db( |
504 | + self.settings['image'], |
505 | + date, |
506 | + self.settings['compatable_hwpacks']) |
507 | + |
508 | + if len(builds): |
509 | + max = 0 |
510 | + for item in builds: |
511 | + #Always get a tuple, only interested in the first entry |
512 | + item = item[0] |
513 | + self.cb_build.Append(item, item.upper()) |
514 | + |
515 | + if item > max: |
516 | + max = item |
517 | + |
518 | + self.cb_build.SetValue(max) |
519 | + self.wizard.FindWindowById(wx.ID_FORWARD).Enable() |
520 | + self.help_text.SetLabel("") |
521 | + |
522 | + else: |
523 | + self.cb_build.SetValue("No builds available") |
524 | + future_date, past_date = self.db.get_next_prev_day_with_builds( |
525 | + self.settings['image'], |
526 | + date, |
527 | + self.settings['compatable_hwpacks']) |
528 | + |
529 | + help_text = None |
530 | + |
531 | + if future_date and past_date: |
532 | + help_text = ("There are no builds that match your " |
533 | + "specifications available on the selected date. " |
534 | + "The previous build was on " + past_date + |
535 | + " and the next build was on " + future_date + ".") |
536 | + elif future_date: |
537 | + help_text = ("There are no builds that match your " |
538 | + "specifications available on the selected date. " |
539 | + "The next build was on " + future_date + |
540 | + " and I couldn't find a past build (looked one " |
541 | + "year back from the selected date).") |
542 | + elif past_date: |
543 | + help_text = ("There are no builds that match your " |
544 | + "specifications available on the selected date. " |
545 | + "The previous build was on " + past_date) |
546 | + if date != self.today.FormatISODate().encode('ascii'): |
547 | + help_text += (" and I couldn't find a future build (I " |
548 | + "looked up to one year forward from the " |
549 | + "selected date).") |
550 | + else: |
551 | + help_text = ("I could not find any builds that match your " |
552 | + "specifications close to the selected date (I " |
553 | + "looked forward and back one year from the " |
554 | + "selected date).") |
555 | + |
556 | + self.help_text.SetLabel(help_text) |
557 | + self.help_text.Wrap(self.width - 10) |
558 | + self.wizard.FindWindowById(wx.ID_FORWARD).Disable() |
559 | + |
560 | + #--- Event(s) --- |
561 | + def on_date_changed(self, evt): |
562 | + self.settings['build_date'] = evt.GetDate().FormatISODate().encode('ascii') |
563 | + self.fill_build_combo_box_for_date(self.settings['build_date']) |
564 | + self.update_build() |
565 | + |
566 | + def event_combo_box_build(self, evt): |
567 | + self.settings['build_number'] = evt.GetString().encode('ascii').lower() |
568 | + self.update_build() |
569 | + #--- END event(s) --- |
570 | + |
571 | + |
572 | +class SelectOS(wiz.WizardPageSimple): |
573 | + """Ask the user which OS they would like to run. Filter out any choices |
574 | + that are unavailable due to previous choices.""" |
575 | + def __init__(self, parent, config, db, width): |
576 | + wiz.WizardPageSimple.__init__(self, parent) |
577 | + self.settings = config.settings |
578 | + self.wizard = parent |
579 | + self.db = db |
580 | + self.width = width |
581 | + self.sizer = wx.BoxSizer(wx.VERTICAL) |
582 | + self.settings['image'] = None |
583 | + |
584 | + header = wx.StaticText(self, label = "Please select the operating " |
585 | + "system you would like to run on " |
586 | + "your hardware.") |
587 | + header.Wrap(width - 10) # -10 because boarder below is 5 pixels wide |
588 | + |
589 | + self.box1 = wx.BoxSizer(wx.VERTICAL) |
590 | + self.sizer.Add(header) |
591 | + |
592 | + self.cb_image = wx.ComboBox(self, |
593 | + style = wx.CB_DROPDOWN | wx.CB_READONLY) |
594 | + self.Bind(wx.EVT_COMBOBOX, self.event_combo_box_os, self.cb_image) |
595 | + |
596 | + #--- Layout --- |
597 | + # -- Combo boxes for hardware and image selection -- |
598 | + self.box1.Add(self.cb_image, 0, wx.ALIGN_LEFT | wx.ALL, 5) |
599 | + |
600 | + self.sizer.Add(self.box1, 0, wx.ALIGN_LEFT | wx.ALL, 5) |
601 | + |
602 | + self.help_text = wx.StaticText(self) |
603 | + self.sizer.Add(self.help_text, 1, wx.EXPAND, 5) |
604 | + |
605 | + self.SetSizer(self.sizer) |
606 | + self.sizer.Fit(self) |
607 | + self.Move((50, 50)) |
608 | + |
609 | + def get_human_os_name(self, item): |
610 | + """Given an OS name from the database, return a human name (either |
611 | + translated from the YAML settings, or just prettified) and if it is a |
612 | + LEB OS or not""" |
613 | + |
614 | + item = re.sub("linaro-", "", item) # Remove any linaro- decoration |
615 | + |
616 | + human_name = item |
617 | + |
618 | + if item in self.settings['UI']['descriptions']: |
619 | + human_name = self.settings['UI']['descriptions'][item] |
620 | + else: |
621 | + # Make human_name look nicer... |
622 | + human_name = string.capwords(item) |
623 | + |
624 | + leb_search = re.search("^LEB:\s*(.*)$", human_name) |
625 | + |
626 | + if leb_search: |
627 | + return leb_search.group(1), True |
628 | + |
629 | + return human_name, False |
630 | + |
631 | + def fill_os_list(self): |
632 | + """Filter the list of OS's from the config file based on the users |
633 | + preferences so all choices in the list are valid (i.e. their hardware |
634 | + is supported for the build they have chosen).""" |
635 | + |
636 | + # select unique image from snapshot_binaries/release_binaries to |
637 | + # generate list |
638 | + os_list = None |
639 | + if self.settings['release_or_snapshot'] == "release": |
640 | + os_list = self.db.get_os_list_from('release_binaries') |
641 | + else: |
642 | + os_list = self.db.get_os_list_from('snapshot_binaries') |
643 | + |
644 | + self.cb_image.Clear() |
645 | + |
646 | + printed_tag = None |
647 | + last_name = None |
648 | + current_image_setting_valid = False |
649 | + |
650 | + for state in ["LEB", "other"]: |
651 | + for item in os_list: |
652 | + if item == "old": |
653 | + # Old is a directory that sometimes hangs around, |
654 | + # but isn't one we want to display |
655 | + continue |
656 | + |
657 | + # Save the original, untouched image name for use later. |
658 | + # We give it a more human name for display |
659 | + original = item |
660 | + item = re.sub("linaro-", "", item) |
661 | + |
662 | + os_hardware_combo_available = ( |
663 | + self.db.image_hardware_combo_available( |
664 | + self.settings['release_or_snapshot'], |
665 | + original, |
666 | + self.settings['compatable_hwpacks'])) |
667 | + |
668 | + if os_hardware_combo_available: |
669 | + human_name, is_LEB = self.get_human_os_name(item) |
670 | + |
671 | + if item == self.settings['image']: |
672 | + current_image_setting_valid = True |
673 | + |
674 | + if state == "LEB" and is_LEB: |
675 | + |
676 | + if printed_tag != state: |
677 | + self.cb_image.Append( |
678 | + "- Linaro Supported Releases -") |
679 | + printed_tag = state |
680 | + |
681 | + self.cb_image.Append(human_name, original) |
682 | + |
683 | + if self.settings['image'] == None: |
684 | + self.settings['image'] = original |
685 | + |
686 | + elif state != "LEB" and not is_LEB: |
687 | + if printed_tag != state: |
688 | + self.cb_image.Append( |
689 | + "- Community Supported Releases -") |
690 | + printed_tag = state |
691 | + |
692 | + self.cb_image.Append(human_name, original) |
693 | + |
694 | + last_name = original |
695 | + |
696 | + if( self.settings['image'] != None |
697 | + and current_image_setting_valid == False): |
698 | + # If we have an image setting, but it doesn't match the OS list, we |
699 | + # have switched OS list. It may be that adding/removing "linaro-" |
700 | + # from the name will get a match. |
701 | + |
702 | + if re.search("linaro-", self.settings['image']): |
703 | + test_name = re.sub("linaro-", "", self.settings['image']) |
704 | + else: |
705 | + test_name = "linaro-" + self.settings['image'] |
706 | + |
707 | + if test_name in os_list: |
708 | + # Success! We have translated the name and can retain the |
709 | + # "old setting" |
710 | + self.settings['image'] = test_name |
711 | + current_image_setting_valid = True |
712 | + |
713 | + if( self.settings['image'] == None |
714 | + or current_image_setting_valid == False): |
715 | + # This should only get hit if there are no LEBs available |
716 | + self.settings['image'] = last_name |
717 | + |
718 | + assert self.settings['image'] |
719 | + |
720 | + # Make sure the visible selected value matches the saved setting |
721 | + self.cb_image.SetValue( |
722 | + self.get_human_os_name(self.settings['image'])[0]) |
723 | + |
724 | + #--- Event(s) --- |
725 | + def event_combo_box_os(self, evt): |
726 | + self.settings['image'] = self.cb_image.GetClientData( |
727 | + evt.GetSelection()) |
728 | + |
729 | + if self.settings['image']: # Is None for items that aren't an OS |
730 | + self.wizard.FindWindowById(wx.ID_FORWARD).Enable() |
731 | + image = re.sub("linaro-", "", self.settings['image']) |
732 | + |
733 | + if image + "::long" in self.settings['UI']['descriptions']: |
734 | + self.help_text.SetLabel(self.settings['UI'] |
735 | + ['descriptions'] |
736 | + [image + "::long"]) |
737 | + else: |
738 | + self.help_text.SetLabel("") |
739 | + |
740 | + else: # Have selected help text |
741 | + self.wizard.FindWindowById(wx.ID_FORWARD).Disable() |
742 | + self.help_text.SetLabel("Please select an operating system to run " |
743 | + "on your chosen hardware.") |
744 | + |
745 | + self.help_text.Wrap(self.width - 10) |
746 | + #--- END event(s) --- |
747 | + |
748 | + |
749 | +class LMC_settings(wiz.WizardPageSimple): |
750 | + """Present the user with, intially, the choice of writing the file system |
751 | + they are going to have created to a file, or directly to a device. Ask |
752 | + which file/device to write to. |
753 | + |
754 | + If writing to a device, the user is asked to tick a box saying that they |
755 | + understand that the device they have chosen will be erased. |
756 | + |
757 | + If the user ticks the advanced box, more options are shown.""" |
758 | + |
759 | + def __init__(self, parent, config, db, width): |
760 | + wiz.WizardPageSimple.__init__(self, parent) |
761 | + self.settings = config.settings |
762 | + self.wizard = parent |
763 | + self.sizer = wx.BoxSizer(wx.VERTICAL) |
764 | + self.yes_use_mmc = False |
765 | + self.db = db |
766 | + |
767 | + self.settings['path_selected'] = "" |
768 | + |
769 | + header = wx.StaticText(self, |
770 | + label = "Media Creation Settings\n\n" |
771 | + "Please select if you would like to write the " |
772 | + "file system I am about to create to a memory " |
773 | + "card, or to a file on the local file system.") |
774 | + header.Wrap(width - 10) # -10 because boarder below is 5 pixels wide |
775 | + |
776 | + #--- Build some widgets --- |
777 | + #-- Target file system -- |
778 | + file_systems = ["ext3", "ext4", "btrfs", "ext2"] |
779 | + default_target = file_systems[0] |
780 | + self.settings['rootfs'] = default_target |
781 | + cb_rootfs = wx.ComboBox(self, |
782 | + value = default_target, |
783 | + style = wx.CB_DROPDOWN | wx.CB_READONLY) |
784 | + |
785 | + for item in file_systems: |
786 | + cb_rootfs.Append(item, item.upper()) |
787 | + |
788 | + self.Bind(wx.EVT_COMBOBOX, self.event_combo_box_rootfs, cb_rootfs) |
789 | + |
790 | + #-- Image size spinner |
791 | + self.image_size_spinner = wx.SpinCtrl(self, -1, "") |
792 | + self.Bind(wx.EVT_SPINCTRL, |
793 | + self.event_image_size, |
794 | + self.image_size_spinner) |
795 | + |
796 | + #-- Swap size spinner |
797 | + self.swap_size_spinner = wx.SpinCtrl(self, -1, "") |
798 | + self.Bind(wx.EVT_SPINCTRL, |
799 | + self.event_swap_size, |
800 | + self.swap_size_spinner) |
801 | + |
802 | + #--- Layout --- |
803 | + self.sizer.Add(header, 0, wx.ALIGN_LEFT | wx.ALL, 5) |
804 | + box1 = wx.BoxSizer(wx.VERTICAL) |
805 | + file_dev_grid = wx.FlexGridSizer(0, 2, 0, 0) |
806 | + box1.Add(file_dev_grid, 0, wx.EXPAND) |
807 | + grid1 = wx.FlexGridSizer(0, 2, 0, 0) |
808 | + |
809 | + # self.settings['write_to_file_or_device'] should match the first |
810 | + # button below... |
811 | + self.settings['write_to_file_or_device'] = "file" |
812 | + add_button(self, |
813 | + file_dev_grid, |
814 | + "Write to file", |
815 | + wx.RB_GROUP, |
816 | + self.event_radio_button_select, |
817 | + None, None) |
818 | + |
819 | + add_button(self, |
820 | + file_dev_grid, |
821 | + "Write to device", |
822 | + None, |
823 | + self.event_radio_button_select, |
824 | + None, None) |
825 | + |
826 | + self.help_text_values = {"device": "Please select a device to write " |
827 | + "the file system to:", |
828 | + "file": "Please select a file to write the " |
829 | + "file system to:"} |
830 | + |
831 | + self.help_text = wx.StaticText( |
832 | + self, |
833 | + label = |
834 | + self.help_text_values[ |
835 | + self.settings['write_to_file_or_device']]) |
836 | + self.help_text.Wrap(width - 10) |
837 | + |
838 | + #-- File/dev picker -- |
839 | + file_browse_button = wx.Button(self, -1, "Browse") |
840 | + file_browse_grid = wx.FlexGridSizer(0, 2, 0, 0) |
841 | + self.file_path_and_name = wx.TextCtrl(self, -1, "", size=(300, -1)) |
842 | + |
843 | + file_browse_grid.Add(self.file_path_and_name, 0, wx.EXPAND) |
844 | + file_browse_grid.Add(file_browse_button, 0, wx.EXPAND) |
845 | + |
846 | + self.Bind(wx.EVT_BUTTON, |
847 | + self.event_open_file_control, |
848 | + file_browse_button) |
849 | + |
850 | + self.Bind(wx.EVT_TEXT, |
851 | + self.event_file_path_and_name, |
852 | + self.file_path_and_name) |
853 | + |
854 | + box1.Add(self.help_text, 0, wx.ALIGN_LEFT | wx.ALL, 5) |
855 | + |
856 | + box1.Add(file_browse_grid, 0, wx.EXPAND) |
857 | + |
858 | + cb1 = wx.CheckBox(self, -1, "Show advanced options") |
859 | + self.Bind(wx.EVT_CHECKBOX, self.event_show_advanced_options, cb1) |
860 | + box1.Add(cb1) |
861 | + |
862 | + #-- Combo boxes for hardware and image selection -- |
863 | + optional_settings_box_title = wx.StaticBox( |
864 | + self, |
865 | + label = " Optional Settings ") |
866 | + |
867 | + self.optional_settings_box = wx.StaticBoxSizer( |
868 | + optional_settings_box_title, |
869 | + wx.VERTICAL) |
870 | + |
871 | + self.box2 = wx.BoxSizer(wx.VERTICAL) |
872 | + |
873 | + self.box2.AddWindow(self.optional_settings_box, |
874 | + 0, |
875 | + border=2, |
876 | + flag=wx.ALL | wx.EXPAND) |
877 | + |
878 | + grid1.Add(cb_rootfs, 0, wx.ALIGN_LEFT | wx.LEFT | wx.RIGHT | wx.TOP, 5) |
879 | + |
880 | + grid1.Add(wx.StaticText(self, |
881 | + label = "The root file system of the image"), |
882 | + 0, |
883 | + wx.ALIGN_LEFT | wx.LEFT | wx.RIGHT | wx.TOP, |
884 | + 5) |
885 | + |
886 | + # We want to sub-devide the cell, to add another grid sizer... |
887 | + file_size_grid = wx.FlexGridSizer(0, 2, 0, 0) |
888 | + |
889 | + grid1.Add(file_size_grid, |
890 | + 0, |
891 | + wx.ALIGN_LEFT | wx.LEFT | wx.RIGHT | wx.TOP) |
892 | + |
893 | + # Add a spinner that allows us to type/click a numerical value (defined above) |
894 | + file_size_grid.Add(self.image_size_spinner, |
895 | + 0, |
896 | + wx.ALIGN_LEFT | wx.LEFT | wx.RIGHT | wx.TOP, |
897 | + 5) |
898 | + |
899 | + # Add a choice of MB or GB for size input |
900 | + units = ["GB", "MB"] |
901 | + self.size_unit = units[0] # Set the default unit |
902 | + unit_choice = wx.Choice(self, -1, (100, 50), choices = units) |
903 | + self.Bind(wx.EVT_CHOICE, self.event_chose_unit, unit_choice) |
904 | + file_size_grid.Add(unit_choice, 0, wx.ALIGN_RIGHT | wx.TOP, 5) |
905 | + |
906 | + # Back out of the extra grid, add some help text |
907 | + grid1.Add(wx.StaticText( |
908 | + self, |
909 | + label = "Writing to file only: Image file size"), |
910 | + 0, |
911 | + wx.ALIGN_LEFT | wx.LEFT | wx.RIGHT | wx.TOP, |
912 | + 5) |
913 | + |
914 | + # The swap size (MB only) |
915 | + grid1.Add(self.swap_size_spinner, |
916 | + 0, |
917 | + wx.ALIGN_LEFT | wx.LEFT | wx.RIGHT | wx.TOP, |
918 | + 5) |
919 | + |
920 | + grid1.Add(wx.StaticText(self, label = "Swap file size in MB"), |
921 | + 0, |
922 | + wx.ALIGN_LEFT | wx.LEFT | wx.RIGHT | wx.TOP, |
923 | + 5) |
924 | + |
925 | + self.cb_hwpacks = wx.ComboBox( |
926 | + self, |
927 | + value = self.settings['compatable_hwpacks'][0], |
928 | + style = wx.CB_DROPDOWN | wx.CB_READONLY) |
929 | + |
930 | + self.Bind(wx.EVT_COMBOBOX, |
931 | + self.event_combo_box_hwpack, |
932 | + self.cb_hwpacks) |
933 | + |
934 | + grid1.Add(self.cb_hwpacks, |
935 | + 0, |
936 | + wx.ALIGN_LEFT | wx.LEFT | wx.RIGHT | wx.TOP, |
937 | + 5) |
938 | + |
939 | + grid1.Add(wx.StaticText(self, label = "Compatible hardware packs"), |
940 | + 0, |
941 | + wx.ALIGN_LEFT | wx.LEFT | wx.RIGHT | wx.TOP, |
942 | + 5) |
943 | + |
944 | + self.optional_settings_box.Add(grid1, 0, wx.ALIGN_LEFT | wx.ALL, 5) |
945 | + |
946 | + confirm_mmc_usage_title = wx.StaticBox(self, label = " Are you sure? ") |
947 | + |
948 | + self.confirm_mmc_usage_box = wx.StaticBoxSizer(confirm_mmc_usage_title, |
949 | + wx.VERTICAL) |
950 | + cb2 = wx.CheckBox( |
951 | + self, |
952 | + -1, |
953 | + "Yes, erase and use the device I have selected above.") |
954 | + |
955 | + self.Bind(wx.EVT_CHECKBOX, self.event_use_mmc_tickbox, cb2) |
956 | + self.confirm_mmc_usage_box.Add(cb2) |
957 | + |
958 | + self.box3 = wx.BoxSizer(wx.VERTICAL) |
959 | + self.box3.AddWindow(self.confirm_mmc_usage_box, |
960 | + 0, |
961 | + border=2, |
962 | + flag=wx.ALL | wx.EXPAND) |
963 | + |
964 | + self.sizer.Add(box1, 0, wx.ALIGN_LEFT | wx.ALL, 0) |
965 | + self.sizer.Add(self.box2, 0, wx.ALIGN_LEFT | wx.ALL, 0) |
966 | + self.sizer.Add(self.box3, 0, wx.ALIGN_LEFT | wx.ALL, 0) |
967 | + self.SetSizer(self.sizer) |
968 | + self.sizer.Fit(self) |
969 | + self.Move((50, 50)) |
970 | + |
971 | + def on_activate(self): |
972 | + self.update_forward_active_and_mmc_confirm_box_visible() |
973 | + self.set_hwpacks_for_hardware() |
974 | + |
975 | + def set_hwpacks_for_hardware(self): |
976 | + self.cb_hwpacks.Clear() |
977 | + |
978 | + if self.settings['release_or_snapshot'] == "snapshot": |
979 | + self.settings['build'] = self.settings['snapshot_build'] |
980 | + |
981 | + date_and_build = self.settings['build'].split(":") |
982 | + |
983 | + compatable_hwpacks = ( |
984 | + self.db.get_available_hwpacks_for_hardware_snapshot_build( |
985 | + self.settings['compatable_hwpacks'], |
986 | + self.settings['platform'], |
987 | + date_and_build[0], |
988 | + date_and_build[1])) |
989 | + else: |
990 | + self.settings['build'] = self.settings['release_build'] |
991 | + compatable_hwpacks = ( |
992 | + self.db.get_available_hwpacks_for_hardware_build_plaform( |
993 | + self.settings['compatable_hwpacks'], |
994 | + self.settings['platform'], |
995 | + self.settings['build'])) |
996 | + |
997 | + for hwpack in compatable_hwpacks: |
998 | + self.cb_hwpacks.Append(hwpack) |
999 | + |
1000 | + self.cb_hwpacks.SetStringSelection(compatable_hwpacks[0]) |
1001 | + self.settings['hwpack'] = compatable_hwpacks[0] |
1002 | + |
1003 | + def update_forward_active_and_mmc_confirm_box_visible(self): |
1004 | + if( self.settings['path_selected'] |
1005 | + and self.settings['path_selected'] != ""): |
1006 | + |
1007 | + if ( self.settings['write_to_file_or_device'] == "file" |
1008 | + or self.settings['write_to_file_or_device'] == "device" |
1009 | + and self.yes_use_mmc): |
1010 | + self.wizard.FindWindowById(wx.ID_FORWARD).Enable() |
1011 | + else: |
1012 | + self.wizard.FindWindowById(wx.ID_FORWARD).Disable() |
1013 | + else: |
1014 | + self.wizard.FindWindowById(wx.ID_FORWARD).Disable() |
1015 | + |
1016 | + if self.settings['write_to_file_or_device'] == "device": |
1017 | + self.box3.Show(self.confirm_mmc_usage_box, True) |
1018 | + else: |
1019 | + self.box3.Hide(self.confirm_mmc_usage_box, True) |
1020 | + |
1021 | + # --- Event Handlers --- |
1022 | + def event_open_file_control(self, event): |
1023 | + if self.settings['write_to_file_or_device'] == "file": |
1024 | + |
1025 | + dlg = wx.FileDialog(self, |
1026 | + message="Save file as ...", |
1027 | + defaultDir=os.getcwd(), |
1028 | + defaultFile="", |
1029 | + style=wx.SAVE) |
1030 | + |
1031 | + elif self.settings['write_to_file_or_device'] == "device": |
1032 | + dlg = wx.FileDialog(self, |
1033 | + message="Choose a device", |
1034 | + defaultDir=os.getcwd(), |
1035 | + defaultFile="", |
1036 | + style=wx.OPEN | wx.CHANGE_DIR) |
1037 | + |
1038 | + if dlg.ShowModal() == wx.ID_OK: |
1039 | + self.settings['path_selected'] = dlg.GetPaths()[0] |
1040 | + self.file_path_and_name.SetValue(self.settings['path_selected']) |
1041 | + |
1042 | + dlg.Destroy() |
1043 | + self.update_forward_active_and_mmc_confirm_box_visible() |
1044 | + |
1045 | + def event_file_path_and_name(self, event): |
1046 | + self.settings['path_selected'] = event.GetString() |
1047 | + self.update_forward_active_and_mmc_confirm_box_visible() |
1048 | + |
1049 | + def event_combo_box_hwpack(self, event): |
1050 | + self.settings['hwpack'] = event.GetString().encode('ascii') |
1051 | + |
1052 | + def event_combo_box_rootfs(self, evt): |
1053 | + self.settings['rootfs'] = evt.GetString().encode('ascii').lower() |
1054 | + |
1055 | + def event_radio_button_select(self, event): |
1056 | + """Search the label of the button that has been selected to work out |
1057 | + what we are writing to.""" |
1058 | + setting_search = re.search( |
1059 | + "write to (\w+)", |
1060 | + event |
1061 | + .GetEventObject() |
1062 | + .GetLabel() |
1063 | + .encode('ascii') |
1064 | + .lower()) |
1065 | + |
1066 | + assert setting_search |
1067 | + |
1068 | + self.settings['write_to_file_or_device'] = setting_search.group(1) |
1069 | + |
1070 | + self.help_text.SetLabel( |
1071 | + self.help_text_values[self.settings['write_to_file_or_device']]) |
1072 | + |
1073 | + self.update_forward_active_and_mmc_confirm_box_visible() |
1074 | + |
1075 | + def event_show_advanced_options(self, event): |
1076 | + if event.IsChecked(): |
1077 | + self.box2.Show(self.optional_settings_box, True) |
1078 | + else: |
1079 | + self.box2.Hide(self.optional_settings_box, True) |
1080 | + |
1081 | + def event_pick_file_path(self, evt): |
1082 | + self.settings['path_selected'] = os.path.abspath(evt.GetPath()) |
1083 | + self.update_forward_active_and_mmc_confirm_box_visible() |
1084 | + |
1085 | + def update_image_size_setting(self): |
1086 | + if(self.image_size_spinner.GetValue() > 0): |
1087 | + self.settings['image_size'] = (str(self.image_size_spinner |
1088 | + .GetValue()) |
1089 | + + self.size_unit[0]) |
1090 | + else: |
1091 | + self.settings['image_size'] = None |
1092 | + |
1093 | + def event_image_size(self, event): |
1094 | + self.update_image_size_setting() |
1095 | + |
1096 | + def event_chose_unit(self, event): |
1097 | + self.size_unit = event.GetString() |
1098 | + self.update_image_size_setting() |
1099 | + |
1100 | + def event_swap_size(self, event): |
1101 | + self.settings['swap_file'] = str(self.image_size_spinner.GetValue()) |
1102 | + |
1103 | + def event_use_mmc_tickbox(self, event): |
1104 | + self.yes_use_mmc = event.IsChecked() |
1105 | + self.update_forward_active_and_mmc_confirm_box_visible() |
1106 | + |
1107 | + |
1108 | +class RunLMC(wiz.WizardPageSimple): |
1109 | + """Present the user with some information about their choices and a button |
1110 | + to start linaro-media-create. The linaro-media-create process is started in |
1111 | + a new thread and important events are communicated back to the UI through a |
1112 | + queue.""" |
1113 | + |
1114 | + def __init__(self, parent, config, db, width): |
1115 | + wiz.WizardPageSimple.__init__(self, parent) |
1116 | + self.settings = config.settings |
1117 | + self.sizer = wx.BoxSizer(wx.VERTICAL) |
1118 | + self.db = db |
1119 | + self.width = width |
1120 | + self.wizard = parent |
1121 | + |
1122 | + header = wx.StaticText(self, label = """Installing...""") |
1123 | + header.Wrap(width - 10) # -10 because boarder below is 5 pixels wide |
1124 | + |
1125 | + self.sizer.Add(header) |
1126 | + self.box1 = wx.BoxSizer(wx.VERTICAL) |
1127 | + |
1128 | + # We expect to print 4 lines of information, reserve space using blank |
1129 | + # lines. |
1130 | + self.settings_summary_text = wx.StaticText(self, label = "\n\n\n\n") |
1131 | + self.settings_summary_text.Wrap(width - 10) |
1132 | + |
1133 | + self.box1.Add(self.settings_summary_text, 0, wx.ALIGN_LEFT | wx.ALL, 5) |
1134 | + |
1135 | + self.start_button = wx.Button(self, 10, "Start", (20, 20)) |
1136 | + self.Bind(wx.EVT_BUTTON, self.start_lmc, self.start_button) |
1137 | + |
1138 | + self.start_button.SetToolTipString("Start creating an image, using the" |
1139 | + "above settings.") |
1140 | + |
1141 | + self.start_button.SetSize(self.start_button.GetBestSize()) |
1142 | + self.box1.Add(self.start_button, 0, wx.ALIGN_LEFT | wx.ALL, 5) |
1143 | + |
1144 | + self.status_grid = wx.FlexGridSizer(0, 2, 0, 0) |
1145 | + |
1146 | + self.status_grid.Add(wx.StaticText(self, label="Downloading files"), |
1147 | + 0, |
1148 | + wx.ALIGN_LEFT | wx.LEFT | wx.RIGHT | wx.TOP, |
1149 | + 5) |
1150 | + |
1151 | + self.downloading_files_status = wx.StaticText(self, label="") |
1152 | + self.status_grid.Add(self.downloading_files_status, |
1153 | + 0, |
1154 | + wx.ALIGN_LEFT | wx.LEFT | wx.RIGHT | wx.TOP, |
1155 | + 5) |
1156 | + |
1157 | + self.status_grid.Add(wx.StaticText(self, label="Unpacking downloads"), |
1158 | + 0, |
1159 | + wx.ALIGN_LEFT | wx.LEFT | wx.RIGHT | wx.TOP, |
1160 | + 5) |
1161 | + |
1162 | + self.unpacking_files_status = wx.StaticText(self, label="") |
1163 | + |
1164 | + self.status_grid.Add(self.unpacking_files_status, |
1165 | + 0, |
1166 | + wx.ALIGN_LEFT | wx.LEFT | wx.RIGHT | wx.TOP, |
1167 | + 5) |
1168 | + |
1169 | + self.status_grid.Add(wx.StaticText(self, label="Installing packages"), |
1170 | + 0, |
1171 | + wx.ALIGN_LEFT | wx.LEFT | wx.RIGHT | wx.TOP, |
1172 | + 5) |
1173 | + |
1174 | + self.installing_packages_status = wx.StaticText(self, label="") |
1175 | + |
1176 | + self.status_grid.Add(self.installing_packages_status, |
1177 | + 0, |
1178 | + wx.ALIGN_LEFT | wx.LEFT | wx.RIGHT | wx.TOP, |
1179 | + 5) |
1180 | + |
1181 | + self.status_grid.Add(wx.StaticText(self, label="Create file system"), |
1182 | + 0, |
1183 | + wx.ALIGN_LEFT | wx.LEFT | wx.RIGHT | wx.TOP, |
1184 | + 5) |
1185 | + |
1186 | + self.create_file_system_status = wx.StaticText(self, label="") |
1187 | + |
1188 | + self.status_grid.Add(self.create_file_system_status, |
1189 | + 0, |
1190 | + wx.ALIGN_LEFT | wx.LEFT | wx.RIGHT | wx.TOP, |
1191 | + 5) |
1192 | + |
1193 | + self.status_grid.Add(wx.StaticText(self, label="Populate file system"), |
1194 | + 0, |
1195 | + wx.ALIGN_LEFT | wx.LEFT | wx.RIGHT | wx.TOP, |
1196 | + 5) |
1197 | + |
1198 | + self.populate_file_system_status = wx.StaticText(self, label="") |
1199 | + |
1200 | + self.status_grid.Add(self.populate_file_system_status, |
1201 | + 0, |
1202 | + wx.ALIGN_LEFT | wx.LEFT | wx.RIGHT | wx.TOP, |
1203 | + 5) |
1204 | + |
1205 | + self.sizer.Add(self.box1, 0, wx.ALIGN_LEFT | wx.ALL, 5) |
1206 | + self.sizer.Add(self.status_grid, 0, wx.ALIGN_LEFT | wx.ALL, 5) |
1207 | + self.SetSizerAndFit(self.sizer) |
1208 | + self.sizer.Fit(self) |
1209 | + self.Move((50, 50)) |
1210 | + |
1211 | + def on_activate(self): |
1212 | + """Called just before the page is displayed to update the text based on |
1213 | + the users preferences.""" |
1214 | + |
1215 | + # The build is stored in different forms depending on if we are using a |
1216 | + # release or snapshot but from here on in it is a common value |
1217 | + if self.settings['release_or_snapshot'] == "snapshot": |
1218 | + self.settings['build'] = self.settings['snapshot_build'] |
1219 | + else: |
1220 | + self.settings['build'] = self.settings['release_build'] |
1221 | + |
1222 | + settings_summary = ("Press start to create an image with the " |
1223 | + "following settings:\n") |
1224 | + settings_summary += "Operating System: " + self.settings['image'] + "\n" |
1225 | + settings_summary += "Hardware: " + self.settings['hardware'] + "\n" |
1226 | + |
1227 | + # Assumption is that a file may be in a long path, we don't know how |
1228 | + # big the font is and we don't want to allow the path to run off the |
1229 | + # end of the line, so if a file is chosen, just show the file name. |
1230 | + # Devices are (probably) /dev/some_short_name and the user really needs |
1231 | + # to check them, so we show the whole thing. |
1232 | + path = self.settings['path_selected'] |
1233 | + if self.settings['write_to_file_or_device'] == "file": |
1234 | + path = self.settings['path_selected'].split(os.sep)[-1] |
1235 | + |
1236 | + settings_summary += ( "Writing image to " |
1237 | + + self.settings['write_to_file_or_device'] |
1238 | + + " " |
1239 | + + path) |
1240 | + |
1241 | + self.settings_summary_text.SetLabel(settings_summary) |
1242 | + self.settings_summary_text.Wrap(self.width - 10) |
1243 | + |
1244 | + def start_lmc(self, event): |
1245 | + """Start a thread that runs linaro-media-create and a timer, which |
1246 | + checks for UI updates every 100ms""" |
1247 | + |
1248 | + if self.settings['write_to_file_or_device'] == "file": |
1249 | + self.settings['image_file'] = self.settings['path_selected'] |
1250 | + elif self.settings['write_to_file_or_device'] == "device": |
1251 | + self.settings['mmc'] = self.settings['path_selected'] |
1252 | + else: |
1253 | + assert False, ("self.config.settings['write_to_file_or_device'] " |
1254 | + "was an unexpected value" |
1255 | + + self.settings['write_to_file_or_device']) |
1256 | + |
1257 | + image_url, hwpack_url = self.db.get_image_and_hwpack_urls(self.settings) |
1258 | + |
1259 | + # Currently the UI is blocked when LMC is running, so grey out the |
1260 | + # buttons to indicate to the user that they won't work! |
1261 | + self.wizard.FindWindowById(wx.ID_BACKWARD).Disable() |
1262 | + self.wizard.FindWindowById(wx.ID_CANCEL).Disable() |
1263 | + |
1264 | + if(image_url and hwpack_url): |
1265 | + |
1266 | + print image_url |
1267 | + print hwpack_url |
1268 | + |
1269 | + self.file_handler = FetchImage.FileHandler() |
1270 | + |
1271 | + tools_dir = os.path.dirname(__file__) |
1272 | + if tools_dir == '': |
1273 | + tools_dir = None |
1274 | + |
1275 | + self.file_handler.create_media(image_url, |
1276 | + hwpack_url, |
1277 | + self.settings, |
1278 | + tools_dir, |
1279 | + True, |
1280 | + self) |
1281 | + |
1282 | + self.timer = wx.Timer(self) |
1283 | + self.Bind(wx.EVT_TIMER, self.timer_ping, self.timer) |
1284 | + self.timer.Start(milliseconds=100, oneShot=True) |
1285 | + |
1286 | + self.start_button.Disable() |
1287 | + self.event_queue = Queue.Queue() |
1288 | + self.file_handler.start_lmc_gui_thread(self.event_queue) |
1289 | + else: |
1290 | + print >> sys.stderr, ("Unable to find files that match the" |
1291 | + "parameters specified") |
1292 | + |
1293 | + def timer_ping(self, event): |
1294 | + """During start_lmc a timer is started to poll for events from |
1295 | + linaro-media-create every 100ms. This is the function which is called |
1296 | + to do that polling.""" |
1297 | + |
1298 | + if self.event_queue.empty() == False: |
1299 | + event = self.event_queue.get() |
1300 | + |
1301 | + if event[0] == "start": |
1302 | + self.event_start(event[1]) |
1303 | + self.timer.Start(milliseconds=100, oneShot=True) |
1304 | + |
1305 | + elif event[0] == "end": |
1306 | + self.event_end(event[1]) |
1307 | + self.timer.Start(milliseconds=100, oneShot=True) |
1308 | + |
1309 | + elif event == "terminate": |
1310 | + # Process complete. Enable next button. |
1311 | + self.wizard.FindWindowById(wx.ID_FORWARD).Enable() |
1312 | + self.populate_file_system_status.SetLabel("Done") |
1313 | + |
1314 | + else: |
1315 | + print >> sys.stderr, "timer_ping: Unhandled event", event |
1316 | + |
1317 | + else: |
1318 | + self.timer.Start(milliseconds=100, oneShot=True) |
1319 | + |
1320 | + def unsigned_packages_query(self, package_list): |
1321 | + message = ('In order to continue, I need to install some unsigned' |
1322 | + 'packages into the image. Is this OK? The packages are:' |
1323 | + '\n\n' + package_list) |
1324 | + |
1325 | + dlg = wx.MessageDialog(self, |
1326 | + message, |
1327 | + 'Install Unsigned Packages Into Image?', |
1328 | + wx.YES_NO | wx.NO_DEFAULT) |
1329 | + |
1330 | + choice = dlg.ShowModal() |
1331 | + dlg.Destroy() |
1332 | + |
1333 | + return choice == wx.ID_YES |
1334 | + |
1335 | + #--- Event(s) --- |
1336 | + def event_start(self, event): |
1337 | + if event == "download OS": |
1338 | + self.downloading_files_status.SetLabel("Downloading OS") |
1339 | + elif event == "download hwpack": |
1340 | + self.downloading_files_status.SetLabel("Downloading Hardware Pack") |
1341 | + elif event == "unpack": |
1342 | + self.unpacking_files_status.SetLabel("Running") |
1343 | + elif event == "installing packages": |
1344 | + self.installing_packages_status.SetLabel("Running") |
1345 | + |
1346 | + elif re.search('^unverified_packages:', event): |
1347 | + # Get rid of event ID and whitespace invariance |
1348 | + packages = " ".join(event.split()[1:]) |
1349 | + install_unsigned_packages = self.unsigned_packages_query(packages) |
1350 | + |
1351 | + if install_unsigned_packages == False: |
1352 | + self.file_handler.kill_create_media() |
1353 | + sys.exit(1) |
1354 | + else: |
1355 | + self.file_handler.send_to_create_process("y") |
1356 | + |
1357 | + elif event == "create file system": |
1358 | + self.create_file_system_status.SetLabel("Running") |
1359 | + elif event == "populate file system": |
1360 | + self.populate_file_system_status.SetLabel("Running") |
1361 | + else: |
1362 | + print "Unhandled start event:", event |
1363 | + |
1364 | + def event_end(self, event): |
1365 | + if event == "download OS": |
1366 | + self.downloading_files_status.SetLabel("Done (1/2)") |
1367 | + elif event == "download hwpack": |
1368 | + self.downloading_files_status.SetLabel("Done") |
1369 | + elif event == "unpack": |
1370 | + self.unpacking_files_status.SetLabel("Done") |
1371 | + elif event == "installing packages": |
1372 | + self.installing_packages_status.SetLabel("Done") |
1373 | + elif event == "create file system": |
1374 | + self.create_file_system_status.SetLabel("Done") |
1375 | + elif event == "populate file system": |
1376 | + self.populate_file_system_status.SetLabel("Done") |
1377 | + else: |
1378 | + print "Unhhandled end event:", event |
1379 | + |
1380 | + def event_combo_box_release(self, evt): |
1381 | + pass |
1382 | + |
1383 | + def event_combo_box_build(self, evt): |
1384 | + pass |
1385 | + #--- END event(s) --- |
1386 | + |
1387 | + |
1388 | +class TestDriveWizard(wx.wizard.Wizard): |
1389 | + def __init__(self, title): |
1390 | + wx.wizard.Wizard.__init__(self, None, -1, title, wx.NullBitmap) |
1391 | + self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGING, self.on_page_changing) |
1392 | + self.done_startup = False |
1393 | + |
1394 | + def on_page_changing(self, evt): |
1395 | + 'Executed before the page changes.' |
1396 | + |
1397 | + if self.done_startup == False: |
1398 | + self.pages['lmc_settings'].box2.Hide( |
1399 | + self.pages['lmc_settings'].optional_settings_box, |
1400 | + True) |
1401 | + |
1402 | + self.pages['lmc_settings'].box3.Hide( |
1403 | + self.pages['lmc_settings'].confirm_mmc_usage_box, |
1404 | + True) |
1405 | + |
1406 | + self.done_startup = True |
1407 | + |
1408 | + page = evt.GetPage() |
1409 | + |
1410 | + if evt.GetDirection(): # If going forwards... |
1411 | + # Always enable back button if going forwards |
1412 | + self.wizard.FindWindowById(wx.ID_BACKWARD).Enable() |
1413 | + |
1414 | + # If going from a select snapshot or select release page, record |
1415 | + # which we were on so the back button of the next page works |
1416 | + if(self.config.settings['release_or_snapshot'] == "release"): |
1417 | + self.pages['select_os'].SetNext(self.pages['select_release']) |
1418 | + self.pages['select_release'].SetPrev(self.pages['select_os']) |
1419 | + |
1420 | + self.pages['select_release'].SetNext(self.pages['lmc_settings']) |
1421 | + self.pages['lmc_settings'].SetPrev(self.pages['select_release']) |
1422 | + else: |
1423 | + self.pages['select_os'].SetNext(self.pages['select_snapshot']) |
1424 | + self.pages['select_snapshot'].SetPrev(self.pages['select_os']) |
1425 | + |
1426 | + if(page == self.pages['select_os']): |
1427 | + self.pages['select_snapshot'].fill_build_combo_box_for_date( |
1428 | + self.config.settings['build_date']) |
1429 | + |
1430 | + self.pages['select_snapshot'].SetNext(self.pages['lmc_settings']) |
1431 | + self.pages['lmc_settings'].SetPrev(self.pages['select_snapshot']) |
1432 | + |
1433 | + if page == self.pages['hardware_details']: |
1434 | + self.pages['select_os'].fill_os_list() |
1435 | + |
1436 | + if page == self.pages['release_or_snapshot']: |
1437 | + self.pages['hardware_details'].on_page_changing() |
1438 | + |
1439 | + # If about to move into the release selection, make sure the list |
1440 | + # is populated only with releases that are valid with our current |
1441 | + # selection |
1442 | + if( page == self.pages['select_os'] |
1443 | + and self.config.settings['release_or_snapshot'] == "release"): |
1444 | + self.pages['select_release'].update_release_and_build_boxes() |
1445 | + |
1446 | + if page == self.pages['select_snapshot']: |
1447 | + # Execute when exiting page |
1448 | + self.pages['select_snapshot'].update_platform() |
1449 | + |
1450 | + if( page == self.pages['select_snapshot'] |
1451 | + or page == self.pages['select_release']): |
1452 | + self.pages['lmc_settings'].on_activate() |
1453 | + |
1454 | + if page == self.pages['lmc_settings']: |
1455 | + # Forward stays disabled until LMC has finished running |
1456 | + self.wizard.FindWindowById(wx.ID_FORWARD).Disable() |
1457 | + self.pages['run_lmc'].on_activate() |
1458 | + |
1459 | + else: # Always enable the forward button if reversing into a page |
1460 | + self.wizard.FindWindowById(wx.ID_FORWARD).Enable() |
1461 | + |
1462 | + def go(self, first_page): |
1463 | + file_handler = FetchImage.FileHandler() |
1464 | + self.config = FetchImage.FetchImageConfig() |
1465 | + self.config.settings["force_download"] = False |
1466 | + self.config.settings['compatable_hwpacks'] = ['foo'] |
1467 | + |
1468 | + # If the settings file and server index need updating, grab them |
1469 | + file_handler.update_files_from_server(show_wx_progress = True) |
1470 | + |
1471 | + # Load settings YAML, which defines the parameters we ask for and |
1472 | + # acceptable responses from the user |
1473 | + self.config.read_config(file_handler.settings_file) |
1474 | + |
1475 | + # Using the config we have, look up URLs to download data from in |
1476 | + # the server index |
1477 | + db = FetchImage.DB(file_handler.index_file) |
1478 | + |
1479 | + # Create the wizard and the pages |
1480 | + self.wizard = wiz.Wizard(self, -1, "Linaro Media Builder") |
1481 | + |
1482 | + self.pages = {} |
1483 | + self.pages['release_or_snapshot'] = ReleaseOrSnapshotPage(self.wizard, |
1484 | + self.config) |
1485 | + self.wizard.FitToPage(self.pages['release_or_snapshot']) |
1486 | + (width, height) = self.wizard.GetSize() |
1487 | + |
1488 | + self.pages['hardware_details'] = AboutMyHardwarePage(self.wizard, |
1489 | + self.config, |
1490 | + db, |
1491 | + width) |
1492 | + |
1493 | + self.pages['select_release'] = SelectStableRelease(self.wizard, |
1494 | + self.config, |
1495 | + db, |
1496 | + width) |
1497 | + |
1498 | + self.pages['select_snapshot'] = SelectSnapshot(self.wizard, |
1499 | + self.config, |
1500 | + db, |
1501 | + width) |
1502 | + |
1503 | + self.pages['select_os'] = SelectOS(self.wizard, |
1504 | + self.config, |
1505 | + db, |
1506 | + width) |
1507 | + |
1508 | + self.pages['lmc_settings'] = LMC_settings(self.wizard, |
1509 | + self.config, |
1510 | + db, |
1511 | + width) |
1512 | + |
1513 | + self.pages['run_lmc'] = RunLMC(self.wizard, |
1514 | + self.config, |
1515 | + db, |
1516 | + width) |
1517 | + |
1518 | + self.pages['release_or_snapshot'].SetNext( |
1519 | + self.pages['hardware_details']) |
1520 | + |
1521 | + self.pages['hardware_details'].SetPrev( |
1522 | + self.pages['release_or_snapshot']) |
1523 | + |
1524 | + self.pages['hardware_details'].SetNext(self.pages['select_os']) |
1525 | + self.pages['select_os'].SetPrev(self.pages['hardware_details']) |
1526 | + # Select OS goes to select build, which is customised for |
1527 | + # releases or snapshots |
1528 | + self.pages['lmc_settings'].SetNext(self.pages['run_lmc']) |
1529 | + self.pages['run_lmc'].SetPrev(self.pages['lmc_settings']) |
1530 | + |
1531 | + for (name, page) in self.pages.items(): |
1532 | + self.wizard.GetPageAreaSizer().Add(page) |
1533 | + |
1534 | + self.wizard.RunWizard(self.pages['release_or_snapshot']) |
1535 | + |
1536 | + |
1537 | +def run(start_page = None): |
1538 | + """Wrapper around the full wizard. Is encapsulated in its own function to |
1539 | + allow a restart to be performed, as described in __main___, easily""" |
1540 | + app = wx.PySimpleApp() # Start the application |
1541 | + #logging.basicConfig(level=logging.INFO) |
1542 | + w = TestDriveWizard('Simple Wizard') |
1543 | + return w.go(start_page) |
1544 | + |
1545 | + |
1546 | +class TestURLLookupFunctions(unittest.TestCase): |
1547 | + |
1548 | + def setUp(self): |
1549 | + self.file_handler = FetchImage.FileHandler() |
1550 | + self.file_handler.update_files_from_server(show_wx_progress = True) |
1551 | + self.config = FetchImage.FetchImageConfig() |
1552 | + self.config.settings["force_download"] = False |
1553 | + |
1554 | + # Load settings YAML, which defines the parameters we ask for and |
1555 | + # acceptable responses from the user |
1556 | + self.config.read_config(self.file_handler.settings_file) |
1557 | + |
1558 | + # Using the config we have, look up URLs to download data from in the |
1559 | + # server index |
1560 | + self.db = FetchImage.DB(self.file_handler.index_file) |
1561 | + |
1562 | + def test_000_url_lookup_snapshot_builds(self): |
1563 | + self.settings = self.config.settings |
1564 | + self.settings['release_or_snapshot'] = "snapshot" |
1565 | + |
1566 | + #--- Test finding builds near a particular day --- |
1567 | + # This functionality is required for further tests, hence forcing the |
1568 | + # run order by putting numbers in the function name. |
1569 | + today = wx.DateTime() |
1570 | + today.SetToCurrent() |
1571 | + |
1572 | + # -- Don't iterate through platforms for snapshot -- |
1573 | + |
1574 | + # -- Select hardware -- |
1575 | + for self.settings['hardware'] in ( |
1576 | + self.settings['choice']['hardware'].keys()): |
1577 | + |
1578 | + compatable_hwpacks = self.settings['choice']['hwpack'][ |
1579 | + self.settings['hardware']] |
1580 | + |
1581 | + future_date, past_date = self.db.get_next_prev_day_with_builds( |
1582 | + "linaro-alip", |
1583 | + today.FormatISODate().encode('ascii'), |
1584 | + compatable_hwpacks) |
1585 | + |
1586 | + if past_date == None: |
1587 | + # Some hardware packs are not available in the snapshot repo, |
1588 | + # so just skip if they aren't |
1589 | + continue |
1590 | + |
1591 | + builds = self.db.get_binary_builds_on_day_from_db( |
1592 | + "linaro-alip", |
1593 | + past_date, |
1594 | + compatable_hwpacks) |
1595 | + |
1596 | + self.assertTrue(len(builds)) |
1597 | + # If the above assert fails, either the DB is empty, or |
1598 | + # db.get_binary_builds_on_day_from_db failed |
1599 | + |
1600 | + def test_100_url_lookup_snapshots(self): |
1601 | + self.settings = self.config.settings |
1602 | + self.settings['release_or_snapshot'] = "snapshot" |
1603 | + |
1604 | + #--- Test snapshot build lookup --- |
1605 | + # -- Fix a build date -- |
1606 | + # We only need to look up a single snapshot date. Start with today and |
1607 | + # go with the day in the DB, build 0 |
1608 | + today = wx.DateTime() |
1609 | + today.SetToCurrent() |
1610 | + |
1611 | + # -- Don't iterate through platforms for snapshot -- |
1612 | + |
1613 | + # -- Select hardware -- |
1614 | + for self.settings['hardware'] in ( |
1615 | + self.settings['choice']['hardware'].keys()): |
1616 | + |
1617 | + compatable_hwpacks = self.settings['choice']['hwpack'][ |
1618 | + self.settings['hardware']] |
1619 | + |
1620 | + future_date, past_date = self.db.get_next_prev_day_with_builds( |
1621 | + "linaro-alip", |
1622 | + today.FormatISODate().encode('ascii'), |
1623 | + compatable_hwpacks) |
1624 | + |
1625 | + if past_date == None: |
1626 | + # Some hardware packs are not available in the snapshot repo, |
1627 | + # so just skip if they aren't |
1628 | + continue |
1629 | + |
1630 | + builds = self.db.get_binary_builds_on_day_from_db( |
1631 | + "linaro-alip", |
1632 | + past_date, |
1633 | + compatable_hwpacks) |
1634 | + |
1635 | + self.assertTrue(len(builds)) |
1636 | + # The above code is tested in test_000_url_lookup_snapshot_build. |
1637 | + # If the above assert fails, either the DB is empty, or |
1638 | + # db.get_binary_builds_on_day_from_db failed. |
1639 | + |
1640 | + small_date = re.sub('-', '', past_date) |
1641 | + self.settings['build'] = small_date + ":" + "0" |
1642 | + |
1643 | + # -- Iterate through hardware packs -- |
1644 | + for self.settings['hwpack'] in compatable_hwpacks: |
1645 | + |
1646 | + # If hardware pack is available... |
1647 | + if(self.settings['hwpack'] |
1648 | + in self.db.get_hwpacks('snapshot_hwpacks')): |
1649 | + |
1650 | + # -- Iterate through images |
1651 | + os_list = self.db.get_os_list_from('snapshot_binaries') |
1652 | + |
1653 | + for self.settings['image'] in os_list: |
1654 | + if re.search('old', self.settings['image']): |
1655 | + # Directories with old in the name are of no |
1656 | + # interest to us |
1657 | + continue |
1658 | + |
1659 | + # -- Check build which matches these parameters |
1660 | + # (builds that don't match are excluded in UI) -- |
1661 | + if( len(self.db.execute_return_list( |
1662 | + 'select * from snapshot_hwpacks ' |
1663 | + 'where hardware == ? ' |
1664 | + 'and date == ? ' |
1665 | + 'and build == ?', |
1666 | + (self.settings['hwpack'], |
1667 | + small_date, |
1668 | + "0"))) |
1669 | + and len(self.db.execute_return_list( |
1670 | + 'select * from snapshot_binaries ' |
1671 | + 'where image == ? ' |
1672 | + 'and date == ? ' |
1673 | + 'and build == ?', |
1674 | + (self.settings['image'], |
1675 | + small_date, |
1676 | + "0")))): |
1677 | + |
1678 | + # - Run the function under test! - |
1679 | + image_url, hwpack_url = ( |
1680 | + self.db.get_image_and_hwpack_urls(self.settings)) |
1681 | + |
1682 | + self.assertTrue(image_url) |
1683 | + self.assertTrue(hwpack_url) |
1684 | + |
1685 | + def test_101_url_lookup_releases(self): |
1686 | + #--- Test release build lookup --- |
1687 | + self.settings = self.config.settings |
1688 | + self.settings['release_or_snapshot'] = "release" |
1689 | + # -- Select hardware -- |
1690 | + for self.settings['hardware'] in ( |
1691 | + self.settings['choice']['hardware'].keys()): |
1692 | + compatable_hwpacks = ( |
1693 | + self.settings['choice']['hwpack'][self.settings['hardware']]) |
1694 | + |
1695 | + # -- Iterate through hardware packs -- |
1696 | + for self.settings['hwpack'] in compatable_hwpacks: |
1697 | + |
1698 | + # If hardware pack is available... |
1699 | + if(self.settings['hwpack'] |
1700 | + in self.db.get_hwpacks('release_hwpacks')): |
1701 | + |
1702 | + # -- Iterate through images |
1703 | + os_list = self.db.get_os_list_from('release_binaries') |
1704 | + |
1705 | + for self.settings['image'] in os_list: |
1706 | + if re.search('old', self.settings['image']): |
1707 | + # Directories with old in the name are of no |
1708 | + # interest to us |
1709 | + continue |
1710 | + |
1711 | + for platform, ignore in ( |
1712 | + self.settings['choice']['platform'].items()): |
1713 | + self.settings['platform'] = platform |
1714 | + |
1715 | + # -- Iterate through available builds -- |
1716 | + builds = self.db.get_builds( |
1717 | + self.settings['platform'], |
1718 | + self.settings['image']) |
1719 | + |
1720 | + for build in builds: |
1721 | + self.settings['build'] = build |
1722 | + |
1723 | + # -- Check build which matches these parameters |
1724 | + #(builds that don't match are excluded in UI)-- |
1725 | + if( len(self.db.execute_return_list( |
1726 | + 'select * from release_hwpacks ' |
1727 | + 'where platform == ? ' |
1728 | + 'and hardware == ? ' |
1729 | + 'and build == ?', |
1730 | + (self.settings['platform'], |
1731 | + self.settings['hwpack'], |
1732 | + self.settings['build']))) |
1733 | + and len(self.db.execute_return_list( |
1734 | + 'select * from release_binaries ' |
1735 | + 'where platform == ? ' |
1736 | + 'and image == ? ' |
1737 | + 'and build == ?', |
1738 | + (self.settings['platform'], |
1739 | + self.settings['image'], |
1740 | + self.settings['build'])))): |
1741 | + |
1742 | + # - Run the function under test! - |
1743 | + image_url, hwpack_url = ( |
1744 | + self.db.get_image_and_hwpack_urls(self.settings)) |
1745 | + self.assertTrue(image_url) |
1746 | + self.assertTrue(hwpack_url) |
1747 | + |
1748 | +if __name__ == '__main__': |
1749 | + run() |
133 + if(style != None): bind_to, label = label, style = style) bind_to, label = label)
134 + radio_button = wx.RadioButton(
135 + else:
136 + radio_button = wx.RadioButton(
I think that's unnecessary isn't it? style=None is usually the default.
(also we usually avoid spaces around = in method calls)
226 + if "panda" in self.settings[ 'choice' ]['hardware' ].keys( ):
227 + default_hardware = "panda"
Was this just to make your testing easier? I don't think that the choice should
have a default until we're in a position to remember their last answer.
1562 + def test_url_ lookup( self):
Please break up this test in to several tests. These sort of test cases
are a nightmare to debug. Ideally each test method should assert a single
thing.
Thanks,
James