Merge lp:~dooferlad/linaro-image-tools/fetch_image_gui into lp:linaro-image-tools/11.11

Proposed by James Tunnicliffe
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
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.

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.linaro.org and combined using linaro-media-create.

--

Now with split up unit tests!

To post a comment you must log in.
Revision history for this message
James Westby (james-w) wrote : Posted in a previous version of this proposal

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)

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

Revision history for this message
James Westby (james-w) : Posted in a previous version of this proposal
review: Needs Fixing
Revision history for this message
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(bind_to, label = label, style = style)
> 135     +    else:
> 136     +        radio_button = wx.RadioButton(bind_to, label = label)
>
> 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['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.

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_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.

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

Revision history for this message
James Westby (james-w) :
review: Approve
Revision history for this message
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?

Revision history for this message
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://code.launchpad.net/~dooferlad/linaro-image-tools/fetch_image_gui/+merge/66917
> 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

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

Subscribers

People subscribed via source and target branches