Merge lp:~salgado/linaro-image-tools/bug-789093 into lp:~salgado/linaro-image-tools/trunk
- bug-789093
- Merge into trunk
Proposed by
Guilherme Salgado
Status: | Superseded |
---|---|
Proposed branch: | lp:~salgado/linaro-image-tools/bug-789093 |
Merge into: | lp:~salgado/linaro-image-tools/trunk |
Diff against target: |
4734 lines (+3510/-287) 18 files modified
fetch_image.py (+79/-0) fetch_image_ui.py (+1714/-0) linaro-android-media-create (+2/-1) linaro-hwpack-install (+1/-1) linaro-image-indexer (+2/-4) linaro-media-create (+1/-0) linaro_image_tools/FetchImage.py (+174/-152) linaro_image_tools/fetch_image_settings.yaml (+4/-0) linaro_image_tools/hwpack/config.py (+71/-9) linaro_image_tools/hwpack/hardwarepack.py (+16/-2) linaro_image_tools/hwpack/tests/test_config.py (+45/-6) linaro_image_tools/hwpack/tests/test_hardwarepack.py (+27/-0) linaro_image_tools/media_create/android_boards.py (+64/-4) linaro_image_tools/media_create/boards.py (+359/-88) linaro_image_tools/media_create/partitions.py (+21/-9) linaro_image_tools/media_create/rootfs.py (+15/-1) linaro_image_tools/media_create/tests/test_media_create.py (+914/-9) setup.py (+1/-1) |
To merge this branch: | bzr merge lp:~salgado/linaro-image-tools/bug-789093 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Linaro Maintainers | Pending | ||
Review via email: mp+68248@code.launchpad.net |
Commit message
Description of the change
Make sure rootfs.
world-readable
To post a comment you must log in.
- 377. By Guilherme Salgado
-
Make sure rootfs.
move_contents( ) doesn't skip files that are not world-readable
Unmerged revisions
- 377. By Guilherme Salgado
-
Make sure rootfs.
move_contents( ) doesn't skip files that are not world-readable
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === added file 'fetch_image.py' |
2 | --- fetch_image.py 1970-01-01 00:00:00 +0000 |
3 | +++ fetch_image.py 2011-07-18 14:39:34 +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-18 14:39:34 +0000 |
88 | @@ -0,0 +1,1714 @@ |
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 | +import time |
123 | +import datetime |
124 | + |
125 | + |
126 | +def add_button(bind_to, |
127 | + sizer, |
128 | + label, |
129 | + style, |
130 | + select_event, |
131 | + hover_event, |
132 | + unhover_event): |
133 | + |
134 | + """Create a radio button with event bindings.""" |
135 | + if(style != None): |
136 | + radio_button = wx.RadioButton(bind_to, label=label, style=style) |
137 | + else: |
138 | + radio_button = wx.RadioButton(bind_to, label=label) |
139 | + |
140 | + sizer.Add(radio_button, 0, wx.ALIGN_LEFT | wx.LEFT | wx.RIGHT | wx.TOP, 5) |
141 | + bind_to.Bind(wx.EVT_RADIOBUTTON, select_event, radio_button) |
142 | + wx.EVT_ENTER_WINDOW(radio_button, hover_event) |
143 | + wx.EVT_LEAVE_WINDOW(radio_button, unhover_event) |
144 | + |
145 | + return radio_button |
146 | + |
147 | + |
148 | +class ReleaseOrSnapshotPage(wiz.PyWizardPage): |
149 | + """Ask the user if they want to use a release or a snapshot""" |
150 | + |
151 | + def __init__(self, parent, config): |
152 | + wiz.PyWizardPage.__init__(self, parent) |
153 | + self.config = config |
154 | + self.settings = self.config.settings |
155 | + self.sizer = wx.BoxSizer(wx.VERTICAL) |
156 | + self.next = None |
157 | + self.prev = None |
158 | + |
159 | + self.sizer.Add(wx.StaticText(self, -1, |
160 | +"""This Wizard will write an operating system of your choosing to |
161 | +either a disk image or to an MMC card. First we need to know if |
162 | +your priority is stability or the latest and greatest features.""")) |
163 | + |
164 | + self.box1 = wx.BoxSizer(wx.VERTICAL) |
165 | + |
166 | + self.button_text = {'release': "I would like to run stable, " |
167 | + "tested software.", |
168 | + 'snapshot': "I would like to run untested, but " |
169 | + "more up-to-date software."} |
170 | + |
171 | + add_button(self, self.box1, self.button_text['release'], |
172 | + wx.RB_GROUP, self.event_radio_button_select, None, None) |
173 | + |
174 | + # Save the setting for the default selected value |
175 | + self.settings['release_or_snapshot'] = "release" |
176 | + |
177 | + add_button(self, self.box1, self.button_text['snapshot'], None, |
178 | + self.event_radio_button_select, None, None) |
179 | + |
180 | + self.sizer.Add(self.box1, 0, wx.ALIGN_LEFT | wx.ALL, 5) |
181 | + |
182 | + self.SetSizerAndFit(self.sizer) |
183 | + self.sizer.Fit(self) |
184 | + self.Move((50, 50)) |
185 | + |
186 | + def event_radio_button_select(self, event): |
187 | + self.radio_selected = event.GetEventObject().GetLabel() |
188 | + # The radio button can be release, snapshot or "latest snapshot" |
189 | + if(self.radio_selected == self.button_text['release']): |
190 | + self.settings['release_or_snapshot'] = "release" |
191 | + else: |
192 | + self.settings['release_or_snapshot'] = "snapshot" |
193 | + |
194 | + def SetNext(self, next): |
195 | + self.next = next |
196 | + |
197 | + def GetNext(self): |
198 | + return self.next |
199 | + |
200 | + |
201 | +class AboutMyHardwarePage(wiz.WizardPageSimple): |
202 | + """Ask the user about their hardware. This only asks about the board, not |
203 | + any specific hardware packs because there can be multiple names for the |
204 | + same hardware pack or sometimes a hardware pack is only available in the |
205 | + releases or snapshots repository. We whittle down the choice as we go |
206 | + and the user can chose a hardare pack (if they don't like the default) |
207 | + under advanced options in the Linaro Media Create options |
208 | + page""" |
209 | + |
210 | + def __init__(self, parent, config, db, width): |
211 | + wiz.WizardPageSimple.__init__(self, parent) |
212 | + self.settings = config.settings |
213 | + self.db = db |
214 | + self.sizer = wx.BoxSizer(wx.VERTICAL) |
215 | + self.box1 = wx.BoxSizer(wx.VERTICAL) |
216 | + self.box2 = wx.BoxSizer(wx.VERTICAL) |
217 | + |
218 | + header = wx.StaticText(self, |
219 | + label="Please select the hardware that you " |
220 | + "would like to build an image for from " |
221 | + "the following list") |
222 | + |
223 | + header.Wrap(width - 10) # -10 because boarder below is 5 pixels wide |
224 | + |
225 | + #--- Hardware Combo Box --- |
226 | + # Make sure that the displayed release is the one set in settings if |
227 | + # no selection is made |
228 | + if "panda" in self.settings['choice']['hardware'].keys(): |
229 | + default_hardware = "panda" |
230 | + else: |
231 | + default_hardware = self.settings['choice']['hardware'].keys()[-1] |
232 | + |
233 | + self.settings['hardware'] = default_hardware |
234 | + self.settings['compatable_hwpacks'] = ( |
235 | + self.settings['choice']['hwpack'][self.settings['hardware']]) |
236 | + |
237 | + self.cb_hardware = wx.ComboBox(self, |
238 | + value=self.settings['choice'] |
239 | + ['hardware'] |
240 | + [default_hardware], |
241 | + style=wx.CB_DROPDOWN | wx.CB_READONLY) |
242 | + |
243 | + self.Bind(wx.EVT_COMBOBOX, |
244 | + self.event_combo_box_hardware, |
245 | + self.cb_hardware) |
246 | + self.box1.Add(self.cb_hardware, 0, |
247 | + wx.ALIGN_LEFT | wx.LEFT | wx.RIGHT | wx.TOP, 5) |
248 | + |
249 | + self.sizer.Add(header) |
250 | + self.sizer.Add(self.box1, 0, wx.ALIGN_LEFT | wx.ALL, 5) |
251 | + self.sizer.Add(self.box2, 0, wx.ALIGN_LEFT | wx.ALL, 5) |
252 | + self.SetSizerAndFit(self.sizer) |
253 | + self.sizer.Fit(self) |
254 | + self.Move((50, 50)) |
255 | + |
256 | + def on_page_changing(self): |
257 | + self.update_hardware_box() |
258 | + |
259 | + def update_hardware_box(self): |
260 | + self.cb_hardware.Clear() |
261 | + |
262 | + sorted_hardware_names = sorted(self.settings['choice']['hardware'] |
263 | + .iteritems(), |
264 | + key=operator.itemgetter(1)) |
265 | + |
266 | + table = self.settings['release_or_snapshot'] + "_hwpacks" |
267 | + |
268 | + for device_name, human_readable_name in sorted_hardware_names: |
269 | + for hwpack in self.settings['choice']['hwpack'][device_name]: |
270 | + if self.db.hardware_is_available_in_table(table, hwpack): |
271 | + self.cb_hardware.Append(human_readable_name, device_name) |
272 | + break |
273 | + |
274 | + #--- Event(s) --- |
275 | + def event_combo_box_hardware(self, event): |
276 | + self.settings['hardware'] = (event |
277 | + .GetEventObject() |
278 | + .GetClientData(event.GetSelection()) |
279 | + .encode('ascii')) |
280 | + |
281 | + self.settings['compatable_hwpacks'] = ( |
282 | + self.settings['choice']['hwpack'][self.settings['hardware']]) |
283 | + #--- END event(s) --- |
284 | + |
285 | + |
286 | +class SelectStableRelease(wiz.WizardPageSimple): |
287 | + """Ask the user which Linaro release they would like to run.""" |
288 | + def __init__(self, parent, config, db, width): |
289 | + wiz.WizardPageSimple.__init__(self, parent) |
290 | + self.settings = config.settings |
291 | + self.db = db |
292 | + self.sizer = wx.BoxSizer(wx.VERTICAL) |
293 | + self.wizard = parent |
294 | + |
295 | + header = wx.StaticText(self, label="Please select the stable Linaro " |
296 | + "release you would like to use") |
297 | + |
298 | + header.Wrap(width - 10) # -10 because boarder below is 5 pixels wide |
299 | + |
300 | + self.sizer.Add(header) |
301 | + self.box1 = wx.BoxSizer(wx.VERTICAL) |
302 | + |
303 | + platforms = [] |
304 | + for key, value in self.settings['choice']['platform'].items(): |
305 | + platforms.append(key) |
306 | + |
307 | + default_release = self.settings['UI']['translate'][platforms[-1]] |
308 | + self.cb_release = wx.ComboBox(self, |
309 | + value=default_release, |
310 | + style=wx.CB_DROPDOWN | wx.CB_READONLY) |
311 | + self.Bind(wx.EVT_COMBOBOX, |
312 | + self.event_combo_box_release, |
313 | + self.cb_release) |
314 | + |
315 | + if(default_release in self.settings['UI']['translate']): |
316 | + default_release = self.settings['UI']['translate'][default_release] |
317 | + self.settings['platform'] = ( |
318 | + self.settings['UI']['reverse-translate'][default_release]) |
319 | + |
320 | + for item in platforms: |
321 | + if(item in self.settings['UI']['translate']): |
322 | + new_item = self.settings['UI']['translate'][item] |
323 | + item = new_item |
324 | + |
325 | + self.cb_release.Append(item, item.upper()) |
326 | + |
327 | + self.cb_build = wx.ComboBox(self, |
328 | + style=wx.CB_DROPDOWN | wx.CB_READONLY) |
329 | + self.Bind(wx.EVT_COMBOBOX, self.event_combo_box_build, self.cb_build) |
330 | + |
331 | + self.box1.Add(self.cb_release, 0, |
332 | + wx.ALIGN_LEFT | wx.LEFT | wx.RIGHT | wx.TOP, 5) |
333 | + self.box1.Add(self.cb_build, 0, |
334 | + wx.ALIGN_LEFT | wx.LEFT | wx.RIGHT | wx.TOP, 5) |
335 | + self.sizer.Add(self.box1, 0, wx.ALIGN_LEFT | wx.ALL, 5) |
336 | + self.SetSizerAndFit(self.sizer) |
337 | + self.sizer.Fit(self) |
338 | + self.Move((50, 50)) |
339 | + |
340 | + def update_build_box(self): |
341 | + """Depending on what hardware has been chosen, the OS list may be |
342 | + restricted. Filter out anything that is unavailable.""" |
343 | + self.cb_build.Clear() |
344 | + |
345 | + builds = self.db.get_builds(self.settings['platform']) |
346 | + self.cb_build.SetValue("No build available") |
347 | + |
348 | + for build in builds: |
349 | + if(self.db.hardware_is_available_for_platform_build( |
350 | + self.settings['compatable_hwpacks'], |
351 | + self.settings['platform'], |
352 | + build) |
353 | + and self.db.build_is_available_for_platform_image( |
354 | + "release_binaries", |
355 | + self.settings['platform'], |
356 | + self.settings['image'], |
357 | + build)): |
358 | + |
359 | + self.cb_build.Append(build) |
360 | + self.cb_build.SetValue(build) |
361 | + self.settings['release_build'] = build |
362 | + |
363 | + available_hwpacks = ( |
364 | + self.db.get_available_hwpacks_for_hardware_build_plaform( |
365 | + self.settings['compatable_hwpacks'], |
366 | + self.settings['platform'], |
367 | + self.settings['release_build'])) |
368 | + |
369 | + if len(available_hwpacks): |
370 | + self.settings['hwpack'] = available_hwpacks[0] |
371 | + self.wizard.FindWindowById(wx.ID_FORWARD).Enable() |
372 | + else: |
373 | + self.wizard.FindWindowById(wx.ID_FORWARD).Disable() |
374 | + |
375 | + def update_release_and_build_boxes(self): |
376 | + """Depending on what hardware has been chosen, some builds may be |
377 | + unavailable...""" |
378 | + self.cb_release.Clear() |
379 | + |
380 | + default_release = None |
381 | + for platform, value in self.settings['choice']['platform'].items(): |
382 | + if(self.db.hardware_is_available_for_platform( |
383 | + self.settings['compatable_hwpacks'], |
384 | + platform) |
385 | + and len(self.db.execute_return_list( |
386 | + 'select * from release_binaries ' |
387 | + 'where platform == ? and image == ?', |
388 | + (platform, self.settings['image'])))): |
389 | + |
390 | + if(platform in self.settings['UI']['translate']): |
391 | + platform = self.settings['UI']['translate'][platform] |
392 | + |
393 | + self.cb_release.Append(platform, platform.upper()) |
394 | + if not default_release or default_release < platform: |
395 | + default_release = platform |
396 | + |
397 | + self.settings['platform'] = ( |
398 | + self.settings['UI']['reverse-translate'][default_release]) |
399 | + self.cb_release.SetValue(default_release) |
400 | + self.update_build_box() |
401 | + |
402 | + #--- Event(s) --- |
403 | + def event_combo_box_release(self, evt): |
404 | + str = evt.GetString().encode('ascii').lower() |
405 | + if(str in self.settings['UI']['reverse-translate']): |
406 | + str = self.settings['UI']['reverse-translate'][str] |
407 | + self.settings['platform'] = str |
408 | + |
409 | + self.update_build_box() |
410 | + |
411 | + def event_combo_box_build(self, evt): |
412 | + self.settings['release_build'] = evt.GetString().encode('ascii') |
413 | + #--- END event(s) --- |
414 | + |
415 | + |
416 | +class SelectSnapshot(wiz.WizardPageSimple): |
417 | + """Present the user with a calendar widget and a list of builds available |
418 | + on the selected date so they can chose a snapshot. Filter out days when |
419 | + their chosen hardware does not have an available build.""" |
420 | + |
421 | + def __init__(self, parent, config, db, width): |
422 | + wiz.WizardPageSimple.__init__(self, parent) |
423 | + self.settings = config.settings |
424 | + self.db = db |
425 | + self.wizard = parent |
426 | + self.width = width |
427 | + self.sizer = wx.BoxSizer(wx.VERTICAL) |
428 | + |
429 | + header = wx.StaticText(self, |
430 | + label="Builds are created most days. First " |
431 | + "please select the day on which the " |
432 | + "build you would like to use was built," |
433 | + " then, if there was more than one " |
434 | + "build that day you will be able to " |
435 | + "select the build number.") |
436 | + header.Wrap(width - 10) # -10 because boarder below is 5 pixels wide |
437 | + |
438 | + box1 = wx.BoxSizer(wx.VERTICAL) |
439 | + self.sizer.Add(header) |
440 | + |
441 | + # Set today as the default build date in settings |
442 | + # (matches the date picker) |
443 | + self.today = wx.DateTime() |
444 | + self.today.SetToCurrent() |
445 | + self.settings['build_date'] = self.today.FormatISODate().encode('ascii') |
446 | + |
447 | + dpc = wx.DatePickerCtrl(self, size=(120, -1), |
448 | + style=wx.DP_DEFAULT) |
449 | + self.Bind(wx.EVT_DATE_CHANGED, self.on_date_changed, dpc) |
450 | + |
451 | + #--- Build number Combo Box --- |
452 | + # Make sure that the displayed build is the one set in settings if no |
453 | + # selection is made |
454 | + self.settings['build_number'] = 0 |
455 | + self.update_build() |
456 | + self.cb_build = wx.ComboBox(self, |
457 | + style=wx.CB_DROPDOWN | wx.CB_READONLY) |
458 | + self.Bind(wx.EVT_COMBOBOX, self.event_combo_box_build, self.cb_build) |
459 | + |
460 | + #--- Layout --- |
461 | + # -- Combo boxes for hardware and image selection -- |
462 | + |
463 | + grid2 = wx.FlexGridSizer(0, 2, 0, 0) |
464 | + grid2.Add(dpc, 0, wx.ALIGN_LEFT | wx.ALL, 5) |
465 | + grid2.Add(self.cb_build, 0, wx.ALIGN_LEFT | wx.ALL, 5) |
466 | + |
467 | + box1.Add(grid2, 0, wx.ALIGN_LEFT | wx.ALL, 5) |
468 | + |
469 | + self.sizer.Add(box1, 0, wx.ALIGN_LEFT | wx.ALL, 5) |
470 | + |
471 | + self.help_text = wx.StaticText(self) |
472 | + self.sizer.Add(self.help_text, 1, wx.EXPAND, 5) |
473 | + |
474 | + self.SetSizer(self.sizer) |
475 | + self.sizer.Fit(self) |
476 | + self.Move((50, 50)) |
477 | + |
478 | + def update_platform(self): |
479 | + build_and_date = self.settings['snapshot_build'].split(":") |
480 | + |
481 | + if len(build_and_date) == 2: |
482 | + self.settings['platform'] = ( |
483 | + self.db.execute_return_list( |
484 | + "select platform from snapshot_binaries " |
485 | + "where date == ? and build == ?", |
486 | + (build_and_date[0], build_and_date[1]))) |
487 | + |
488 | + if len(self.settings['platform']) > 0: |
489 | + self.settings['platform'] = self.settings['platform'][0][0] |
490 | + |
491 | + def update_build(self): |
492 | + small_date = re.sub('-', '', self.settings['build_date']) |
493 | + self.settings['snapshot_build'] = (small_date |
494 | + + ":" |
495 | + + str(self.settings['build_number'])) |
496 | + |
497 | + def fill_build_combo_box_for_date(self, date): |
498 | + """Every time a date is chosen, this function should be called. It will |
499 | + check to see if a compatible build is available. If there isn't, it |
500 | + will search for one and provide some help text to tell the user when |
501 | + compatable builds were built.""" |
502 | + # Re-populate the build combo box |
503 | + |
504 | + self.cb_build.Clear() |
505 | + |
506 | + builds = self.db.get_binary_builds_on_day_from_db( |
507 | + self.settings['image'], |
508 | + date, |
509 | + self.settings['compatable_hwpacks']) |
510 | + |
511 | + if len(builds): |
512 | + max = 0 |
513 | + for item in builds: |
514 | + #Always get a tuple, only interested in the first entry |
515 | + item = item[0] |
516 | + self.cb_build.Append(item, item.upper()) |
517 | + |
518 | + if item > max: |
519 | + max = item |
520 | + |
521 | + self.cb_build.SetValue(max) |
522 | + self.wizard.FindWindowById(wx.ID_FORWARD).Enable() |
523 | + self.help_text.SetLabel("") |
524 | + |
525 | + else: |
526 | + self.cb_build.SetValue("No builds available") |
527 | + future_date, past_date = self.db.get_next_prev_day_with_builds( |
528 | + self.settings['image'], |
529 | + date, |
530 | + self.settings['compatable_hwpacks']) |
531 | + |
532 | + help_text = None |
533 | + |
534 | + if future_date and past_date: |
535 | + help_text = ("There are no builds that match your " |
536 | + "specifications available on the selected date. " |
537 | + "The previous build was on " + past_date + |
538 | + " and the next build was on " + future_date + ".") |
539 | + elif future_date: |
540 | + help_text = ("There are no builds that match your " |
541 | + "specifications available on the selected date. " |
542 | + "The next build was on " + future_date + |
543 | + " and I couldn't find a past build (looked one " |
544 | + "year back from the selected date).") |
545 | + elif past_date: |
546 | + help_text = ("There are no builds that match your " |
547 | + "specifications available on the selected date. " |
548 | + "The previous build was on " + past_date) |
549 | + if date != self.today.FormatISODate().encode('ascii'): |
550 | + help_text += (" and I couldn't find a future build (I " |
551 | + "looked up to one year forward from the " |
552 | + "selected date).") |
553 | + else: |
554 | + help_text = ("I could not find any builds that match your " |
555 | + "specifications close to the selected date (I " |
556 | + "looked forward and back one year from the " |
557 | + "selected date).") |
558 | + |
559 | + self.help_text.SetLabel(help_text) |
560 | + self.help_text.Wrap(self.width - 10) |
561 | + self.wizard.FindWindowById(wx.ID_FORWARD).Disable() |
562 | + |
563 | + #--- Event(s) --- |
564 | + def on_date_changed(self, evt): |
565 | + self.settings['build_date'] = evt.GetDate().FormatISODate().encode('ascii') |
566 | + self.fill_build_combo_box_for_date(self.settings['build_date']) |
567 | + self.update_build() |
568 | + |
569 | + def event_combo_box_build(self, evt): |
570 | + self.settings['build_number'] = evt.GetString().encode('ascii').lower() |
571 | + self.update_build() |
572 | + #--- END event(s) --- |
573 | + |
574 | + |
575 | +class SelectOS(wiz.WizardPageSimple): |
576 | + """Ask the user which OS they would like to run. Filter out any choices |
577 | + that are unavailable due to previous choices.""" |
578 | + def __init__(self, parent, config, db, width): |
579 | + wiz.WizardPageSimple.__init__(self, parent) |
580 | + self.settings = config.settings |
581 | + self.wizard = parent |
582 | + self.db = db |
583 | + self.width = width |
584 | + self.sizer = wx.BoxSizer(wx.VERTICAL) |
585 | + self.settings['image'] = None |
586 | + |
587 | + header = wx.StaticText(self, label="Please select the operating " |
588 | + "system you would like to run on " |
589 | + "your hardware.") |
590 | + header.Wrap(width - 10) # -10 because boarder below is 5 pixels wide |
591 | + |
592 | + self.box1 = wx.BoxSizer(wx.VERTICAL) |
593 | + self.sizer.Add(header) |
594 | + |
595 | + self.cb_image = wx.ComboBox(self, |
596 | + style=wx.CB_DROPDOWN | wx.CB_READONLY) |
597 | + self.Bind(wx.EVT_COMBOBOX, self.event_combo_box_os, self.cb_image) |
598 | + |
599 | + #--- Layout --- |
600 | + # -- Combo boxes for hardware and image selection -- |
601 | + self.box1.Add(self.cb_image, 0, wx.ALIGN_LEFT | wx.ALL, 5) |
602 | + |
603 | + self.sizer.Add(self.box1, 0, wx.ALIGN_LEFT | wx.ALL, 5) |
604 | + |
605 | + self.help_text = wx.StaticText(self) |
606 | + self.sizer.Add(self.help_text, 1, wx.EXPAND, 5) |
607 | + |
608 | + self.SetSizer(self.sizer) |
609 | + self.sizer.Fit(self) |
610 | + self.Move((50, 50)) |
611 | + |
612 | + def get_human_os_name(self, item): |
613 | + """Given an OS name from the database, return a human name (either |
614 | + translated from the YAML settings, or just prettified) and if it is a |
615 | + LEB OS or not""" |
616 | + |
617 | + item = re.sub("linaro-", "", item) # Remove any linaro- decoration |
618 | + |
619 | + human_name = item |
620 | + |
621 | + if item in self.settings['UI']['descriptions']: |
622 | + human_name = self.settings['UI']['descriptions'][item] |
623 | + else: |
624 | + # Make human_name look nicer... |
625 | + human_name = string.capwords(item) |
626 | + |
627 | + leb_search = re.search("^LEB:\s*(.*)$", human_name) |
628 | + |
629 | + if leb_search: |
630 | + return leb_search.group(1), True |
631 | + |
632 | + return human_name, False |
633 | + |
634 | + def fill_os_list(self): |
635 | + """Filter the list of OS's from the config file based on the users |
636 | + preferences so all choices in the list are valid (i.e. their hardware |
637 | + is supported for the build they have chosen).""" |
638 | + |
639 | + # select unique image from snapshot_binaries/release_binaries to |
640 | + # generate list |
641 | + os_list = None |
642 | + if self.settings['release_or_snapshot'] == "release": |
643 | + os_list = self.db.get_os_list_from('release_binaries') |
644 | + else: |
645 | + os_list = self.db.get_os_list_from('snapshot_binaries') |
646 | + |
647 | + self.cb_image.Clear() |
648 | + |
649 | + printed_tag = None |
650 | + last_name = None |
651 | + current_image_setting_valid = False |
652 | + |
653 | + for state in ["LEB", "other"]: |
654 | + for item in os_list: |
655 | + if item == "old": |
656 | + # Old is a directory that sometimes hangs around, |
657 | + # but isn't one we want to display |
658 | + continue |
659 | + |
660 | + # Save the original, untouched image name for use later. |
661 | + # We give it a more human name for display |
662 | + original = item |
663 | + item = re.sub("linaro-", "", item) |
664 | + |
665 | + os_hardware_combo_available = ( |
666 | + self.db.image_hardware_combo_available( |
667 | + self.settings['release_or_snapshot'], |
668 | + original, |
669 | + self.settings['compatable_hwpacks'])) |
670 | + |
671 | + if os_hardware_combo_available: |
672 | + human_name, is_LEB = self.get_human_os_name(item) |
673 | + |
674 | + if item == self.settings['image']: |
675 | + current_image_setting_valid = True |
676 | + |
677 | + if state == "LEB" and is_LEB: |
678 | + |
679 | + if printed_tag != state: |
680 | + self.cb_image.Append( |
681 | + "- Linaro Supported Releases -") |
682 | + printed_tag = state |
683 | + |
684 | + self.cb_image.Append(human_name, original) |
685 | + |
686 | + if self.settings['image'] == None: |
687 | + self.settings['image'] = original |
688 | + |
689 | + elif state != "LEB" and not is_LEB: |
690 | + if printed_tag != state: |
691 | + self.cb_image.Append( |
692 | + "- Community Supported Releases -") |
693 | + printed_tag = state |
694 | + |
695 | + self.cb_image.Append(human_name, original) |
696 | + |
697 | + last_name = original |
698 | + |
699 | + if( self.settings['image'] != None |
700 | + and current_image_setting_valid == False): |
701 | + # If we have an image setting, but it doesn't match the OS list, we |
702 | + # have switched OS list. It may be that adding/removing "linaro-" |
703 | + # from the name will get a match. |
704 | + |
705 | + if re.search("linaro-", self.settings['image']): |
706 | + test_name = re.sub("linaro-", "", self.settings['image']) |
707 | + else: |
708 | + test_name = "linaro-" + self.settings['image'] |
709 | + |
710 | + if test_name in os_list: |
711 | + # Success! We have translated the name and can retain the |
712 | + # "old setting" |
713 | + self.settings['image'] = test_name |
714 | + current_image_setting_valid = True |
715 | + |
716 | + if( self.settings['image'] == None |
717 | + or current_image_setting_valid == False): |
718 | + # This should only get hit if there are no LEBs available |
719 | + self.settings['image'] = last_name |
720 | + |
721 | + assert self.settings['image'] |
722 | + |
723 | + # Make sure the visible selected value matches the saved setting |
724 | + self.cb_image.SetValue( |
725 | + self.get_human_os_name(self.settings['image'])[0]) |
726 | + |
727 | + #--- Event(s) --- |
728 | + def event_combo_box_os(self, evt): |
729 | + self.settings['image'] = self.cb_image.GetClientData( |
730 | + evt.GetSelection()) |
731 | + |
732 | + if self.settings['image']: # Is None for items that aren't an OS |
733 | + self.wizard.FindWindowById(wx.ID_FORWARD).Enable() |
734 | + image = re.sub("linaro-", "", self.settings['image']) |
735 | + |
736 | + if image + "::long" in self.settings['UI']['descriptions']: |
737 | + self.help_text.SetLabel(self.settings['UI'] |
738 | + ['descriptions'] |
739 | + [image + "::long"]) |
740 | + else: |
741 | + self.help_text.SetLabel("") |
742 | + |
743 | + else: # Have selected help text |
744 | + self.wizard.FindWindowById(wx.ID_FORWARD).Disable() |
745 | + self.help_text.SetLabel("Please select an operating system to run " |
746 | + "on your chosen hardware.") |
747 | + |
748 | + self.help_text.Wrap(self.width - 10) |
749 | + #--- END event(s) --- |
750 | + |
751 | + |
752 | +class LMC_settings(wiz.WizardPageSimple): |
753 | + """Present the user with, intially, the choice of writing the file system |
754 | + they are going to have created to a file, or directly to a device. Ask |
755 | + which file/device to write to. |
756 | + |
757 | + If writing to a device, the user is asked to tick a box saying that they |
758 | + understand that the device they have chosen will be erased. |
759 | + |
760 | + If the user ticks the advanced box, more options are shown.""" |
761 | + |
762 | + def __init__(self, parent, config, db, width): |
763 | + wiz.WizardPageSimple.__init__(self, parent) |
764 | + self.settings = config.settings |
765 | + self.wizard = parent |
766 | + self.sizer = wx.BoxSizer(wx.VERTICAL) |
767 | + self.yes_use_mmc = False |
768 | + self.db = db |
769 | + |
770 | + self.settings['path_selected'] = "" |
771 | + |
772 | + header = wx.StaticText(self, |
773 | + label="Media Creation Settings\n\n" |
774 | + "Please select if you would like to write the " |
775 | + "file system I am about to create to a memory " |
776 | + "card, or to a file on the local file system.") |
777 | + header.Wrap(width - 10) # -10 because boarder below is 5 pixels wide |
778 | + |
779 | + #--- Build some widgets --- |
780 | + #-- Target file system -- |
781 | + file_systems = ["ext3", "ext4", "btrfs", "ext2"] |
782 | + default_target = file_systems[0] |
783 | + self.settings['rootfs'] = default_target |
784 | + cb_rootfs = wx.ComboBox(self, |
785 | + value=default_target, |
786 | + style=wx.CB_DROPDOWN | wx.CB_READONLY) |
787 | + |
788 | + for item in file_systems: |
789 | + cb_rootfs.Append(item, item.upper()) |
790 | + |
791 | + self.Bind(wx.EVT_COMBOBOX, self.event_combo_box_rootfs, cb_rootfs) |
792 | + |
793 | + #-- Image size spinner |
794 | + self.image_size_spinner = wx.SpinCtrl(self, -1, "") |
795 | + self.Bind(wx.EVT_SPINCTRL, |
796 | + self.event_image_size, |
797 | + self.image_size_spinner) |
798 | + |
799 | + #-- Swap size spinner |
800 | + self.swap_size_spinner = wx.SpinCtrl(self, -1, "") |
801 | + self.Bind(wx.EVT_SPINCTRL, |
802 | + self.event_swap_size, |
803 | + self.swap_size_spinner) |
804 | + |
805 | + #--- Layout --- |
806 | + self.sizer.Add(header, 0, wx.ALIGN_LEFT | wx.ALL, 5) |
807 | + box1 = wx.BoxSizer(wx.VERTICAL) |
808 | + file_dev_grid = wx.FlexGridSizer(0, 2, 0, 0) |
809 | + box1.Add(file_dev_grid, 0, wx.EXPAND) |
810 | + grid1 = wx.FlexGridSizer(0, 2, 0, 0) |
811 | + |
812 | + # self.settings['write_to_file_or_device'] should match the first |
813 | + # button below... |
814 | + self.settings['write_to_file_or_device'] = "file" |
815 | + add_button(self, |
816 | + file_dev_grid, |
817 | + "Write to file", |
818 | + wx.RB_GROUP, |
819 | + self.event_radio_button_select, |
820 | + None, None) |
821 | + |
822 | + add_button(self, |
823 | + file_dev_grid, |
824 | + "Write to device", |
825 | + None, |
826 | + self.event_radio_button_select, |
827 | + None, None) |
828 | + |
829 | + self.help_text_values = {"device": "Please select a device to write " |
830 | + "the file system to:", |
831 | + |
832 | + "file": "Please select a file to write the " |
833 | + "file system to:"} |
834 | + |
835 | + self.help_text = wx.StaticText( |
836 | + self, |
837 | + label=self.help_text_values[ |
838 | + self.settings['write_to_file_or_device']]) |
839 | + self.help_text.Wrap(width - 10) |
840 | + |
841 | + #-- File/dev picker -- |
842 | + file_browse_button = wx.Button(self, -1, "Browse") |
843 | + file_browse_grid = wx.FlexGridSizer(0, 2, 0, 0) |
844 | + self.file_path_and_name = wx.TextCtrl(self, -1, "", size=(300, -1)) |
845 | + |
846 | + file_browse_grid.Add(self.file_path_and_name, 0, wx.EXPAND) |
847 | + file_browse_grid.Add(file_browse_button, 0, wx.EXPAND) |
848 | + |
849 | + self.Bind(wx.EVT_BUTTON, |
850 | + self.event_open_file_control, |
851 | + file_browse_button) |
852 | + |
853 | + self.Bind(wx.EVT_TEXT, |
854 | + self.event_file_path_and_name, |
855 | + self.file_path_and_name) |
856 | + |
857 | + box1.Add(self.help_text, 0, wx.ALIGN_LEFT | wx.ALL, 5) |
858 | + |
859 | + box1.Add(file_browse_grid, 0, wx.EXPAND) |
860 | + |
861 | + cb1 = wx.CheckBox(self, -1, "Show advanced options") |
862 | + self.Bind(wx.EVT_CHECKBOX, self.event_show_advanced_options, cb1) |
863 | + box1.Add(cb1) |
864 | + |
865 | + #-- Combo boxes for hardware and image selection -- |
866 | + optional_settings_box_title = wx.StaticBox( |
867 | + self, |
868 | + label=" Optional Settings ") |
869 | + |
870 | + self.optional_settings_box = wx.StaticBoxSizer( |
871 | + optional_settings_box_title, |
872 | + wx.VERTICAL) |
873 | + |
874 | + self.box2 = wx.BoxSizer(wx.VERTICAL) |
875 | + |
876 | + self.box2.AddWindow(self.optional_settings_box, |
877 | + 0, |
878 | + border=2, |
879 | + flag=wx.ALL | wx.EXPAND) |
880 | + |
881 | + grid1.Add(cb_rootfs, 0, wx.ALIGN_LEFT | wx.LEFT | wx.RIGHT | wx.TOP, 5) |
882 | + |
883 | + grid1.Add(wx.StaticText(self, |
884 | + label="The root file system of the image"), |
885 | + 0, |
886 | + wx.ALIGN_LEFT | wx.LEFT | wx.RIGHT | wx.TOP, |
887 | + 5) |
888 | + |
889 | + # We want to sub-devide the cell, to add another grid sizer... |
890 | + file_size_grid = wx.FlexGridSizer(0, 2, 0, 0) |
891 | + |
892 | + grid1.Add(file_size_grid, |
893 | + 0, |
894 | + wx.ALIGN_LEFT | wx.LEFT | wx.RIGHT | wx.TOP) |
895 | + |
896 | + # Add a spinner that allows us to type/click a numerical value (defined above) |
897 | + file_size_grid.Add(self.image_size_spinner, |
898 | + 0, |
899 | + wx.ALIGN_LEFT | wx.LEFT | wx.RIGHT | wx.TOP, |
900 | + 5) |
901 | + |
902 | + # Add a choice of MB or GB for size input |
903 | + units = ["GB", "MB"] |
904 | + self.size_unit = units[0] # Set the default unit |
905 | + unit_choice = wx.Choice(self, -1, (100, 50), choices=units) |
906 | + self.Bind(wx.EVT_CHOICE, self.event_chose_unit, unit_choice) |
907 | + file_size_grid.Add(unit_choice, 0, wx.ALIGN_RIGHT | wx.TOP, 5) |
908 | + |
909 | + # Back out of the extra grid, add some help text |
910 | + grid1.Add(wx.StaticText( |
911 | + self, |
912 | + label="Writing to file only: Image file size"), |
913 | + 0, |
914 | + wx.ALIGN_LEFT | wx.LEFT | wx.RIGHT | wx.TOP, |
915 | + 5) |
916 | + |
917 | + # The swap size (MB only) |
918 | + grid1.Add(self.swap_size_spinner, |
919 | + 0, |
920 | + wx.ALIGN_LEFT | wx.LEFT | wx.RIGHT | wx.TOP, |
921 | + 5) |
922 | + |
923 | + grid1.Add(wx.StaticText(self, label="Swap file size in MB"), |
924 | + 0, |
925 | + wx.ALIGN_LEFT | wx.LEFT | wx.RIGHT | wx.TOP, |
926 | + 5) |
927 | + |
928 | + self.cb_hwpacks = wx.ComboBox( |
929 | + self, |
930 | + value=self.settings['compatable_hwpacks'][0], |
931 | + style=wx.CB_DROPDOWN | wx.CB_READONLY) |
932 | + |
933 | + self.Bind(wx.EVT_COMBOBOX, |
934 | + self.event_combo_box_hwpack, |
935 | + self.cb_hwpacks) |
936 | + |
937 | + grid1.Add(self.cb_hwpacks, |
938 | + 0, |
939 | + wx.ALIGN_LEFT | wx.LEFT | wx.RIGHT | wx.TOP, |
940 | + 5) |
941 | + |
942 | + grid1.Add(wx.StaticText(self, label="Compatible hardware packs"), |
943 | + 0, |
944 | + wx.ALIGN_LEFT | wx.LEFT | wx.RIGHT | wx.TOP, |
945 | + 5) |
946 | + |
947 | + self.optional_settings_box.Add(grid1, 0, wx.ALIGN_LEFT | wx.ALL, 5) |
948 | + |
949 | + confirm_mmc_usage_title = wx.StaticBox(self, label=" Are you sure? ") |
950 | + |
951 | + self.confirm_mmc_usage_box = wx.StaticBoxSizer(confirm_mmc_usage_title, |
952 | + wx.VERTICAL) |
953 | + cb2 = wx.CheckBox( |
954 | + self, |
955 | + -1, |
956 | + "Yes, erase and use the device I have selected above.") |
957 | + |
958 | + self.Bind(wx.EVT_CHECKBOX, self.event_use_mmc_tickbox, cb2) |
959 | + self.confirm_mmc_usage_box.Add(cb2) |
960 | + |
961 | + self.box3 = wx.BoxSizer(wx.VERTICAL) |
962 | + self.box3.AddWindow(self.confirm_mmc_usage_box, |
963 | + 0, |
964 | + border=2, |
965 | + flag=wx.ALL | wx.EXPAND) |
966 | + |
967 | + self.sizer.Add(box1, 0, wx.ALIGN_LEFT | wx.ALL, 0) |
968 | + self.sizer.Add(self.box2, 0, wx.ALIGN_LEFT | wx.ALL, 0) |
969 | + self.sizer.Add(self.box3, 0, wx.ALIGN_LEFT | wx.ALL, 0) |
970 | + self.SetSizer(self.sizer) |
971 | + self.sizer.Fit(self) |
972 | + self.Move((50, 50)) |
973 | + |
974 | + def on_activate(self): |
975 | + self.update_forward_active_and_mmc_confirm_box_visible() |
976 | + self.set_hwpacks_for_hardware() |
977 | + |
978 | + def set_hwpacks_for_hardware(self): |
979 | + self.cb_hwpacks.Clear() |
980 | + |
981 | + if self.settings['release_or_snapshot'] == "snapshot": |
982 | + self.settings['build'] = self.settings['snapshot_build'] |
983 | + |
984 | + date_and_build = self.settings['build'].split(":") |
985 | + |
986 | + compatable_hwpacks = ( |
987 | + self.db.get_available_hwpacks_for_hardware_snapshot_build( |
988 | + self.settings['compatable_hwpacks'], |
989 | + self.settings['platform'], |
990 | + date_and_build[0], |
991 | + date_and_build[1])) |
992 | + else: |
993 | + self.settings['build'] = self.settings['release_build'] |
994 | + compatable_hwpacks = ( |
995 | + self.db.get_available_hwpacks_for_hardware_build_plaform( |
996 | + self.settings['compatable_hwpacks'], |
997 | + self.settings['platform'], |
998 | + self.settings['build'])) |
999 | + |
1000 | + for hwpack in compatable_hwpacks: |
1001 | + self.cb_hwpacks.Append(hwpack) |
1002 | + |
1003 | + self.cb_hwpacks.SetStringSelection(compatable_hwpacks[0]) |
1004 | + self.settings['hwpack'] = compatable_hwpacks[0] |
1005 | + |
1006 | + def update_forward_active_and_mmc_confirm_box_visible(self): |
1007 | + if( self.settings['path_selected'] |
1008 | + and self.settings['path_selected'] != ""): |
1009 | + |
1010 | + if ( self.settings['write_to_file_or_device'] == "file" |
1011 | + or self.settings['write_to_file_or_device'] == "device" |
1012 | + and self.yes_use_mmc): |
1013 | + self.wizard.FindWindowById(wx.ID_FORWARD).Enable() |
1014 | + else: |
1015 | + self.wizard.FindWindowById(wx.ID_FORWARD).Disable() |
1016 | + else: |
1017 | + self.wizard.FindWindowById(wx.ID_FORWARD).Disable() |
1018 | + |
1019 | + if self.settings['write_to_file_or_device'] == "device": |
1020 | + self.box3.Show(self.confirm_mmc_usage_box, True) |
1021 | + else: |
1022 | + self.box3.Hide(self.confirm_mmc_usage_box, True) |
1023 | + |
1024 | + # --- Event Handlers --- |
1025 | + def event_open_file_control(self, event): |
1026 | + if self.settings['write_to_file_or_device'] == "file": |
1027 | + |
1028 | + dlg = wx.FileDialog(self, |
1029 | + message="Save file as ...", |
1030 | + defaultDir=os.getcwd(), |
1031 | + defaultFile="", |
1032 | + style=wx.SAVE) |
1033 | + |
1034 | + elif self.settings['write_to_file_or_device'] == "device": |
1035 | + dlg = wx.FileDialog(self, |
1036 | + message="Choose a device", |
1037 | + defaultDir=os.getcwd(), |
1038 | + defaultFile="", |
1039 | + style=wx.OPEN | wx.CHANGE_DIR) |
1040 | + |
1041 | + if dlg.ShowModal() == wx.ID_OK: |
1042 | + self.settings['path_selected'] = dlg.GetPaths()[0] |
1043 | + self.file_path_and_name.SetValue(self.settings['path_selected']) |
1044 | + |
1045 | + dlg.Destroy() |
1046 | + self.update_forward_active_and_mmc_confirm_box_visible() |
1047 | + |
1048 | + def event_file_path_and_name(self, event): |
1049 | + self.settings['path_selected'] = event.GetString() |
1050 | + self.update_forward_active_and_mmc_confirm_box_visible() |
1051 | + |
1052 | + def event_combo_box_hwpack(self, event): |
1053 | + self.settings['hwpack'] = event.GetString().encode('ascii') |
1054 | + |
1055 | + def event_combo_box_rootfs(self, evt): |
1056 | + self.settings['rootfs'] = evt.GetString().encode('ascii').lower() |
1057 | + |
1058 | + def event_radio_button_select(self, event): |
1059 | + """Search the label of the button that has been selected to work out |
1060 | + what we are writing to.""" |
1061 | + setting_search = re.search( |
1062 | + "write to (\w+)", |
1063 | + event |
1064 | + .GetEventObject() |
1065 | + .GetLabel() |
1066 | + .encode('ascii') |
1067 | + .lower()) |
1068 | + |
1069 | + assert setting_search |
1070 | + |
1071 | + self.settings['write_to_file_or_device'] = setting_search.group(1) |
1072 | + |
1073 | + self.help_text.SetLabel( |
1074 | + self.help_text_values[self.settings['write_to_file_or_device']]) |
1075 | + |
1076 | + self.update_forward_active_and_mmc_confirm_box_visible() |
1077 | + |
1078 | + def event_show_advanced_options(self, event): |
1079 | + if event.IsChecked(): |
1080 | + self.box2.Show(self.optional_settings_box, True) |
1081 | + else: |
1082 | + self.box2.Hide(self.optional_settings_box, True) |
1083 | + |
1084 | + def event_pick_file_path(self, evt): |
1085 | + self.settings['path_selected'] = os.path.abspath(evt.GetPath()) |
1086 | + self.update_forward_active_and_mmc_confirm_box_visible() |
1087 | + |
1088 | + def update_image_size_setting(self): |
1089 | + if(self.image_size_spinner.GetValue() > 0): |
1090 | + self.settings['image_size'] = (str(self.image_size_spinner |
1091 | + .GetValue()) |
1092 | + + self.size_unit[0]) |
1093 | + else: |
1094 | + self.settings['image_size'] = None |
1095 | + |
1096 | + def event_image_size(self, event): |
1097 | + self.update_image_size_setting() |
1098 | + |
1099 | + def event_chose_unit(self, event): |
1100 | + self.size_unit = event.GetString() |
1101 | + self.update_image_size_setting() |
1102 | + |
1103 | + def event_swap_size(self, event): |
1104 | + self.settings['swap_file'] = str(self.image_size_spinner.GetValue()) |
1105 | + |
1106 | + def event_use_mmc_tickbox(self, event): |
1107 | + self.yes_use_mmc = event.IsChecked() |
1108 | + self.update_forward_active_and_mmc_confirm_box_visible() |
1109 | + |
1110 | + |
1111 | +class RunLMC(wiz.WizardPageSimple): |
1112 | + """Present the user with some information about their choices and a button |
1113 | + to start linaro-media-create. The linaro-media-create process is started in |
1114 | + a new thread and important events are communicated back to the UI through a |
1115 | + queue.""" |
1116 | + |
1117 | + def __init__(self, parent, config, db, width): |
1118 | + wiz.WizardPageSimple.__init__(self, parent) |
1119 | + self.settings = config.settings |
1120 | + self.sizer = wx.BoxSizer(wx.VERTICAL) |
1121 | + self.db = db |
1122 | + self.width = width |
1123 | + self.wizard = parent |
1124 | + |
1125 | + header = wx.StaticText(self, label="""Installing...""") |
1126 | + header.Wrap(width - 10) # -10 because boarder below is 5 pixels wide |
1127 | + |
1128 | + self.sizer.Add(header) |
1129 | + self.box1 = wx.BoxSizer(wx.VERTICAL) |
1130 | + |
1131 | + # We expect to print 4 lines of information, reserve space using blank |
1132 | + # lines. |
1133 | + self.settings_summary_text = wx.StaticText(self, label="\n\n\n\n") |
1134 | + self.settings_summary_text.Wrap(width - 10) |
1135 | + |
1136 | + self.box1.Add(self.settings_summary_text, 0, wx.ALIGN_LEFT | wx.ALL, 5) |
1137 | + |
1138 | + self.start_button = wx.Button(self, 10, "Start", (20, 20)) |
1139 | + self.Bind(wx.EVT_BUTTON, self.start_lmc, self.start_button) |
1140 | + |
1141 | + self.start_button.SetToolTipString("Start creating an image, using the" |
1142 | + "above settings.") |
1143 | + |
1144 | + self.start_button.SetSize(self.start_button.GetBestSize()) |
1145 | + self.box1.Add(self.start_button, 0, wx.ALIGN_LEFT | wx.ALL, 5) |
1146 | + |
1147 | + self.download_guage = wx.Gauge(self, |
1148 | + -1, |
1149 | + 1000, |
1150 | + size=(self.width * 2 / 3, 25)) |
1151 | + |
1152 | + self.status_grid = wx.FlexGridSizer(0, 2) |
1153 | + |
1154 | + self.status_grid.Add(wx.StaticText(self, label="Downloading files"), |
1155 | + 0, |
1156 | + wx.ALIGN_LEFT | wx.LEFT | wx.RIGHT | wx.TOP, |
1157 | + 5) |
1158 | + |
1159 | + self.downloading_files_status = wx.StaticText(self, label="") |
1160 | + |
1161 | + self.status_grid.Add(self.downloading_files_status, |
1162 | + 0, |
1163 | + wx.ALIGN_LEFT | wx.LEFT | wx.RIGHT | wx.TOP, |
1164 | + 5) |
1165 | + |
1166 | + self.status_grid.Add(self.download_guage, |
1167 | + 0, |
1168 | + wx.ALIGN_LEFT | wx.LEFT | wx.RIGHT | wx.TOP, |
1169 | + 5) |
1170 | + |
1171 | + self.downloading_files_info = wx.StaticText(self, label="") |
1172 | + |
1173 | + self.status_grid.Add(self.downloading_files_info, |
1174 | + 0, |
1175 | + wx.ALIGN_LEFT | wx.LEFT | wx.RIGHT | wx.TOP, |
1176 | + 5) |
1177 | + |
1178 | + self.status_grid.Add(wx.StaticText(self, label="Unpacking downloads"), |
1179 | + 0, |
1180 | + wx.ALIGN_LEFT | wx.LEFT | wx.RIGHT | wx.TOP, |
1181 | + 5) |
1182 | + |
1183 | + self.unpacking_files_status = wx.StaticText(self, label="") |
1184 | + |
1185 | + self.status_grid.Add(self.unpacking_files_status, |
1186 | + 0, |
1187 | + wx.ALIGN_LEFT | wx.LEFT | wx.RIGHT | wx.TOP, |
1188 | + 5) |
1189 | + |
1190 | + self.status_grid.Add(wx.StaticText(self, label="Installing packages"), |
1191 | + 0, |
1192 | + wx.ALIGN_LEFT | wx.LEFT | wx.RIGHT | wx.TOP, |
1193 | + 5) |
1194 | + |
1195 | + self.installing_packages_status = wx.StaticText(self, label="") |
1196 | + |
1197 | + self.status_grid.Add(self.installing_packages_status, |
1198 | + 0, |
1199 | + wx.ALIGN_LEFT | wx.LEFT | wx.RIGHT | wx.TOP, |
1200 | + 5) |
1201 | + |
1202 | + self.status_grid.Add(wx.StaticText(self, label="Create file system"), |
1203 | + 0, |
1204 | + wx.ALIGN_LEFT | wx.LEFT | wx.RIGHT | wx.TOP, |
1205 | + 5) |
1206 | + |
1207 | + self.create_file_system_status = wx.StaticText(self, label="") |
1208 | + |
1209 | + self.status_grid.Add(self.create_file_system_status, |
1210 | + 0, |
1211 | + wx.ALIGN_LEFT | wx.LEFT | wx.RIGHT | wx.TOP, |
1212 | + 5) |
1213 | + |
1214 | + self.status_grid.Add(wx.StaticText(self, label="Populate file system"), |
1215 | + 0, |
1216 | + wx.ALIGN_LEFT | wx.LEFT | wx.RIGHT | wx.TOP, |
1217 | + 5) |
1218 | + |
1219 | + self.populate_file_system_status = wx.StaticText(self, label="") |
1220 | + |
1221 | + self.status_grid.Add(self.populate_file_system_status, |
1222 | + 0, |
1223 | + wx.ALIGN_LEFT | wx.LEFT | wx.RIGHT | wx.TOP, |
1224 | + 5) |
1225 | + |
1226 | + self.sizer.Add(self.box1, 0, wx.ALIGN_LEFT | wx.ALL, 5) |
1227 | + self.sizer.Add(self.status_grid, 0, wx.ALIGN_LEFT | wx.ALL, 5) |
1228 | + self.SetSizerAndFit(self.sizer) |
1229 | + self.sizer.Fit(self) |
1230 | + self.Move((50, 50)) |
1231 | + |
1232 | + def on_activate(self): |
1233 | + """Called just before the page is displayed to update the text based on |
1234 | + the users preferences.""" |
1235 | + |
1236 | + # The build is stored in different forms depending on if we are using a |
1237 | + # release or snapshot but from here on in it is a common value |
1238 | + if self.settings['release_or_snapshot'] == "snapshot": |
1239 | + self.settings['build'] = self.settings['snapshot_build'] |
1240 | + else: |
1241 | + self.settings['build'] = self.settings['release_build'] |
1242 | + |
1243 | + settings_summary = ("Press start to create an image with the " |
1244 | + "following settings:\n") |
1245 | + settings_summary += "Operating System: " + self.settings['image'] + "\n" |
1246 | + settings_summary += "Hardware: " + self.settings['hardware'] + "\n" |
1247 | + |
1248 | + # Assumption is that a file may be in a long path, we don't know how |
1249 | + # big the font is and we don't want to allow the path to run off the |
1250 | + # end of the line, so if a file is chosen, just show the file name. |
1251 | + # Devices are (probably) /dev/some_short_name and the user really needs |
1252 | + # to check them, so we show the whole thing. |
1253 | + path = self.settings['path_selected'] |
1254 | + if self.settings['write_to_file_or_device'] == "file": |
1255 | + path = self.settings['path_selected'].split(os.sep)[-1] |
1256 | + |
1257 | + settings_summary += ( "Writing image to " |
1258 | + + self.settings['write_to_file_or_device'] |
1259 | + + " " |
1260 | + + path) |
1261 | + |
1262 | + self.settings_summary_text.SetLabel(settings_summary) |
1263 | + self.settings_summary_text.Wrap(self.width - 10) |
1264 | + |
1265 | + def start_lmc(self, event): |
1266 | + """Start a thread that runs linaro-media-create and a timer, which |
1267 | + checks for UI updates every 100ms""" |
1268 | + |
1269 | + if self.settings['write_to_file_or_device'] == "file": |
1270 | + self.settings['image_file'] = self.settings['path_selected'] |
1271 | + elif self.settings['write_to_file_or_device'] == "device": |
1272 | + self.settings['mmc'] = self.settings['path_selected'] |
1273 | + else: |
1274 | + assert False, ("self.config.settings['write_to_file_or_device'] " |
1275 | + "was an unexpected value" |
1276 | + + self.settings['write_to_file_or_device']) |
1277 | + |
1278 | + image_url, hwpack_url = self.db.get_image_and_hwpack_urls(self.settings) |
1279 | + |
1280 | + # Currently the UI is blocked when LMC is running, so grey out the |
1281 | + # buttons to indicate to the user that they won't work! |
1282 | + self.wizard.FindWindowById(wx.ID_BACKWARD).Disable() |
1283 | + self.wizard.FindWindowById(wx.ID_CANCEL).Disable() |
1284 | + |
1285 | + if(image_url and hwpack_url): |
1286 | + |
1287 | + self.file_handler = FetchImage.FileHandler() |
1288 | + |
1289 | + self.timer = wx.Timer(self) |
1290 | + self.Bind(wx.EVT_TIMER, self.timer_ping, self.timer) |
1291 | + self.timer.Start(milliseconds=100, oneShot=True) |
1292 | + |
1293 | + tools_dir = os.path.dirname(__file__) |
1294 | + if tools_dir == '': |
1295 | + tools_dir = None |
1296 | + |
1297 | + self.start_button.Disable() |
1298 | + self.event_queue = Queue.Queue() |
1299 | + self.lmc_thread = self.file_handler.LinaroMediaCreate( |
1300 | + image_url, |
1301 | + hwpack_url, |
1302 | + self.file_handler, |
1303 | + self.event_queue, |
1304 | + self.settings, |
1305 | + tools_dir) |
1306 | + self.lmc_thread.start() |
1307 | + else: |
1308 | + print >> sys.stderr, ("Unable to find files that match the" |
1309 | + "parameters specified") |
1310 | + |
1311 | + def timer_ping(self, event): |
1312 | + """During start_lmc a timer is started to poll for events from |
1313 | + linaro-media-create every 100ms. This is the function which is called |
1314 | + to do that polling.""" |
1315 | + |
1316 | + while not self.event_queue.empty(): |
1317 | + event = self.event_queue.get() |
1318 | + |
1319 | + if event[0] == "start": |
1320 | + self.event_start(event[1]) |
1321 | + |
1322 | + elif event[0] == "end": |
1323 | + self.event_end(event[1]) |
1324 | + |
1325 | + elif event == "terminate": |
1326 | + # Process complete. Enable next button. |
1327 | + self.wizard.FindWindowById(wx.ID_FORWARD).Enable() |
1328 | + self.populate_file_system_status.SetLabel("Done") |
1329 | + return # Even if queue isn't empty, stop processing it |
1330 | + |
1331 | + elif event[0] == "update": |
1332 | + self.event_update(event[1], event[2], event[3]) |
1333 | + |
1334 | + else: |
1335 | + print >> sys.stderr, "timer_ping: Unhandled event", event |
1336 | + |
1337 | + self.timer.Start(milliseconds=50, oneShot=True) |
1338 | + |
1339 | + def unsigned_packages_query(self, package_list): |
1340 | + message = ('In order to continue, I need to install some unsigned' |
1341 | + 'packages into the image. Is this OK? The packages are:' |
1342 | + '\n\n' + package_list) |
1343 | + |
1344 | + dlg = wx.MessageDialog(self, |
1345 | + message, |
1346 | + 'Install Unsigned Packages Into Image?', |
1347 | + wx.YES_NO | wx.NO_DEFAULT) |
1348 | + |
1349 | + choice = dlg.ShowModal() |
1350 | + dlg.Destroy() |
1351 | + |
1352 | + return choice == wx.ID_YES |
1353 | + |
1354 | + #--- Event(s) --- |
1355 | + def event_start(self, event): |
1356 | + if event == "download OS": |
1357 | + self.downloading_files_status.SetLabel("Downloading OS") |
1358 | + elif event == "download hwpack": |
1359 | + self.downloading_files_status.SetLabel("Downloading Hardware Pack") |
1360 | + elif event == "unpack": |
1361 | + self.unpacking_files_status.SetLabel("Running") |
1362 | + elif event == "installing packages": |
1363 | + self.installing_packages_status.SetLabel("Running") |
1364 | + |
1365 | + elif re.search('^unverified_packages:', event): |
1366 | + # Get rid of event ID and whitespace invariance |
1367 | + packages = " ".join(event.split()[1:]) |
1368 | + install_unsigned_packages = self.unsigned_packages_query(packages) |
1369 | + |
1370 | + if install_unsigned_packages == False: |
1371 | + self.file_handler.kill_create_media() |
1372 | + sys.exit(1) |
1373 | + else: |
1374 | + self.lmc_thread.send_to_create_process("y") |
1375 | + |
1376 | + elif event == "create file system": |
1377 | + self.create_file_system_status.SetLabel("Running") |
1378 | + elif event == "populate file system": |
1379 | + self.populate_file_system_status.SetLabel("Running") |
1380 | + else: |
1381 | + print "Unhandled start event:", event |
1382 | + |
1383 | + def event_end(self, event): |
1384 | + if event == "download OS": |
1385 | + self.downloading_files_status.SetLabel("Done (1/2)") |
1386 | + elif event == "download hwpack": |
1387 | + self.downloading_files_status.SetLabel("Done") |
1388 | + elif event == "unpack": |
1389 | + self.unpacking_files_status.SetLabel("Done") |
1390 | + elif event == "installing packages": |
1391 | + self.installing_packages_status.SetLabel("Done") |
1392 | + elif event == "create file system": |
1393 | + self.create_file_system_status.SetLabel("Done") |
1394 | + elif event == "populate file system": |
1395 | + self.populate_file_system_status.SetLabel("Done") |
1396 | + else: |
1397 | + print "Unhhandled end event:", event |
1398 | + |
1399 | + def event_update(self, task, update_type, value): |
1400 | + if task == "download": |
1401 | + if update_type == "name": |
1402 | + self.downloading_files_status.SetLabel("Downloading") |
1403 | + self.old_time = time.time() |
1404 | + self.old_bytes_downloaded = 0 |
1405 | + |
1406 | + elif update_type == "progress": |
1407 | + self.total_bytes_downloaded += value |
1408 | + |
1409 | + time_difference = time.time() - self.old_time |
1410 | + |
1411 | + if time_difference > 1.0: |
1412 | + self.old_time = time.time() |
1413 | + |
1414 | + # More than a second has passed since we calculated data |
1415 | + # rate |
1416 | + speed = ( float( self.total_bytes_downloaded |
1417 | + - self.old_bytes_downloaded) |
1418 | + / time_difference) |
1419 | + |
1420 | + self.old_bytes_downloaded = self.total_bytes_downloaded |
1421 | + |
1422 | + self.speeds.append(speed) |
1423 | + |
1424 | + average_speed = 0 |
1425 | + speeds_accumulated = 0 |
1426 | + for speed in reversed(self.speeds): |
1427 | + average_speed += speed |
1428 | + speeds_accumulated += 1 |
1429 | + |
1430 | + if speeds_accumulated == 6: |
1431 | + break # do rolling average of 6 seconds |
1432 | + |
1433 | + average_speed /= speeds_accumulated |
1434 | + |
1435 | + time_remaining = ( ( self.total_bytes_to_download |
1436 | + - self.total_bytes_downloaded) |
1437 | + / speed) |
1438 | + |
1439 | + pretty_time = str(datetime.timedelta(seconds=int( |
1440 | + time_remaining))) |
1441 | + |
1442 | + # Following table assumes we don't get past TBps internet |
1443 | + # connections soon :-) |
1444 | + units = ["Bps", "kBps", "MBps", "GBps", "TBps"] |
1445 | + units_index = 0 |
1446 | + while speed > 1024: |
1447 | + speed /= 1024 |
1448 | + units_index += 1 |
1449 | + |
1450 | + info = "Downloading at {0:.1f} {1}".format( |
1451 | + speed, |
1452 | + units[units_index]) |
1453 | + |
1454 | + self.downloading_files_status.SetLabel(info) |
1455 | + |
1456 | + info = "{0} remaining".format( |
1457 | + pretty_time) |
1458 | + |
1459 | + self.downloading_files_info.SetLabel(info) |
1460 | + |
1461 | + self.download_guage.SetValue( 1000 |
1462 | + * self.total_bytes_downloaded |
1463 | + / self.total_bytes_to_download) |
1464 | + |
1465 | + elif update_type == "total bytes": |
1466 | + self.total_bytes_to_download = value |
1467 | + self.total_bytes_downloaded = 0 |
1468 | + self.speeds = [] # keep an array of speeds used to calculate |
1469 | + # the estimated time remaining - by not just using the |
1470 | + # current speed we can stop the ETA bouncing around too much. |
1471 | + |
1472 | + def event_combo_box_release(self, evt): |
1473 | + pass |
1474 | + |
1475 | + def event_combo_box_build(self, evt): |
1476 | + pass |
1477 | + #--- END event(s) --- |
1478 | + |
1479 | + |
1480 | +class TestDriveWizard(wx.wizard.Wizard): |
1481 | + def __init__(self, title): |
1482 | + wx.wizard.Wizard.__init__(self, None, -1, title, wx.NullBitmap) |
1483 | + self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGING, self.on_page_changing) |
1484 | + self.done_startup = False |
1485 | + |
1486 | + def on_page_changing(self, evt): |
1487 | + 'Executed before the page changes.' |
1488 | + |
1489 | + if self.done_startup == False: |
1490 | + self.pages['lmc_settings'].box2.Hide( |
1491 | + self.pages['lmc_settings'].optional_settings_box, |
1492 | + True) |
1493 | + |
1494 | + self.pages['lmc_settings'].box3.Hide( |
1495 | + self.pages['lmc_settings'].confirm_mmc_usage_box, |
1496 | + True) |
1497 | + |
1498 | + self.done_startup = True |
1499 | + |
1500 | + page = evt.GetPage() |
1501 | + |
1502 | + if evt.GetDirection(): # If going forwards... |
1503 | + # Always enable back button if going forwards |
1504 | + self.wizard.FindWindowById(wx.ID_BACKWARD).Enable() |
1505 | + |
1506 | + # If going from a select snapshot or select release page, record |
1507 | + # which we were on so the back button of the next page works |
1508 | + if(self.config.settings['release_or_snapshot'] == "release"): |
1509 | + self.pages['select_os'].SetNext(self.pages['select_release']) |
1510 | + self.pages['select_release'].SetPrev(self.pages['select_os']) |
1511 | + |
1512 | + self.pages['select_release'].SetNext(self.pages['lmc_settings']) |
1513 | + self.pages['lmc_settings'].SetPrev(self.pages['select_release']) |
1514 | + else: |
1515 | + self.pages['select_os'].SetNext(self.pages['select_snapshot']) |
1516 | + self.pages['select_snapshot'].SetPrev(self.pages['select_os']) |
1517 | + |
1518 | + if(page == self.pages['select_os']): |
1519 | + self.pages['select_snapshot'].fill_build_combo_box_for_date( |
1520 | + self.config.settings['build_date']) |
1521 | + |
1522 | + self.pages['select_snapshot'].SetNext(self.pages['lmc_settings']) |
1523 | + self.pages['lmc_settings'].SetPrev(self.pages['select_snapshot']) |
1524 | + |
1525 | + if page == self.pages['hardware_details']: |
1526 | + self.pages['select_os'].fill_os_list() |
1527 | + |
1528 | + if page == self.pages['release_or_snapshot']: |
1529 | + self.pages['hardware_details'].on_page_changing() |
1530 | + |
1531 | + # If about to move into the release selection, make sure the list |
1532 | + # is populated only with releases that are valid with our current |
1533 | + # selection |
1534 | + if( page == self.pages['select_os'] |
1535 | + and self.config.settings['release_or_snapshot'] == "release"): |
1536 | + self.pages['select_release'].update_release_and_build_boxes() |
1537 | + |
1538 | + if page == self.pages['select_snapshot']: |
1539 | + # Execute when exiting page |
1540 | + self.pages['select_snapshot'].update_platform() |
1541 | + |
1542 | + if( page == self.pages['select_snapshot'] |
1543 | + or page == self.pages['select_release']): |
1544 | + self.pages['lmc_settings'].on_activate() |
1545 | + |
1546 | + if page == self.pages['lmc_settings']: |
1547 | + # Forward stays disabled until LMC has finished running |
1548 | + self.wizard.FindWindowById(wx.ID_FORWARD).Disable() |
1549 | + self.pages['run_lmc'].on_activate() |
1550 | + |
1551 | + else: # Always enable the forward button if reversing into a page |
1552 | + self.wizard.FindWindowById(wx.ID_FORWARD).Enable() |
1553 | + |
1554 | + def go(self): |
1555 | + file_handler = FetchImage.FileHandler() |
1556 | + self.config = FetchImage.FetchImageConfig() |
1557 | + self.config.settings["force_download"] = False |
1558 | + self.config.settings['compatable_hwpacks'] = ['foo'] |
1559 | + |
1560 | + # If the settings file and server index need updating, grab them |
1561 | + file_handler.update_files_from_server() |
1562 | + |
1563 | + # Load settings YAML, which defines the parameters we ask for and |
1564 | + # acceptable responses from the user |
1565 | + self.config.read_config(file_handler.settings_file) |
1566 | + |
1567 | + # Using the config we have, look up URLs to download data from in |
1568 | + # the server index |
1569 | + db = FetchImage.DB(file_handler.index_file) |
1570 | + |
1571 | + # Create the wizard and the pages |
1572 | + self.wizard = wiz.Wizard(self, -1, "Linaro Media Builder") |
1573 | + |
1574 | + self.pages = {} |
1575 | + self.pages['release_or_snapshot'] = ReleaseOrSnapshotPage(self.wizard, |
1576 | + self.config) |
1577 | + self.wizard.FitToPage(self.pages['release_or_snapshot']) |
1578 | + (width, height) = self.wizard.GetSize() |
1579 | + |
1580 | + self.pages['hardware_details'] = AboutMyHardwarePage(self.wizard, |
1581 | + self.config, |
1582 | + db, |
1583 | + width) |
1584 | + |
1585 | + self.pages['select_release'] = SelectStableRelease(self.wizard, |
1586 | + self.config, |
1587 | + db, |
1588 | + width) |
1589 | + |
1590 | + self.pages['select_snapshot'] = SelectSnapshot(self.wizard, |
1591 | + self.config, |
1592 | + db, |
1593 | + width) |
1594 | + |
1595 | + self.pages['select_os'] = SelectOS(self.wizard, |
1596 | + self.config, |
1597 | + db, |
1598 | + width) |
1599 | + |
1600 | + self.pages['lmc_settings'] = LMC_settings(self.wizard, |
1601 | + self.config, |
1602 | + db, |
1603 | + width) |
1604 | + |
1605 | + self.pages['run_lmc'] = RunLMC(self.wizard, |
1606 | + self.config, |
1607 | + db, |
1608 | + width) |
1609 | + |
1610 | + self.pages['release_or_snapshot'].SetNext( |
1611 | + self.pages['hardware_details']) |
1612 | + |
1613 | + self.pages['hardware_details'].SetPrev( |
1614 | + self.pages['release_or_snapshot']) |
1615 | + |
1616 | + self.pages['hardware_details'].SetNext(self.pages['select_os']) |
1617 | + self.pages['select_os'].SetPrev(self.pages['hardware_details']) |
1618 | + # Select OS goes to select build, which is customised for |
1619 | + # releases or snapshots |
1620 | + self.pages['lmc_settings'].SetNext(self.pages['run_lmc']) |
1621 | + self.pages['run_lmc'].SetPrev(self.pages['lmc_settings']) |
1622 | + |
1623 | + for (name, page) in self.pages.items(): |
1624 | + self.wizard.GetPageAreaSizer().Add(page) |
1625 | + |
1626 | + self.wizard.RunWizard(self.pages['release_or_snapshot']) |
1627 | + |
1628 | + |
1629 | +def run(): |
1630 | + """Wrapper around the full wizard. Is encapsulated in its own function to |
1631 | + allow a restart to be performed, as described in __main___, easily""" |
1632 | + app = wx.PySimpleApp() # Start the application |
1633 | + if app: |
1634 | + pass # We don't use this directly. Stop pyflakes complaining! |
1635 | + |
1636 | + w = TestDriveWizard('Simple Wizard') |
1637 | + return w.go() |
1638 | + |
1639 | + |
1640 | +class TestURLLookupFunctions(unittest.TestCase): |
1641 | + |
1642 | + def setUp(self): |
1643 | + self.file_handler = FetchImage.FileHandler() |
1644 | + self.file_handler.update_files_from_server() |
1645 | + self.config = FetchImage.FetchImageConfig() |
1646 | + self.config.settings["force_download"] = False |
1647 | + |
1648 | + # Load settings YAML, which defines the parameters we ask for and |
1649 | + # acceptable responses from the user |
1650 | + self.config.read_config(self.file_handler.settings_file) |
1651 | + |
1652 | + # Using the config we have, look up URLs to download data from in the |
1653 | + # server index |
1654 | + self.db = FetchImage.DB(self.file_handler.index_file) |
1655 | + |
1656 | + def test_url_lookup(self): |
1657 | + self.settings = self.config.settings |
1658 | + self.settings['release_or_snapshot'] = "snapshot" |
1659 | + |
1660 | + #--- Test first with a snapshot build lookup --- |
1661 | + # -- Fix a build date -- |
1662 | + # We only need to look up a single snapshot date. Start with today and |
1663 | + # go with the day in the DB, build 0 |
1664 | + today = wx.DateTime() |
1665 | + today.SetToCurrent() |
1666 | + |
1667 | + # -- Don't iterate through platforms for snapshot -- |
1668 | + |
1669 | + # -- Select hardware -- |
1670 | + for self.settings['hardware'] in ( |
1671 | + self.settings['choice']['hardware'].keys()): |
1672 | + |
1673 | + compatable_hwpacks = self.settings['choice']['hwpack'][ |
1674 | + self.settings['hardware']] |
1675 | + |
1676 | + future_date, past_date = self.db.get_next_prev_day_with_builds( |
1677 | + "linaro-alip", |
1678 | + today.FormatISODate().encode('ascii'), |
1679 | + compatable_hwpacks) |
1680 | + |
1681 | + if past_date == None: |
1682 | + # Some hardware packs are not available in the snapshot repo, |
1683 | + # so just skip if they aren't |
1684 | + continue |
1685 | + |
1686 | + builds = self.db.get_binary_builds_on_day_from_db( |
1687 | + "linaro-alip", |
1688 | + past_date, |
1689 | + compatable_hwpacks) |
1690 | + |
1691 | + self.assertTrue(len(builds)) |
1692 | + # If the above assert fails, either the DB is empty, or |
1693 | + # db.get_binary_builds_on_day_from_db failed |
1694 | + |
1695 | + small_date = re.sub('-', '', past_date) |
1696 | + self.settings['build'] = small_date + ":" + "0" |
1697 | + |
1698 | + # -- Iterate through hardware packs -- |
1699 | + for self.settings['hwpack'] in compatable_hwpacks: |
1700 | + |
1701 | + # If hardware pack is available... |
1702 | + if(self.settings['hwpack'] |
1703 | + in self.db.get_hwpacks('snapshot_hwpacks')): |
1704 | + |
1705 | + # -- Iterate through images |
1706 | + os_list = self.db.get_os_list_from('snapshot_binaries') |
1707 | + |
1708 | + for self.settings['image'] in os_list: |
1709 | + if re.search('old', self.settings['image']): |
1710 | + # Directories with old in the name are of no |
1711 | + # interest to us |
1712 | + continue |
1713 | + |
1714 | + # -- Check build which matches these parameters |
1715 | + # (builds that don't match are excluded in UI) -- |
1716 | + if( len(self.db.execute_return_list( |
1717 | + 'select * from snapshot_hwpacks ' |
1718 | + 'where hardware == ? ' |
1719 | + 'and date == ? ' |
1720 | + 'and build == ?', |
1721 | + (self.settings['hwpack'], |
1722 | + small_date, |
1723 | + "0"))) |
1724 | + and len(self.db.execute_return_list( |
1725 | + 'select * from snapshot_binaries ' |
1726 | + 'where image == ? ' |
1727 | + 'and date == ? ' |
1728 | + 'and build == ?', |
1729 | + (self.settings['image'], |
1730 | + small_date, |
1731 | + "0")))): |
1732 | + |
1733 | + # - Run the function under test! - |
1734 | + image_url, hwpack_url = ( |
1735 | + self.db.get_image_and_hwpack_urls(self.settings)) |
1736 | + |
1737 | + self.assertTrue(image_url) |
1738 | + self.assertTrue(hwpack_url) |
1739 | + |
1740 | + #--- Now test release build lookup --- |
1741 | + self.settings['release_or_snapshot'] = "release" |
1742 | + # -- Select hardware -- |
1743 | + for self.settings['hardware'] in ( |
1744 | + self.settings['choice']['hardware'].keys()): |
1745 | + compatable_hwpacks = ( |
1746 | + self.settings['choice']['hwpack'][self.settings['hardware']]) |
1747 | + |
1748 | + # -- Iterate through hardware packs -- |
1749 | + for self.settings['hwpack'] in compatable_hwpacks: |
1750 | + |
1751 | + # If hardware pack is available... |
1752 | + if(self.settings['hwpack'] |
1753 | + in self.db.get_hwpacks('release_hwpacks')): |
1754 | + |
1755 | + # -- Iterate through images |
1756 | + os_list = self.db.get_os_list_from('release_binaries') |
1757 | + |
1758 | + for self.settings['image'] in os_list: |
1759 | + if re.search('old', self.settings['image']): |
1760 | + # Directories with old in the name are of no |
1761 | + # interest to us |
1762 | + continue |
1763 | + |
1764 | + for platform, ignore in ( |
1765 | + self.settings['choice']['platform'].items()): |
1766 | + self.settings['platform'] = platform |
1767 | + |
1768 | + # -- Iterate through available builds -- |
1769 | + builds = self.db.get_builds( |
1770 | + self.settings['platform'], |
1771 | + self.settings['image']) |
1772 | + |
1773 | + for build in builds: |
1774 | + self.settings['build'] = build |
1775 | + |
1776 | + # -- Check build which matches these parameters |
1777 | + #(builds that don't match are excluded in UI)-- |
1778 | + if( len(self.db.execute_return_list( |
1779 | + 'select * from release_hwpacks ' |
1780 | + 'where platform == ? ' |
1781 | + 'and hardware == ? ' |
1782 | + 'and build == ?', |
1783 | + (self.settings['platform'], |
1784 | + self.settings['hwpack'], |
1785 | + self.settings['build']))) |
1786 | + and len(self.db.execute_return_list( |
1787 | + 'select * from release_binaries ' |
1788 | + 'where platform == ? ' |
1789 | + 'and image == ? ' |
1790 | + 'and build == ?', |
1791 | + (self.settings['platform'], |
1792 | + self.settings['image'], |
1793 | + self.settings['build'])))): |
1794 | + |
1795 | + # - Run the function under test! - |
1796 | + image_url, hwpack_url = ( |
1797 | + self.db.get_image_and_hwpack_urls(self.settings)) |
1798 | + self.assertTrue(image_url) |
1799 | + self.assertTrue(hwpack_url) |
1800 | + |
1801 | +if __name__ == '__main__': |
1802 | + run() |
1803 | |
1804 | === modified file 'linaro-android-media-create' |
1805 | --- linaro-android-media-create 2011-05-26 09:16:35 +0000 |
1806 | +++ linaro-android-media-create 2011-07-18 14:39:34 +0000 |
1807 | @@ -133,12 +133,13 @@ |
1808 | unpack_android_binary_tarball(args.system, SYSTEM_DIR) |
1809 | unpack_android_binary_tarball(args.userdata, DATA_DIR) |
1810 | |
1811 | - # Create partitions |
1812 | + # Create partitions |
1813 | boot_partition, system_partition, cache_partition, \ |
1814 | data_partition, sdcard_partition = setup_android_partitions( \ |
1815 | board_config, media, args.image_size, args.boot_label, |
1816 | args.should_create_partitions, args.should_align_boot_part) |
1817 | |
1818 | + board_config.populate_raw_partition(args.device, BOOT_DIR) |
1819 | populate_partition(BOOT_DIR + "/boot", BOOT_DISK, boot_partition) |
1820 | board_config.populate_boot_script(boot_partition, BOOT_DISK, args.consoles) |
1821 | populate_partition(SYSTEM_DIR + "/system", SYSTEM_DISK, system_partition) |
1822 | |
1823 | === modified file 'linaro-hwpack-install' |
1824 | --- linaro-hwpack-install 2011-01-29 16:35:06 +0000 |
1825 | +++ linaro-hwpack-install 2011-07-18 14:39:34 +0000 |
1826 | @@ -36,7 +36,7 @@ |
1827 | FORCE_YES="no" |
1828 | SOURCES_LIST_FILE="${TEMP_DIR}/sources.list" |
1829 | APT_GET_OPTIONS="Dir::Etc::SourceList=${SOURCES_LIST_FILE}" |
1830 | -SUPPORTED_FORMATS="1.0" # A space-separated list of hwpack formats. |
1831 | +SUPPORTED_FORMATS="1.0 2.0" # A space-separated list of hwpack formats. |
1832 | |
1833 | sudo="sudo" |
1834 | if [ $(id -u) -eq 0 ]; then |
1835 | |
1836 | === renamed file 'linaro_image_tools/index_server.py' => 'linaro-image-indexer' |
1837 | --- linaro_image_tools/index_server.py 2011-06-17 18:04:47 +0000 |
1838 | +++ linaro-image-indexer 2011-07-18 14:39:34 +0000 |
1839 | @@ -22,10 +22,10 @@ |
1840 | |
1841 | import os |
1842 | import re |
1843 | -import FetchImage |
1844 | import urlparse |
1845 | import logging |
1846 | import bz2 |
1847 | +import linaro_image_tools.FetchImage |
1848 | |
1849 | RELEASES_WWW_DOCUMENT_ROOT = "/srv/releases.linaro.org/www/platform/" |
1850 | RELEASE_URL = "http://releases.linaro.org/platform/" |
1851 | @@ -41,7 +41,7 @@ |
1852 | def __init__(self): |
1853 | self.reset() |
1854 | self.db_file_name = "server_index" |
1855 | - self.db = FetchImage.DB(self.db_file_name) |
1856 | + self.db = linaro_image_tools.FetchImage.DB(self.db_file_name) |
1857 | |
1858 | def crawl(self): |
1859 | self.db.set_url_parse_info(self.url_parse) |
1860 | @@ -89,8 +89,6 @@ |
1861 | url_chunks_): |
1862 | |
1863 | if(not id_ in self.url_parse): |
1864 | - |
1865 | - print base_dir_ |
1866 | self.url_parse[id_] = {"base_dir": base_dir_, |
1867 | "base_url": base_url_, |
1868 | "url_validator": url_validator_, |
1869 | |
1870 | === modified file 'linaro-media-create' |
1871 | --- linaro-media-create 2011-06-21 09:16:28 +0000 |
1872 | +++ linaro-media-create 2011-07-18 14:39:34 +0000 |
1873 | @@ -104,6 +104,7 @@ |
1874 | ROOT_DISK = os.path.join(TMP_DIR, 'root-disc') |
1875 | |
1876 | board_config = board_configs[args.board] |
1877 | + board_config.set_metadata(args.hwpacks) |
1878 | |
1879 | ensure_required_commands(args) |
1880 | |
1881 | |
1882 | === modified file 'linaro_image_tools/FetchImage.py' |
1883 | --- linaro_image_tools/FetchImage.py 2011-06-17 18:04:47 +0000 |
1884 | +++ linaro_image_tools/FetchImage.py 2011-07-18 14:39:34 +0000 |
1885 | @@ -52,15 +52,6 @@ |
1886 | "image-tools", |
1887 | "fetch_image") |
1888 | |
1889 | - class DummyEventHandler(): |
1890 | - """Just a sink for events if no event handler is provided to |
1891 | - create_media""" |
1892 | - def event_start(self, event): |
1893 | - pass |
1894 | - |
1895 | - def event_end(self, event): |
1896 | - pass |
1897 | - |
1898 | def has_key_and_evaluates_True(self, dictionary, key): |
1899 | return bool(key in dictionary and dictionary[key]) |
1900 | |
1901 | @@ -72,17 +63,15 @@ |
1902 | list.append(setting_name) |
1903 | list.append(dictionary[key]) |
1904 | |
1905 | - def create_media(self, image_url, hwpack_url, settings, tools_dir, |
1906 | - run_in_gui=False, event_handler=None): |
1907 | - """Create a command line for linaro-media-create based on the settings |
1908 | - provided then run linaro-media-create, either in a separate thread |
1909 | - (GUI mode) or in the current one (CLI mode).""" |
1910 | + def build_lmc_command(self, |
1911 | + binary_file, |
1912 | + hwpack_file, |
1913 | + settings, |
1914 | + tools_dir, |
1915 | + run_in_gui=False): |
1916 | |
1917 | import linaro_image_tools.utils |
1918 | |
1919 | - if event_handler == None: |
1920 | - event_handler = self.DummyEventHandler() |
1921 | - |
1922 | args = [] |
1923 | args.append("pkexec") |
1924 | |
1925 | @@ -100,41 +89,6 @@ |
1926 | if run_in_gui: |
1927 | args.append("--nocheck-mmc") |
1928 | |
1929 | - event_handler.event_start("download OS") |
1930 | - try: |
1931 | - binary_file = self.download(image_url, |
1932 | - settings["force_download"], |
1933 | - show_wx_progress=run_in_gui, |
1934 | - wx_progress_title= |
1935 | - "Downloading file 1 of 2") |
1936 | - except Exception: |
1937 | - # Download error. Hardly matters what, we can't continue. |
1938 | - print "Unexpected error:", sys.exc_info()[0] |
1939 | - logging.error("Unable to download " + image_url + " - aborting.") |
1940 | - event_handler.event_end("download OS") |
1941 | - |
1942 | - if binary_file == None: # User hit cancel when downloading |
1943 | - sys.exit(0) |
1944 | - |
1945 | - event_handler.event_start("download hwpack") |
1946 | - try: |
1947 | - hwpack_file = self.download(hwpack_url, |
1948 | - settings["force_download"], |
1949 | - show_wx_progress=run_in_gui, |
1950 | - wx_progress_title= |
1951 | - "Downloading file 2 of 2") |
1952 | - except Exception: |
1953 | - # Download error. Hardly matters what, we can't continue. |
1954 | - print "Unexpected error:", sys.exc_info()[0] |
1955 | - logging.error("Unable to download " + hwpack_url + " - aborting.") |
1956 | - event_handler.event_end("download hwpack") |
1957 | - |
1958 | - if hwpack_file == None: # User hit cancel when downloading |
1959 | - sys.exit(0) |
1960 | - |
1961 | - logging.info("Have downloaded OS binary to", binary_file, |
1962 | - "and hardware pack to", hwpack_file) |
1963 | - |
1964 | if 'rootfs' in settings and settings['rootfs']: |
1965 | args.append("--rootfs") |
1966 | args.append(settings['rootfs']) |
1967 | @@ -157,34 +111,74 @@ |
1968 | args.append("--hwpack") |
1969 | args.append(hwpack_file) |
1970 | |
1971 | - logging.info(args) |
1972 | - |
1973 | - if run_in_gui: |
1974 | - self.lmcargs = args |
1975 | - self.event_handler = event_handler |
1976 | - self.started_lmc = False |
1977 | - return |
1978 | - |
1979 | - else: |
1980 | - self.create_process = subprocess.Popen(args) |
1981 | - self.create_process.wait() |
1982 | + logging.info(" ".join(args)) |
1983 | + |
1984 | + return args |
1985 | + |
1986 | + def create_media(self, image_url, hwpack_url, settings, tools_dir): |
1987 | + """Create a command line for linaro-media-create based on the settings |
1988 | + provided then run linaro-media-create, either in a separate thread |
1989 | + (GUI mode) or in the current one (CLI mode).""" |
1990 | + |
1991 | + to_download = [(image_url, "OS"), |
1992 | + (hwpack_url, "hwpack")] |
1993 | + downloaded_files = self.download_files(to_download, |
1994 | + settings) |
1995 | + |
1996 | + args = self.build_lmc_command(downloaded_files['OS'], |
1997 | + downloaded_files['hwpack'], |
1998 | + settings, |
1999 | + tools_dir) |
2000 | + |
2001 | + self.create_process = subprocess.Popen(args) |
2002 | + self.create_process.wait() |
2003 | |
2004 | class LinaroMediaCreate(threading.Thread): |
2005 | """Thread class for running linaro-media-create""" |
2006 | - def __init__(self, event_handler, lmcargs, event_queue): |
2007 | + def __init__(self, |
2008 | + image_url, |
2009 | + hwpack_url, |
2010 | + file_handler, |
2011 | + event_queue, |
2012 | + settings, |
2013 | + tools_dir): |
2014 | + |
2015 | threading.Thread.__init__(self) |
2016 | - self.event_handler = event_handler |
2017 | - self.lmcargs = lmcargs |
2018 | - self.event_queue = event_queue |
2019 | + |
2020 | + self.image_url = image_url |
2021 | + self.hwpack_url = hwpack_url |
2022 | + self.file_handler = file_handler |
2023 | + self.event_queue = event_queue |
2024 | + self.settings = settings |
2025 | + self.tools_dir = tools_dir |
2026 | |
2027 | def run(self): |
2028 | - """Start linaro-media-create and look for lines in the output that: |
2029 | - 1. Tell us that an event has happened that we can use to update the |
2030 | - UI progress. |
2031 | - 2. Tell us that linaro-media-create is asking a question that needs |
2032 | - to be re-directed to the GUI""" |
2033 | - |
2034 | - self.create_process = subprocess.Popen(self.lmcargs, |
2035 | + """ |
2036 | + 1. Download required files. |
2037 | + 2. Build linaro-media-create command |
2038 | + 3. Start linaro-media-create and look for lines in the output that: |
2039 | + 1. Tell us that an event has happened that we can use to update |
2040 | + the UI progress. |
2041 | + 2. Tell us that linaro-media-create is asking a question that |
2042 | + needs to be re-directed to the GUI |
2043 | + """ |
2044 | + |
2045 | + to_download = [(self.image_url, "OS"), |
2046 | + (self.hwpack_url, "hwpack")] |
2047 | + |
2048 | + downloaded_files = self.file_handler.download_files( |
2049 | + to_download, |
2050 | + self.settings, |
2051 | + self.event_queue) |
2052 | + |
2053 | + lmc_command = self.file_handler.build_lmc_command( |
2054 | + downloaded_files['OS'], |
2055 | + downloaded_files['hwpack'], |
2056 | + self.settings, |
2057 | + self.tools_dir, |
2058 | + True) |
2059 | + |
2060 | + self.create_process = subprocess.Popen(lmc_command, |
2061 | stdin=subprocess.PIPE, |
2062 | stdout=subprocess.PIPE, |
2063 | stderr=subprocess.STDOUT) |
2064 | @@ -262,18 +256,6 @@ |
2065 | print >> self.create_process.stdin, text |
2066 | self.waiting_for_event_response = False |
2067 | |
2068 | - def start_lmc_gui_thread(self, event_queue): |
2069 | - self.lmc_thread = self.LinaroMediaCreate(self.event_handler, |
2070 | - self.lmcargs, event_queue) |
2071 | - self.lmc_thread.start() |
2072 | - |
2073 | - def kill_create_media(self): |
2074 | - pass # TODO: Something! |
2075 | - # Need to make sure all child processes are terminated. |
2076 | - |
2077 | - def send_to_create_process(self, text): |
2078 | - self.lmc_thread.send_to_create_process(text) |
2079 | - |
2080 | def name_and_path_from_url(self, url): |
2081 | """Return the file name and the path at which the file will be stored |
2082 | on the local system based on the URL we are downloading from""" |
2083 | @@ -290,34 +272,94 @@ |
2084 | |
2085 | return file_name, file_path |
2086 | |
2087 | - def create_wx_progress(self, title, message): |
2088 | - """Create a standard WX progrss dialog""" |
2089 | - import wx |
2090 | - self.dlg = wx.ProgressDialog(title, |
2091 | - message, |
2092 | - maximum=1000, |
2093 | - parent=None, |
2094 | - style=wx.PD_CAN_ABORT |
2095 | - | wx.PD_APP_MODAL |
2096 | - | wx.PD_ELAPSED_TIME |
2097 | - | wx.PD_AUTO_HIDE |
2098 | - | wx.PD_REMAINING_TIME) |
2099 | - |
2100 | - def timer_ping(self): |
2101 | - self.update_wx_process(self.download_count) |
2102 | - |
2103 | - def update_wx_progress(self, count): |
2104 | - self.download_count = count |
2105 | - (self.do_download, skip) = self.dlg.Update(count) |
2106 | - |
2107 | - def download(self, url, force_download=False, |
2108 | - show_wx_progress=False, wx_progress_title=None): |
2109 | + def urllib2_open(self, url): |
2110 | + maxtries = 10 |
2111 | + for trycount in range(0, maxtries): |
2112 | + try: |
2113 | + response = urllib2.urlopen(url) |
2114 | + except: |
2115 | + if trycount < maxtries - 1: |
2116 | + print "Unable to connect to", url, "retrying in 5 seconds..." |
2117 | + time.sleep(5) |
2118 | + continue |
2119 | + else: |
2120 | + print "Connect failed:", url |
2121 | + raise |
2122 | + return None |
2123 | + else: |
2124 | + return response |
2125 | + |
2126 | + return None |
2127 | + |
2128 | + def download_files(self, |
2129 | + downloads_list, |
2130 | + settings, |
2131 | + event_queue=None): |
2132 | + """ |
2133 | + Download files specified in the downloads_list, which is a list of |
2134 | + url, name tuples. |
2135 | + """ |
2136 | + |
2137 | + downloaded_files = {} |
2138 | + |
2139 | + bytes_to_download = 0 |
2140 | + |
2141 | + for url, name in downloads_list: |
2142 | + file_name, file_path = self.name_and_path_from_url(url) |
2143 | + |
2144 | + file_name = file_path + os.sep + file_name |
2145 | + if os.path.exists(file_name): |
2146 | + continue # If file already exists, don't download it |
2147 | + |
2148 | + response = self.urllib2_open(url) |
2149 | + if response: |
2150 | + bytes_to_download += int(response.info() |
2151 | + .getheader('Content-Length').strip()) |
2152 | + response.close() |
2153 | + |
2154 | + if event_queue: |
2155 | + event_queue.put(("update", |
2156 | + "download", |
2157 | + "total bytes", |
2158 | + bytes_to_download)) |
2159 | + |
2160 | + for url, name in downloads_list: |
2161 | + if event_queue: |
2162 | + event_queue.put(("start", "download " + name)) |
2163 | + event_queue.put(("update", |
2164 | + "download", |
2165 | + "name", |
2166 | + name)) |
2167 | + |
2168 | + path = None |
2169 | + try: |
2170 | + path = self.download(url, |
2171 | + event_queue, |
2172 | + settings["force_download"]) |
2173 | + except Exception: |
2174 | + # Download error. Hardly matters what, we can't continue. |
2175 | + print "Unexpected error:", sys.exc_info()[0] |
2176 | + logging.error("Unable to download " + url + " - aborting.") |
2177 | + |
2178 | + if event_queue: |
2179 | + event_queue.put(("end", "download " + name)) |
2180 | + |
2181 | + if path == None: # User hit cancel when downloading |
2182 | + sys.exit(0) |
2183 | + |
2184 | + downloaded_files[name] = path |
2185 | + logging.info("Have downloaded {0} to {1}".format(name, path)) |
2186 | + |
2187 | + return downloaded_files |
2188 | + |
2189 | + def download(self, |
2190 | + url, |
2191 | + event_queue, |
2192 | + force_download=False): |
2193 | """Downloads the file requested buy URL to the local cache and returns |
2194 | the full path to the downloaded file""" |
2195 | |
2196 | file_name, file_path = self.name_and_path_from_url(url) |
2197 | - |
2198 | - just_file_name = file_name |
2199 | file_name = file_path + os.sep + file_name |
2200 | |
2201 | if not os.path.isdir(file_path): |
2202 | @@ -328,23 +370,9 @@ |
2203 | "--force-download to override).") |
2204 | return file_name |
2205 | |
2206 | - logging.info("Fetching", url) |
2207 | + logging.info("Fetching " + url) |
2208 | |
2209 | - maxtries = 10 |
2210 | - for trycount in range(0, maxtries): |
2211 | - try: |
2212 | - response = urllib2.urlopen(url) |
2213 | - except: |
2214 | - if trycount < maxtries - 1: |
2215 | - print "Unable to download", url, "retrying in 5 seconds..." |
2216 | - time.sleep(5) |
2217 | - continue |
2218 | - else: |
2219 | - print "Download failed for some reason:", url |
2220 | - raise |
2221 | - return |
2222 | - else: |
2223 | - break |
2224 | + response = self.urllib2_open(url) |
2225 | |
2226 | self.do_download = True |
2227 | file_out = open(file_name, 'w') |
2228 | @@ -356,28 +384,22 @@ |
2229 | |
2230 | if show_progress: |
2231 | chunk_size = download_size_in_bytes / 1000 |
2232 | - if show_wx_progress: |
2233 | - if wx_progress_title == None: |
2234 | - wx_progress_title = "Downloading File" |
2235 | - self.create_wx_progress(wx_progress_title, |
2236 | - "Downloading " + just_file_name) |
2237 | - else: |
2238 | + if not event_queue: |
2239 | print "Fetching", url |
2240 | else: |
2241 | chunk_size = download_size_in_bytes |
2242 | |
2243 | - if show_progress and show_wx_progress: |
2244 | - # Just update the download box before we get the first % |
2245 | - self.update_wx_progress(0) |
2246 | - |
2247 | printed_progress = False |
2248 | while self.do_download: |
2249 | chunk = response.read(chunk_size) |
2250 | if len(chunk): |
2251 | # Print a % download complete so we don't get too bored |
2252 | if show_progress: |
2253 | - if show_wx_progress: |
2254 | - self.update_wx_progress(chunks_downloaded) |
2255 | + if event_queue: |
2256 | + event_queue.put(("update", |
2257 | + "download", |
2258 | + "progress", |
2259 | + len(chunk))) |
2260 | else: |
2261 | # Have 1000 chunks so div by 10 to get %... |
2262 | sys.stdout.write("\r%d%%" % (chunks_downloaded / 10)) |
2263 | @@ -400,7 +422,7 @@ |
2264 | |
2265 | return file_name |
2266 | |
2267 | - def download_if_old(self, url, force_download, show_wx_progress=False): |
2268 | + def download_if_old(self, url, event_queue, force_download): |
2269 | file_name, file_path = self.name_and_path_from_url(url) |
2270 | |
2271 | file_path_and_name = file_path + os.sep + file_name |
2272 | @@ -411,25 +433,25 @@ |
2273 | force_download = (force_download == True |
2274 | or ( time.mktime(time.localtime()) |
2275 | - os.path.getmtime(file_path_and_name) |
2276 | - > 60 * 60 * 24)) |
2277 | + > 60 * 60)) |
2278 | except OSError: |
2279 | force_download = True # File not found... |
2280 | |
2281 | - return self.download(url, force_download, show_wx_progress) |
2282 | + return self.download(url, event_queue, force_download) |
2283 | |
2284 | def update_files_from_server(self, force_download=False, |
2285 | - show_wx_progress=False): |
2286 | + event_queue=None): |
2287 | |
2288 | - settings_url = "http://z.nanosheep.org/fetch_image_settings.yaml" |
2289 | - server_index_url = "http://z.nanosheep.org/server_index.bz2" |
2290 | + settings_url = "http://releases.linaro.org/fetch_image/fetch_image_settings.yaml" |
2291 | + server_index_url = "http://releases.linaro.org/fetch_image/server_index.bz2" |
2292 | |
2293 | self.settings_file = self.download_if_old(settings_url, |
2294 | - force_download, |
2295 | - show_wx_progress) |
2296 | + event_queue, |
2297 | + force_download) |
2298 | |
2299 | self.index_file = self.download_if_old(server_index_url, |
2300 | - force_download, |
2301 | - show_wx_progress) |
2302 | + event_queue, |
2303 | + force_download) |
2304 | |
2305 | zip_search = re.search(r"^(.*)\.bz2$", self.index_file) |
2306 | |
2307 | @@ -484,9 +506,9 @@ |
2308 | self.settings['UI']['reverse-translate'][value] = key |
2309 | |
2310 | def parse_args(self, args): |
2311 | - parser = argparse.ArgumentParser(description= |
2312 | - "Create a board image, first " |
2313 | - "downloading any required files.") |
2314 | + parser = argparse.ArgumentParser(description="Create a board image, " |
2315 | + "first downloading any required " |
2316 | + "files.") |
2317 | |
2318 | for (key, value) in self.settings['choice'].items(): |
2319 | parser.add_argument( |
2320 | @@ -983,7 +1005,7 @@ |
2321 | loop_date_increment = -one_day |
2322 | |
2323 | test_date[in_the] = current_date |
2324 | - |
2325 | + |
2326 | while test_date[in_the] <= max_search_date: |
2327 | test_date[in_the] += loop_date_increment |
2328 | |
2329 | |
2330 | === modified file 'linaro_image_tools/fetch_image_settings.yaml' |
2331 | --- linaro_image_tools/fetch_image_settings.yaml 2011-06-17 18:04:47 +0000 |
2332 | +++ linaro_image_tools/fetch_image_settings.yaml 2011-07-18 14:39:34 +0000 |
2333 | @@ -45,6 +45,7 @@ |
2334 | # u8500: U8500 |
2335 | overo: Overo |
2336 | smdkv310: S5PV310 |
2337 | + origen: Origen |
2338 | |
2339 | hwpack: |
2340 | beagle: |
2341 | @@ -88,6 +89,9 @@ |
2342 | - lt-s5pv310 |
2343 | - s5pv310 |
2344 | |
2345 | + origen: |
2346 | + - lt-origen |
2347 | + |
2348 | image: |
2349 | - alip |
2350 | - developer |
2351 | |
2352 | === modified file 'linaro_image_tools/hwpack/config.py' |
2353 | --- linaro_image_tools/hwpack/config.py 2011-06-20 13:46:16 +0000 |
2354 | +++ linaro_image_tools/hwpack/config.py 2011-07-18 14:39:34 +0000 |
2355 | @@ -22,7 +22,7 @@ |
2356 | import ConfigParser |
2357 | import re |
2358 | |
2359 | -from hardwarepack_format import ( |
2360 | +from linaro_image_tools.hwpack.hardwarepack_format import ( |
2361 | HardwarePackFormatV1, |
2362 | HardwarePackFormatV2, |
2363 | ) |
2364 | @@ -42,7 +42,7 @@ |
2365 | SOURCES_ENTRY_KEY = "sources-entry" |
2366 | PACKAGES_KEY = "packages" |
2367 | PACKAGE_REGEX = NAME_REGEX |
2368 | - PATH_REGEX = r"[a-z0-9][a-z0-9+\-./]+$" |
2369 | + PATH_REGEX = r"[a-z0-9][a-z0-9+\-./_]+$" |
2370 | ORIGIN_KEY = "origin" |
2371 | MAINTAINER_KEY = "maintainer" |
2372 | ARCHITECTURES_KEY = "architectures" |
2373 | @@ -58,6 +58,16 @@ |
2374 | PARTITION_LAYOUT_KEY = "partition_layout" |
2375 | MMC_ID_KEY = "mmc_id" |
2376 | FORMAT_KEY = "format" |
2377 | + BOOT_MIN_SIZE_KEY = "boot_min_size" |
2378 | + ROOT_MIN_SIZE_KEY = "root_min_size" |
2379 | + LOADER_MIN_SIZE_KEY = "loader_min_size" |
2380 | + |
2381 | + DEFINED_PARTITION_LAYOUTS = [ |
2382 | + 'bootfs16_rootfs', |
2383 | + 'bootfs_rootfs', |
2384 | + #'reserved_bootfs_rootfs', |
2385 | + ] |
2386 | + |
2387 | |
2388 | def __init__(self, fp): |
2389 | """Create a Config. |
2390 | @@ -93,6 +103,9 @@ |
2391 | self._validate_wireless_interfaces() |
2392 | self._validate_partition_layout() |
2393 | self._validate_mmc_id() |
2394 | + self._validate_boot_min_size() |
2395 | + self._validate_root_min_size() |
2396 | + self._validate_loader_min_size() |
2397 | |
2398 | self._validate_sections() |
2399 | |
2400 | @@ -217,6 +230,30 @@ |
2401 | return self._get_option_from_main_section(self.MMC_ID_KEY) |
2402 | |
2403 | @property |
2404 | + def root_min_size(self): |
2405 | + """Minimum size of the root partition, in MiB. |
2406 | + |
2407 | + An int. |
2408 | + """ |
2409 | + return self._get_option_from_main_section(self.ROOT_MIN_SIZE_KEY) |
2410 | + |
2411 | + @property |
2412 | + def boot_min_size(self): |
2413 | + """Minimum size of the boot partition, in MiB. |
2414 | + |
2415 | + An int. |
2416 | + """ |
2417 | + return self._get_option_from_main_section(self.BOOT_MIN_SIZE_KEY) |
2418 | + |
2419 | + @property |
2420 | + def loader_min_size(self): |
2421 | + """Minimum size of the optional loader partition, in MiB. |
2422 | + |
2423 | + An int. |
2424 | + """ |
2425 | + return self._get_option_from_main_section(self.LOADER_MIN_SIZE_KEY) |
2426 | + |
2427 | + @property |
2428 | def origin(self): |
2429 | """The origin that should be recorded in the hwpack. |
2430 | |
2431 | @@ -375,17 +412,12 @@ |
2432 | pass |
2433 | |
2434 | def _validate_partition_layout(self): |
2435 | - defined_partition_layouts = [ |
2436 | - #'bootfs16_rootfs', |
2437 | - 'bootfs_rootfs', |
2438 | - #'reserved_bootfs_rootfs', |
2439 | - ] |
2440 | - if self.partition_layout not in defined_partition_layouts: |
2441 | + if self.partition_layout not in self.DEFINED_PARTITION_LAYOUTS: |
2442 | raise HwpackConfigError( |
2443 | "Undefined partition layout %s in the [%s] section. " |
2444 | "Valid partition layouts are %s." |
2445 | % (self.partition_layout, self.MAIN_SECTION, |
2446 | - ", ".join(defined_partition_layouts))) |
2447 | + ", ".join(self.DEFINED_PARTITION_LAYOUTS))) |
2448 | |
2449 | def _validate_mmc_id(self): |
2450 | mmc_id = self.mmc_id |
2451 | @@ -396,6 +428,36 @@ |
2452 | except: |
2453 | raise HwpackConfigError("Invalid mmc id %s" % (mmc_id)) |
2454 | |
2455 | + def _validate_root_min_size(self): |
2456 | + root_min_size = self.root_min_size |
2457 | + if root_min_size is None: |
2458 | + return |
2459 | + try: |
2460 | + assert int(root_min_size) > 0 |
2461 | + except: |
2462 | + raise HwpackConfigError( |
2463 | + "Invalid root min size %s" % (root_min_size)) |
2464 | + |
2465 | + def _validate_boot_min_size(self): |
2466 | + boot_min_size = self.boot_min_size |
2467 | + if boot_min_size is None: |
2468 | + return |
2469 | + try: |
2470 | + assert int(boot_min_size) > 0 |
2471 | + except: |
2472 | + raise HwpackConfigError( |
2473 | + "Invalid boot min size %s" % (boot_min_size)) |
2474 | + |
2475 | + def _validate_loader_min_size(self): |
2476 | + loader_min_size = self.loader_min_size |
2477 | + if loader_min_size is None: |
2478 | + return |
2479 | + try: |
2480 | + assert int(loader_min_size) > 0 |
2481 | + except: |
2482 | + raise HwpackConfigError( |
2483 | + "Invalid loader min size %s" % (loader_min_size)) |
2484 | + |
2485 | def _validate_include_debs(self): |
2486 | try: |
2487 | self.include_debs |
2488 | |
2489 | === modified file 'linaro_image_tools/hwpack/hardwarepack.py' |
2490 | --- linaro_image_tools/hwpack/hardwarepack.py 2011-06-20 13:46:16 +0000 |
2491 | +++ linaro_image_tools/hwpack/hardwarepack.py 2011-07-18 14:39:34 +0000 |
2492 | @@ -80,7 +80,8 @@ |
2493 | def add_v2_config(self, serial_tty=None, kernel_addr=None, initrd_addr=None, |
2494 | load_addr=None, fdt=None, wired_interfaces=[], |
2495 | wireless_interfaces=[], partition_layout=None, |
2496 | - mmc_id=None): |
2497 | + mmc_id=None, boot_min_size=None, root_min_size=None, |
2498 | + loader_min_size=None): |
2499 | """Add fields that are specific to the new format. |
2500 | |
2501 | These fields are not present in earlier config files. |
2502 | @@ -94,6 +95,9 @@ |
2503 | self.wireless_interfaces = wireless_interfaces |
2504 | self.partition_layout = partition_layout |
2505 | self.mmc_id = mmc_id |
2506 | + self.boot_min_size = boot_min_size |
2507 | + self.root_min_size = root_min_size |
2508 | + self.loader_min_size = loader_min_size |
2509 | |
2510 | @classmethod |
2511 | def from_config(cls, config, version, architecture): |
2512 | @@ -126,7 +130,10 @@ |
2513 | wired_interfaces=config.wired_interfaces, |
2514 | wireless_interfaces=config.wireless_interfaces, |
2515 | partition_layout=config.partition_layout, |
2516 | - mmc_id=config.mmc_id) |
2517 | + mmc_id=config.mmc_id, |
2518 | + boot_min_size=config.boot_min_size, |
2519 | + root_min_size=config.root_min_size, |
2520 | + loader_min_size=config.loader_min_size) |
2521 | return metadata |
2522 | |
2523 | def __str__(self): |
2524 | @@ -163,6 +170,13 @@ |
2525 | metadata += "PARTITION_LAYOUT=%s\n" % self.partition_layout |
2526 | if self.mmc_id is not None: |
2527 | metadata += "MMC_ID=%s\n" % self.mmc_id |
2528 | + if self.boot_min_size is not None: |
2529 | + metadata += "BOOT_MIN_SIZE=%s\n" % self.boot_min_size |
2530 | + if self.root_min_size is not None: |
2531 | + metadata += "ROOT_MIN_SIZE=%s\n" % self.root_min_size |
2532 | + if self.loader_min_size is not None: |
2533 | + metadata += "LOADER_MIN_SIZE=%s\n" % self.loader_min_size |
2534 | + |
2535 | return metadata |
2536 | |
2537 | |
2538 | |
2539 | === modified file 'linaro_image_tools/hwpack/tests/test_config.py' |
2540 | --- linaro_image_tools/hwpack/tests/test_config.py 2011-06-17 12:28:43 +0000 |
2541 | +++ linaro_image_tools/hwpack/tests/test_config.py 2011-07-18 14:39:34 +0000 |
2542 | @@ -216,13 +216,16 @@ |
2543 | self.assertValidationError("Invalid path: ~~", config) |
2544 | |
2545 | def test_validate_partition_layout(self): |
2546 | - config = self.get_config(self.valid_start_v2 + |
2547 | - "u-boot-package = u-boot-linaro-s5pv310\n" \ |
2548 | - "u-boot-file = u-boot.bin\n" \ |
2549 | - "partition_layout = apafs_bananfs\n") |
2550 | + partition_layout = 'apafs_bananfs' |
2551 | + config = self.get_config(self.valid_start_v2 + "u-boot-package = " \ |
2552 | + "u-boot-linaro-s5pv310\nu-boot-file = " \ |
2553 | + "u-boot.bin\npartition_layout = %s\n" % \ |
2554 | + partition_layout) |
2555 | self.assertValidationError( |
2556 | - "Undefined partition layout apafs_bananfs in the [hwpack] " \ |
2557 | - "section. Valid partition layouts are bootfs_rootfs.", config) |
2558 | + "Undefined partition layout %s in the [%s] section. " |
2559 | + "Valid partition layouts are %s." |
2560 | + % (partition_layout, 'hwpack', |
2561 | + ", ".join(config.DEFINED_PARTITION_LAYOUTS)), config) |
2562 | |
2563 | def test_validate_wired_interfaces(self): |
2564 | self.assertTrue("XXX What is an invalid interface name?") |
2565 | @@ -246,6 +249,21 @@ |
2566 | "mmc_id = x\n") |
2567 | self.assertValidationError("Invalid mmc id x", config) |
2568 | |
2569 | + def test_validate_boot_min_size(self): |
2570 | + config = self.get_config(self.valid_complete_v2 + |
2571 | + "boot_min_size = x\n") |
2572 | + self.assertValidationError("Invalid boot min size x", config) |
2573 | + |
2574 | + def test_validate_root_min_size(self): |
2575 | + config = self.get_config(self.valid_complete_v2 + |
2576 | + "root_min_size = x\n") |
2577 | + self.assertValidationError("Invalid root min size x", config) |
2578 | + |
2579 | + def test_validate_loader_min_size(self): |
2580 | + config = self.get_config(self.valid_complete_v2 + |
2581 | + "loader_min_size = x\n") |
2582 | + self.assertValidationError("Invalid loader min size x", config) |
2583 | + |
2584 | def test_validate_kernel_addr(self): |
2585 | config = self.get_config(self.valid_complete_v2 + |
2586 | "kernel_addr = 0x8000000\n") |
2587 | @@ -327,6 +345,27 @@ |
2588 | config.validate() |
2589 | self.assertEqual("1", config.mmc_id) |
2590 | |
2591 | + def test_boot_min_size(self): |
2592 | + config = self.get_config(self.valid_complete_v2 + |
2593 | + "boot_min_size = 50\n" + |
2594 | + self.valid_end) |
2595 | + config.validate() |
2596 | + self.assertEqual("50", config.boot_min_size) |
2597 | + |
2598 | + def test_root_min_size(self): |
2599 | + config = self.get_config(self.valid_complete_v2 + |
2600 | + "root_min_size = 50\n" + |
2601 | + self.valid_end) |
2602 | + config.validate() |
2603 | + self.assertEqual("50", config.root_min_size) |
2604 | + |
2605 | + def test_loader_min_size(self): |
2606 | + config = self.get_config(self.valid_complete_v2 + |
2607 | + "loader_min_size = 2\n" + |
2608 | + self.valid_end) |
2609 | + config.validate() |
2610 | + self.assertEqual("2", config.loader_min_size) |
2611 | + |
2612 | def test_kernel_addr(self): |
2613 | config = self.get_config(self.valid_complete_v2 + |
2614 | "kernel_addr = 0x80000000\n" + |
2615 | |
2616 | === modified file 'linaro_image_tools/hwpack/tests/test_hardwarepack.py' |
2617 | --- linaro_image_tools/hwpack/tests/test_hardwarepack.py 2011-06-17 15:10:49 +0000 |
2618 | +++ linaro_image_tools/hwpack/tests/test_hardwarepack.py 2011-07-18 14:39:34 +0000 |
2619 | @@ -183,6 +183,33 @@ |
2620 | "MMC_ID=1\n", |
2621 | str(metadata)) |
2622 | |
2623 | + def test_str_with_boot_min_size(self): |
2624 | + metadata = Metadata("ahwpack", "4", "armel", |
2625 | + format=HardwarePackFormatV2()) |
2626 | + metadata.add_v2_config(boot_min_size='50') |
2627 | + self.assertEqual( |
2628 | + "NAME=ahwpack\nVERSION=4\nARCHITECTURE=armel\n" |
2629 | + "BOOT_MIN_SIZE=50\n", |
2630 | + str(metadata)) |
2631 | + |
2632 | + def test_str_with_root_min_size(self): |
2633 | + metadata = Metadata("ahwpack", "4", "armel", |
2634 | + format=HardwarePackFormatV2()) |
2635 | + metadata.add_v2_config(root_min_size='100') |
2636 | + self.assertEqual( |
2637 | + "NAME=ahwpack\nVERSION=4\nARCHITECTURE=armel\n" |
2638 | + "ROOT_MIN_SIZE=100\n", |
2639 | + str(metadata)) |
2640 | + |
2641 | + def test_str_with_loader_min_size(self): |
2642 | + metadata = Metadata("ahwpack", "4", "armel", |
2643 | + format=HardwarePackFormatV2()) |
2644 | + metadata.add_v2_config(loader_min_size='1') |
2645 | + self.assertEqual( |
2646 | + "NAME=ahwpack\nVERSION=4\nARCHITECTURE=armel\n" |
2647 | + "LOADER_MIN_SIZE=1\n", |
2648 | + str(metadata)) |
2649 | + |
2650 | def test_from_config(self): |
2651 | class Config: |
2652 | name = "foo" |
2653 | |
2654 | === modified file 'linaro_image_tools/media_create/android_boards.py' |
2655 | --- linaro_image_tools/media_create/android_boards.py 2011-04-22 15:09:08 +0000 |
2656 | +++ linaro_image_tools/media_create/android_boards.py 2011-07-18 14:39:34 +0000 |
2657 | @@ -28,6 +28,8 @@ |
2658 | from linaro_image_tools.media_create.boards import PART_ALIGN_S |
2659 | from linaro_image_tools.media_create.boards import BeagleConfig |
2660 | from linaro_image_tools.media_create.boards import PandaConfig |
2661 | +from linaro_image_tools.media_create.boards import SnowballSdConfig |
2662 | +from linaro_image_tools.media_create.boards import SnowballEmmcConfig |
2663 | from linaro_image_tools.media_create.boards import ( |
2664 | align_up, |
2665 | align_partition, |
2666 | @@ -37,6 +39,7 @@ |
2667 | from linaro_image_tools import cmd_runner |
2668 | import os |
2669 | |
2670 | + |
2671 | class AndroidBoardConfig(object): |
2672 | @classmethod |
2673 | def _get_bootargs(cls, consoles): |
2674 | @@ -78,7 +81,7 @@ |
2675 | as_root=True).wait() |
2676 | |
2677 | boot_env = cls._get_boot_env(consoles) |
2678 | - cmdline_filepath = os.path.join(boot_disk, "cmdline") |
2679 | + cmdline_filepath = os.path.join(boot_disk, "cmdline") |
2680 | cmdline_file = open(cmdline_filepath, 'r') |
2681 | android_kernel_cmdline = cmdline_file.read() |
2682 | boot_env['bootargs'] = boot_env['bootargs'] + ' ' + \ |
2683 | @@ -96,7 +99,8 @@ |
2684 | pass |
2685 | |
2686 | @classmethod |
2687 | - def get_sfdisk_cmd(cls, should_align_boot_part=False): |
2688 | + def get_sfdisk_cmd(cls, should_align_boot_part=False, |
2689 | + start_addr=0, extra_part=False): |
2690 | if cls.fat_size == 32: |
2691 | partition_type = '0x0C' |
2692 | else: |
2693 | @@ -116,7 +120,7 @@ |
2694 | |
2695 | # can only start on sector 1 (sector 0 is MBR / partition table) |
2696 | boot_start, boot_end, boot_len = align_partition( |
2697 | - 1, BOOT_MIN_SIZE_S, boot_align, PART_ALIGN_S) |
2698 | + start_addr + 1, BOOT_MIN_SIZE_S, boot_align, PART_ALIGN_S) |
2699 | # apparently OMAP3 ROMs require the vfat length to be an even number |
2700 | # of sectors (multiple of 1 KiB); decrease the length if it's odd, |
2701 | # there should still be enough room |
2702 | @@ -131,12 +135,28 @@ |
2703 | _cache_end + 1, USERDATA_MIN_SIZE_S, PART_ALIGN_S, PART_ALIGN_S) |
2704 | sdcard_start, _sdcard_end, _sdcard_len = align_partition( |
2705 | _userdata_end + 1, SDCARD_MIN_SIZE_S, PART_ALIGN_S, PART_ALIGN_S) |
2706 | - |
2707 | + |
2708 | + # Snowball board needs a raw partition added to the beginning of image. |
2709 | + # If extra_part is True an extra primary partition will be added. |
2710 | + # Due to a maximum of 4 primary partitions cache data will be placed in |
2711 | + # a extended partition |
2712 | + if extra_part == True: |
2713 | + assert start_addr > 0, ("Not possible to add extra partition" \ |
2714 | + "when boot partition starts at '0'") |
2715 | + return '%s,%s,%s,*\n%s,%s,L\n%s,-,E\n%s,%s,L\n%s,%s,L\n%s,,,-' % ( |
2716 | + boot_start, boot_len, partition_type, system_start, _system_len, |
2717 | + cache_start, cache_start, _cache_len, userdata_start, |
2718 | + _userdata_len, sdcard_start) |
2719 | + |
2720 | return '%s,%s,%s,*\n%s,%s,L\n%s,%s,L\n%s,-,E\n%s,%s,L\n%s,,,-' % ( |
2721 | boot_start, boot_len, partition_type, system_start, _system_len, |
2722 | cache_start, _cache_len, userdata_start, userdata_start, |
2723 | _userdata_len, sdcard_start) |
2724 | |
2725 | + @classmethod |
2726 | + def populate_raw_partition(cls, media, boot_dir): |
2727 | + super(AndroidBoardConfig, cls).populate_raw_partition(boot_dir, media) |
2728 | + |
2729 | |
2730 | class AndroidOmapConfig(AndroidBoardConfig): |
2731 | pass |
2732 | @@ -149,10 +169,50 @@ |
2733 | |
2734 | class AndroidPandaConfig(AndroidOmapConfig, PandaConfig): |
2735 | _extra_serial_opts = 'console=tty0 console=ttyO2,115200n8' |
2736 | + extra_boot_args_options = ( |
2737 | + 'earlyprintk fixrtc nocompcache vram=48M ' |
2738 | + 'omapfb.vram=0:24M,1:24M mem=456M@0x80000000 mem=512M@0xA0000000') |
2739 | android_specific_args = 'init=/init androidboot.console=ttyO2' |
2740 | |
2741 | |
2742 | +class AndroidSnowballSdConfig(AndroidBoardConfig, SnowballSdConfig): |
2743 | + extra_boot_args_options = ( |
2744 | + 'earlyprintk rootdelay=1 fixrtc nocompcache ' |
2745 | + 'mem=128M@0 mali.mali_mem=64M@128M mem=24M@192M hwmem=167M@216M ' |
2746 | + 'mem_issw=1M@383M mem=640M@384M vmalloc=256M') |
2747 | + _extra_serial_opts = 'console=tty0 console=ttyO2,115200n8' |
2748 | + android_specific_args = 'init=/init androidboot.console=ttyAMA2' |
2749 | + |
2750 | + |
2751 | +class AndroidSnowballEmmcConfig(AndroidBoardConfig, SnowballEmmcConfig): |
2752 | + extra_boot_args_options = ( |
2753 | + 'earlyprintk rootdelay=1 fixrtc nocompcache ' |
2754 | + 'mem=128M@0 mali.mali_mem=64M@128M mem=24M@192M hwmem=167M@216M ' |
2755 | + 'mem_issw=1M@383M mem=640M@384M vmalloc=256M') |
2756 | + _extra_serial_opts = 'console=tty0 console=ttyAMA2,115200n8' |
2757 | + android_specific_args = 'init=/init androidboot.console=ttyAMA2' |
2758 | + |
2759 | + @classmethod |
2760 | + def get_sfdisk_cmd(cls, should_align_boot_part=False): |
2761 | + |
2762 | + LOADER_MIN_SIZE_S = align_up( |
2763 | + 1 * 1024 * 1024, SECTOR_SIZE) / SECTOR_SIZE |
2764 | + |
2765 | + loader_start, loader_end, loader_len = align_partition( |
2766 | + SnowballEmmcConfig.SNOWBALL_LOADER_START_S, |
2767 | + LOADER_MIN_SIZE_S, 1, PART_ALIGN_S) |
2768 | + |
2769 | + command = super(AndroidSnowballEmmcConfig, cls).get_sfdisk_cmd( |
2770 | + should_align_boot_part=True, start_addr=loader_end, |
2771 | + extra_part=True) |
2772 | + |
2773 | + return '%s,%s,0xDA\n%s' % ( |
2774 | + loader_start, loader_len, command) |
2775 | + |
2776 | + |
2777 | android_board_configs = { |
2778 | 'beagle': AndroidBeagleConfig, |
2779 | 'panda': AndroidPandaConfig, |
2780 | + 'snowball_sd': AndroidSnowballSdConfig, |
2781 | + 'snowball_emmc': AndroidSnowballEmmcConfig, |
2782 | } |
2783 | |
2784 | === modified file 'linaro_image_tools/media_create/boards.py' |
2785 | --- linaro_image_tools/media_create/boards.py 2011-05-26 20:19:23 +0000 |
2786 | +++ linaro_image_tools/media_create/boards.py 2011-07-18 14:39:34 +0000 |
2787 | @@ -31,11 +31,15 @@ |
2788 | import tempfile |
2789 | import struct |
2790 | from binascii import crc32 |
2791 | +import tarfile |
2792 | +import ConfigParser |
2793 | +import shutil |
2794 | |
2795 | from linaro_image_tools import cmd_runner |
2796 | |
2797 | from linaro_image_tools.media_create.partitions import SECTOR_SIZE |
2798 | |
2799 | + |
2800 | KERNEL_GLOB = 'vmlinuz-*-%(kernel_flavor)s' |
2801 | INITRD_GLOB = 'initrd.img-*-%(kernel_flavor)s' |
2802 | DTB_GLOB = 'dt-*-%(kernel_flavor)s/%(dtb_name)s' |
2803 | @@ -58,21 +62,11 @@ |
2804 | # align on 4 MiB |
2805 | PART_ALIGN_S = 4 * 1024 * 1024 / SECTOR_SIZE |
2806 | |
2807 | + |
2808 | def align_up(value, align): |
2809 | """Round value to the next multiple of align.""" |
2810 | return (value + align - 1) / align * align |
2811 | |
2812 | -# optional bootloader partition; at least 1 MiB; in theory, an i.MX5x |
2813 | -# bootloader partition could hold RedBoot, FIS table, RedBoot config, kernel, |
2814 | -# and initrd, but we typically use U-Boot which is about 167 KiB as of |
2815 | -# 2011/02/11 and currently doesn't even store its environment there, so this |
2816 | -# should be enough |
2817 | -LOADER_MIN_SIZE_S = align_up(1 * 1024 * 1024, SECTOR_SIZE) / SECTOR_SIZE |
2818 | -# boot partition; at least 50 MiB; XXX this shouldn't be hardcoded |
2819 | -BOOT_MIN_SIZE_S = align_up(50 * 1024 * 1024, SECTOR_SIZE) / SECTOR_SIZE |
2820 | -# root partition; at least 50 MiB; XXX this shouldn't be hardcoded |
2821 | -ROOT_MIN_SIZE_S = align_up(50 * 1024 * 1024, SECTOR_SIZE) / SECTOR_SIZE |
2822 | - |
2823 | # Samsung v310 implementation notes and terminology |
2824 | # |
2825 | # * BL0, BL1 etc. are the various bootloaders in order of execution |
2826 | @@ -104,6 +98,7 @@ |
2827 | assert SAMSUNG_V310_BL2_LEN * SECTOR_SIZE == 512 * 1024, ( |
2828 | "BL1 expects BL2 (u-boot) to be 512 KiB") |
2829 | |
2830 | + |
2831 | def align_partition(min_start, min_length, start_alignment, end_alignment): |
2832 | """Compute partition start and end offsets based on specified constraints. |
2833 | |
2834 | @@ -125,10 +120,103 @@ |
2835 | """A descriptor that provides @property behavior on class methods.""" |
2836 | def __init__(self, getter): |
2837 | self.getter = getter |
2838 | + |
2839 | def __get__(self, instance, cls): |
2840 | return self.getter(cls) |
2841 | |
2842 | |
2843 | +class HardwarepackHandler(object): |
2844 | + FORMAT_1 = '1.0' |
2845 | + FORMAT_2 = '2.0' |
2846 | + FORMAT_MIXED = '1.0and2.0' |
2847 | + metadata_filename = 'metadata' |
2848 | + format_filename = 'FORMAT' |
2849 | + main_section = 'main' |
2850 | + hwpack_tarfiles = [] |
2851 | + tempdir = None |
2852 | + |
2853 | + def __init__(self, hwpacks): |
2854 | + self.hwpacks = hwpacks |
2855 | + self.hwpack_tarfiles = [] |
2856 | + |
2857 | + class FakeSecHead(object): |
2858 | + """ Add a fake section header to the metadata file. |
2859 | + |
2860 | + This is done so we can use ConfigParser to parse the file. |
2861 | + """ |
2862 | + def __init__(self, fp): |
2863 | + self.fp = fp |
2864 | + self.sechead = '[%s]\n' % HardwarepackHandler.main_section |
2865 | + |
2866 | + def readline(self): |
2867 | + if self.sechead: |
2868 | + try: |
2869 | + return self.sechead |
2870 | + finally: |
2871 | + self.sechead = None |
2872 | + else: |
2873 | + return self.fp.readline() |
2874 | + |
2875 | + def __enter__(self): |
2876 | + self.tempdir = tempfile.mkdtemp() |
2877 | + for hwpack in self.hwpacks: |
2878 | + hwpack_tarfile = tarfile.open(hwpack, mode='r:gz') |
2879 | + self.hwpack_tarfiles.append(hwpack_tarfile) |
2880 | + return self |
2881 | + |
2882 | + def __exit__(self, type, value, traceback): |
2883 | + for hwpack_tarfile in self.hwpack_tarfiles: |
2884 | + if hwpack_tarfile is not None: |
2885 | + hwpack_tarfile.close() |
2886 | + self.hwpack_tarfiles = [] |
2887 | + if self.tempdir is not None and os.path.exists(self.tempdir): |
2888 | + shutil.rmtree(self.tempdir) |
2889 | + |
2890 | + def get_field(self, section, field): |
2891 | + data = None |
2892 | + hwpack_with_data = None |
2893 | + for hwpack_tarfile in self.hwpack_tarfiles: |
2894 | + metadata = hwpack_tarfile.extractfile(self.metadata_filename) |
2895 | + # Use RawConfigParser which does not support the magical interpolation |
2896 | + # behavior of ConfigParser so we don't mess up metadata accidentally. |
2897 | + parser = ConfigParser.RawConfigParser() |
2898 | + parser.readfp(self.FakeSecHead(metadata)) |
2899 | + try: |
2900 | + new_data = parser.get(section, field) |
2901 | + if new_data is not None: |
2902 | + assert data is None, "The metadata field '%s' is set to " \ |
2903 | + "'%s' and new value '%s' is found" % (field, data, new_data) |
2904 | + data = new_data |
2905 | + hwpack_with_data = hwpack_tarfile |
2906 | + except ConfigParser.NoOptionError: |
2907 | + continue |
2908 | + return data, hwpack_with_data |
2909 | + |
2910 | + def get_format(self): |
2911 | + format = None |
2912 | + supported_formats = [self.FORMAT_1, self.FORMAT_2] |
2913 | + for hwpack_tarfile in self.hwpack_tarfiles: |
2914 | + format_file = hwpack_tarfile.extractfile(self.format_filename) |
2915 | + format_string = format_file.read().strip() |
2916 | + if not format_string in supported_formats: |
2917 | + raise AssertionError( |
2918 | + "Format version '%s' is not supported." % \ |
2919 | + format_string) |
2920 | + if format is None: |
2921 | + format = format_string |
2922 | + elif format != format_string: |
2923 | + return self.FORMAT_MIXED |
2924 | + return format |
2925 | + |
2926 | + def get_file(self, file_alias): |
2927 | + file_name, hwpack_tarfile = self.get_field(self.main_section, |
2928 | + file_alias) |
2929 | + if file_name is not None: |
2930 | + hwpack_tarfile.extract(file_name, self.tempdir) |
2931 | + file_name = os.path.join(self.tempdir, file_name) |
2932 | + return file_name |
2933 | + |
2934 | + |
2935 | class BoardConfig(object): |
2936 | """The configuration used when building an image for a board.""" |
2937 | # These attributes may not need to be redefined on some subclasses. |
2938 | @@ -138,12 +226,17 @@ |
2939 | mmc_option = '0:1' |
2940 | mmc_part_offset = 0 |
2941 | fat_size = 32 |
2942 | - extra_serial_opts = '' |
2943 | - live_serial_opts = '' |
2944 | + _extra_serial_opts = '' |
2945 | + _live_serial_opts = '' |
2946 | extra_boot_args_options = None |
2947 | supports_writing_to_mmc = True |
2948 | + LOADER_MIN_SIZE_S = align_up(1 * 1024**2, SECTOR_SIZE) / SECTOR_SIZE |
2949 | + BOOT_MIN_SIZE_S = align_up(50 * 1024**2, SECTOR_SIZE) / SECTOR_SIZE |
2950 | + ROOT_MIN_SIZE_S = align_up(50 * 1024**2, SECTOR_SIZE) / SECTOR_SIZE |
2951 | |
2952 | - # These attributes must be defined on all subclasses. |
2953 | + # These attributes must be defined on all subclasses for backwards |
2954 | + # compatibility with hwpacks v1 format. Hwpacks v2 format allows these to |
2955 | + # be specified in the hwpack metadata. |
2956 | kernel_addr = None |
2957 | initrd_addr = None |
2958 | load_addr = None |
2959 | @@ -152,6 +245,88 @@ |
2960 | kernel_flavors = None |
2961 | boot_script = None |
2962 | serial_tty = None |
2963 | + wired_interfaces = None |
2964 | + wireless_interfaces = None |
2965 | + mmc_id = None |
2966 | + |
2967 | + hardwarepack_handler = None |
2968 | + |
2969 | + @classmethod |
2970 | + def get_metadata_field(cls, target, field_name): |
2971 | + """ Return the metadata value for field_name if it can be found. |
2972 | + """ |
2973 | + data, _ = cls.hardwarepack_handler.get_field( |
2974 | + cls.hardwarepack_handler.main_section, field_name) |
2975 | + return data |
2976 | + |
2977 | + @classmethod |
2978 | + def set_metadata(cls, hwpacks): |
2979 | + cls.hardwarepack_handler = HardwarepackHandler(hwpacks) |
2980 | + with cls.hardwarepack_handler: |
2981 | + if (cls.hardwarepack_handler.get_format() == |
2982 | + cls.hardwarepack_handler.FORMAT_1): |
2983 | + return |
2984 | + |
2985 | + if (cls.hardwarepack_handler.get_format() == |
2986 | + cls.hardwarepack_handler.FORMAT_2): |
2987 | + # Clear V1 defaults. |
2988 | + cls.kernel_addr = None |
2989 | + cls.initrd_addr = None |
2990 | + cls.load_addr = None |
2991 | + cls.serial_tty = None |
2992 | + cls.fat_size = None |
2993 | + cls.BOOT_MIN_SIZE_S = None |
2994 | + cls.ROOT_MIN_SIZE_S = None |
2995 | + cls.LOADER_MIN_SIZE_S = None |
2996 | + |
2997 | + # Set new values from metadata. |
2998 | + cls.kernel_addr = cls.get_metadata_field( |
2999 | + cls.kernel_addr, 'kernel_addr') |
3000 | + cls.initrd_addr = cls.get_metadata_field( |
3001 | + cls.initrd_addr, 'initrd_addr') |
3002 | + cls.load_addr = cls.get_metadata_field( |
3003 | + cls.load_addr, 'load_addr') |
3004 | + cls.serial_tty = cls.get_metadata_field( |
3005 | + cls.serial_tty, 'serial_tty') |
3006 | + cls.wired_interfaces = cls.get_metadata_field( |
3007 | + cls.wired_interfaces, 'wired_interfaces') |
3008 | + cls.wireless_interfaces = cls.get_metadata_field( |
3009 | + cls.wireless_interfaces, 'wireless_interfaces') |
3010 | + cls.mmc_id = cls.get_metadata_field( |
3011 | + cls.mmc_id, 'mmc_id') |
3012 | + |
3013 | + partition_layout = cls.get_metadata_field(cls.fat_size, 'partition_layout') |
3014 | + if partition_layout == 'bootfs_rootfs' or partition_layout is None: |
3015 | + cls.fat_size = 32 |
3016 | + elif partition_layout == 'bootfs16_rootfs': |
3017 | + cls.fat_size = 16 |
3018 | + else: |
3019 | + raise AssertionError("Unknown partition layout '%s'." % partition_layout) |
3020 | + |
3021 | + boot_min_size = cls.get_metadata_field( |
3022 | + cls.BOOT_MIN_SIZE_S, 'boot_min_size') |
3023 | + if boot_min_size is not None: |
3024 | + cls.BOOT_MIN_SIZE_S = align_up(int(boot_min_size) * 1024**2, |
3025 | + SECTOR_SIZE) / SECTOR_SIZE |
3026 | + root_min_size = cls.get_metadata_field( |
3027 | + cls.ROOT_MIN_SIZE_S, 'root_min_size') |
3028 | + if root_min_size is not None: |
3029 | + cls.ROOT_MIN_SIZE_S = align_up(int(root_min_size) * 1024**2, |
3030 | + SECTOR_SIZE) / SECTOR_SIZE |
3031 | + loader_min_size = cls.get_metadata_field( |
3032 | + cls.LOADER_MIN_SIZE_S, 'loader_min_size') |
3033 | + if loader_min_size is not None: |
3034 | + cls.LOADER_MIN_SIZE_S = align_up(int(loader_min_size) * 1024**2, |
3035 | + SECTOR_SIZE) / SECTOR_SIZE |
3036 | + |
3037 | + |
3038 | + @classmethod |
3039 | + def get_file(cls, file_alias, default=None): |
3040 | + file_in_hwpack = cls.hardwarepack_handler.get_file(file_alias) |
3041 | + if file_in_hwpack is not None: |
3042 | + return file_in_hwpack |
3043 | + else: |
3044 | + return default |
3045 | |
3046 | @classmethod |
3047 | def get_sfdisk_cmd(cls, should_align_boot_part=False): |
3048 | @@ -167,9 +342,6 @@ |
3049 | else: |
3050 | partition_type = '0x0E' |
3051 | |
3052 | - BOOT_MIN_SIZE_S = align_up(50 * 1024 * 1024, SECTOR_SIZE) / SECTOR_SIZE |
3053 | - ROOT_MIN_SIZE_S = align_up(50 * 1024 * 1024, SECTOR_SIZE) / SECTOR_SIZE |
3054 | - |
3055 | # align on sector 63 for compatibility with broken versions of x-loader |
3056 | # unless align_boot_part is set |
3057 | boot_align = 63 |
3058 | @@ -178,7 +350,7 @@ |
3059 | |
3060 | # can only start on sector 1 (sector 0 is MBR / partition table) |
3061 | boot_start, boot_end, boot_len = align_partition( |
3062 | - 1, BOOT_MIN_SIZE_S, boot_align, PART_ALIGN_S) |
3063 | + 1, cls.BOOT_MIN_SIZE_S, boot_align, PART_ALIGN_S) |
3064 | # apparently OMAP3 ROMs require the vfat length to be an even number |
3065 | # of sectors (multiple of 1 KiB); decrease the length if it's odd, |
3066 | # there should still be enough room |
3067 | @@ -189,7 +361,7 @@ |
3068 | # instruct the use of all remaining space; XXX if we had some root size |
3069 | # config, we could do something more sensible |
3070 | root_start, _root_end, _root_len = align_partition( |
3071 | - boot_end + 1, ROOT_MIN_SIZE_S, PART_ALIGN_S, PART_ALIGN_S) |
3072 | + boot_end + 1, cls.ROOT_MIN_SIZE_S, PART_ALIGN_S, PART_ALIGN_S) |
3073 | |
3074 | return '%s,%s,%s,*\n%s,,,-' % ( |
3075 | boot_start, boot_len, partition_type, root_start) |
3076 | @@ -299,10 +471,12 @@ |
3077 | if cls.uboot_in_boot_part: |
3078 | assert cls.uboot_flavor is not None, ( |
3079 | "uboot_in_boot_part is set but not uboot_flavor") |
3080 | - uboot_bin = os.path.join(chroot_dir, 'usr', 'lib', 'u-boot', |
3081 | - cls.uboot_flavor, 'u-boot.bin') |
3082 | - cmd_runner.run( |
3083 | - ['cp', '-v', uboot_bin, boot_disk], as_root=True).wait() |
3084 | + with cls.hardwarepack_handler: |
3085 | + uboot_bin = cls.get_file('u_boot', default=os.path.join( |
3086 | + chroot_dir, 'usr', 'lib', 'u-boot', cls.uboot_flavor, |
3087 | + 'u-boot.bin')) |
3088 | + cmd_runner.run( |
3089 | + ['cp', '-v', uboot_bin, boot_disk], as_root=True).wait() |
3090 | |
3091 | cls.make_boot_files( |
3092 | uboot_parts_dir, is_live, is_lowmem, consoles, chroot_dir, |
3093 | @@ -337,9 +511,14 @@ |
3094 | "No kernel found matching %s for flavors %s" % ( |
3095 | KERNEL_GLOB, " ".join(cls.kernel_flavors))) |
3096 | |
3097 | + @classmethod |
3098 | + def populate_raw_partition(cls, media, boot_dir): |
3099 | + # Override in subclass if needed |
3100 | + pass |
3101 | + |
3102 | |
3103 | class OmapConfig(BoardConfig): |
3104 | - kernel_flavors = ['linaro-omap4', 'linaro-omap', 'omap4'] |
3105 | + kernel_flavors = ['linaro-omap4', 'linaro-lt-omap', 'linaro-omap', 'omap4'] |
3106 | uboot_in_boot_part = True |
3107 | |
3108 | # XXX: Here we define these things as dynamic properties because our |
3109 | @@ -471,8 +650,8 @@ |
3110 | |
3111 | class Ux500Config(BoardConfig): |
3112 | serial_tty = 'ttyAMA2' |
3113 | - extra_serial_opts = 'console=tty0 console=%s,115200n8' % serial_tty |
3114 | - live_serial_opts = 'serialtty=%s' % serial_tty |
3115 | + _extra_serial_opts = 'console=tty0 console=%s,115200n8' |
3116 | + _live_serial_opts = 'serialtty=%s' |
3117 | kernel_addr = '0x00100000' |
3118 | initrd_addr = '0x08000000' |
3119 | load_addr = '0x00008000' |
3120 | @@ -485,6 +664,14 @@ |
3121 | 'hwmem=48M@302M mem=152M@360M') |
3122 | mmc_option = '1:1' |
3123 | |
3124 | + @classproperty |
3125 | + def live_serial_opts(cls): |
3126 | + return cls._live_serial_opts % cls.serial_tty |
3127 | + |
3128 | + @classproperty |
3129 | + def extra_serial_opts(cls): |
3130 | + return cls._extra_serial_opts % cls.serial_tty |
3131 | + |
3132 | @classmethod |
3133 | def _make_boot_files(cls, boot_env, chroot_dir, boot_dir, |
3134 | boot_device_or_file, k_img_data, i_img_data, |
3135 | @@ -517,7 +704,7 @@ |
3136 | and u-boot.''' |
3137 | # Boot ROM looks for a boot table of contents (TOC) at 0x20000 |
3138 | # Actually, it first looks at address 0, but that's where l-m-c |
3139 | - # puts the MBR, so the boot loader skips that address. |
3140 | + # puts the MBR, so the boot loader skips that address. |
3141 | supports_writing_to_mmc = False |
3142 | SNOWBALL_LOADER_START_S = (128 * 1024) / SECTOR_SIZE |
3143 | SNOWBALL_STARTUP_FILES_CONFIG = 'startfiles.cfg' |
3144 | @@ -537,20 +724,20 @@ |
3145 | This is done since the boot rom always boots off the internal memory; |
3146 | there simply is no point to having a loader partition on SD card. |
3147 | """ |
3148 | - # boot ROM expects bootloader at 0x20000, which is sector 0x100 |
3149 | + # boot ROM expects bootloader at 0x20000, which is sector 0x100 |
3150 | # with the usual SECTOR_SIZE of 0x200. |
3151 | # (sector 0 is MBR / partition table) |
3152 | loader_start, loader_end, loader_len = align_partition( |
3153 | - SnowballEmmcConfig.SNOWBALL_LOADER_START_S, |
3154 | - LOADER_MIN_SIZE_S, 1, PART_ALIGN_S) |
3155 | + SnowballEmmcConfig.SNOWBALL_LOADER_START_S, |
3156 | + cls.LOADER_MIN_SIZE_S, 1, PART_ALIGN_S) |
3157 | |
3158 | boot_start, boot_end, boot_len = align_partition( |
3159 | - loader_end + 1, BOOT_MIN_SIZE_S, PART_ALIGN_S, PART_ALIGN_S) |
3160 | + loader_end + 1, cls.BOOT_MIN_SIZE_S, PART_ALIGN_S, PART_ALIGN_S) |
3161 | # we ignore _root_end / _root_len and return an sfdisk command to |
3162 | # instruct the use of all remaining space; XXX if we had some root size |
3163 | # config, we could do something more sensible |
3164 | root_start, _root_end, _root_len = align_partition( |
3165 | - boot_end + 1, ROOT_MIN_SIZE_S, PART_ALIGN_S, PART_ALIGN_S) |
3166 | + boot_end + 1, cls.ROOT_MIN_SIZE_S, PART_ALIGN_S, PART_ALIGN_S) |
3167 | |
3168 | return '%s,%s,0xDA\n%s,%s,0x0C,*\n%s,,,-' % ( |
3169 | loader_start, loader_len, boot_start, boot_len, root_start) |
3170 | @@ -562,15 +749,22 @@ |
3171 | make_uImage(cls.load_addr, k_img_data, boot_dir) |
3172 | boot_script_path = os.path.join(boot_dir, cls.boot_script) |
3173 | make_boot_script(boot_env, boot_script_path) |
3174 | + cls.populate_raw_partition(chroot_dir, boot_device_or_file) |
3175 | + |
3176 | + @classmethod |
3177 | + def populate_raw_partition(cls, chroot_dir, boot_device_or_file): |
3178 | + # Populate created raw partition with TOC and startup files. |
3179 | + config_files_path = os.path.join(chroot_dir, 'boot') |
3180 | _, toc_filename = tempfile.mkstemp() |
3181 | - atexit.register(os.unlink, toc_filename) |
3182 | - config_files_path = os.path.join(chroot_dir, 'boot') |
3183 | new_files = cls.get_file_info(config_files_path) |
3184 | with open(toc_filename, 'wb') as toc: |
3185 | cls.create_toc(toc, new_files) |
3186 | cls.install_snowball_boot_loader(toc_filename, new_files, |
3187 | boot_device_or_file, |
3188 | cls.SNOWBALL_LOADER_START_S) |
3189 | + cls.delete_file(toc_filename) |
3190 | + cls.delete_file(os.path.join(config_files_path, |
3191 | + cls.SNOWBALL_STARTUP_FILES_CONFIG)) |
3192 | |
3193 | @classmethod |
3194 | def install_snowball_boot_loader(cls, toc_file_name, files, |
3195 | @@ -584,13 +778,21 @@ |
3196 | for file in files: |
3197 | # XXX We need checks that these files do not overwrite each |
3198 | # other. This code assumes that offset and file sizes are ok. |
3199 | + filename = file['filename'] |
3200 | if (file['offset'] % SECTOR_SIZE) != 0: |
3201 | seek_bytes = start_sector * SECTOR_SIZE + file['offset'] |
3202 | - _dd(file['filename'], boot_device_or_file, block_size=1, |
3203 | + _dd(filename, boot_device_or_file, block_size=1, |
3204 | seek=seek_bytes) |
3205 | else: |
3206 | - seek_sectors = start_sector + file['offset']/SECTOR_SIZE |
3207 | - _dd(file['filename'], boot_device_or_file, seek=seek_sectors) |
3208 | + seek_sectors = start_sector + file['offset'] / SECTOR_SIZE |
3209 | + _dd(filename, boot_device_or_file, seek=seek_sectors) |
3210 | + cls.delete_file(filename) |
3211 | + |
3212 | + @classmethod |
3213 | + def delete_file(cls, file_path): |
3214 | + cmd = ["rm", "%s" % file_path] |
3215 | + proc = cmd_runner.run(cmd, as_root=True) |
3216 | + proc.wait() |
3217 | |
3218 | @classmethod |
3219 | def create_toc(cls, f, files): |
3220 | @@ -605,6 +807,8 @@ |
3221 | # i; int; load_address, |
3222 | # 12s; string of char; name |
3223 | # http://igloocommunity.org/support/index.php/ConfigPartitionOverview |
3224 | + assert len(file['section_name']) < 12, ( |
3225 | + "Section name %s too large" % file['section_name']) |
3226 | flags = 0 |
3227 | load_adress = file['align'] |
3228 | data = struct.pack('<IIIii12s', file['offset'], file['size'], |
3229 | @@ -642,12 +846,20 @@ |
3230 | |
3231 | class Mx5Config(BoardConfig): |
3232 | serial_tty = 'ttymxc0' |
3233 | - extra_serial_opts = 'console=tty0 console=%s,115200n8' % serial_tty |
3234 | - live_serial_opts = 'serialtty=%s' % serial_tty |
3235 | + _extra_serial_opts = 'console=tty0 console=%s,115200n8' |
3236 | + _live_serial_opts = 'serialtty=%s' |
3237 | boot_script = 'boot.scr' |
3238 | mmc_part_offset = 1 |
3239 | mmc_option = '0:2' |
3240 | |
3241 | + @classproperty |
3242 | + def live_serial_opts(cls): |
3243 | + return cls._live_serial_opts % cls.serial_tty |
3244 | + |
3245 | + @classproperty |
3246 | + def extra_serial_opts(cls): |
3247 | + return cls._extra_serial_opts % cls.serial_tty |
3248 | + |
3249 | @classmethod |
3250 | def get_sfdisk_cmd(cls, should_align_boot_part=None): |
3251 | """Return the sfdisk command to partition the media. |
3252 | @@ -663,15 +875,15 @@ |
3253 | # onwards, so it's safer to just start at the first sector, sector 1 |
3254 | # (sector 0 is MBR / partition table) |
3255 | loader_start, loader_end, loader_len = align_partition( |
3256 | - 1, LOADER_MIN_SIZE_S, 1, PART_ALIGN_S) |
3257 | + 1, cls.LOADER_MIN_SIZE_S, 1, PART_ALIGN_S) |
3258 | |
3259 | boot_start, boot_end, boot_len = align_partition( |
3260 | - loader_end + 1, BOOT_MIN_SIZE_S, PART_ALIGN_S, PART_ALIGN_S) |
3261 | + loader_end + 1, cls.BOOT_MIN_SIZE_S, PART_ALIGN_S, PART_ALIGN_S) |
3262 | # we ignore _root_end / _root_len and return a sfdisk command to |
3263 | # instruct the use of all remaining space; XXX if we had some root size |
3264 | # config, we could do something more sensible |
3265 | root_start, _root_end, _root_len = align_partition( |
3266 | - boot_end + 1, ROOT_MIN_SIZE_S, PART_ALIGN_S, PART_ALIGN_S) |
3267 | + boot_end + 1, cls.ROOT_MIN_SIZE_S, PART_ALIGN_S, PART_ALIGN_S) |
3268 | |
3269 | return '%s,%s,0xDA\n%s,%s,0x0C,*\n%s,,,-' % ( |
3270 | loader_start, loader_len, boot_start, boot_len, root_start) |
3271 | @@ -680,9 +892,12 @@ |
3272 | def _make_boot_files(cls, boot_env, chroot_dir, boot_dir, |
3273 | boot_device_or_file, k_img_data, i_img_data, |
3274 | d_img_data): |
3275 | - uboot_file = os.path.join( |
3276 | - chroot_dir, 'usr', 'lib', 'u-boot', cls.uboot_flavor, 'u-boot.imx') |
3277 | - install_mx5_boot_loader(uboot_file, boot_device_or_file) |
3278 | + with cls.hardwarepack_handler: |
3279 | + uboot_file = cls.get_file('u_boot', default=os.path.join( |
3280 | + chroot_dir, 'usr', 'lib', 'u-boot', cls.uboot_flavor, |
3281 | + 'u-boot.imx')) |
3282 | + install_mx5_boot_loader(uboot_file, boot_device_or_file, |
3283 | + cls.LOADER_MIN_SIZE_S) |
3284 | make_uImage(cls.load_addr, k_img_data, boot_dir) |
3285 | make_uInitrd(i_img_data, boot_dir) |
3286 | make_dtb(d_img_data, boot_dir) |
3287 | @@ -730,8 +945,8 @@ |
3288 | uboot_flavor = 'ca9x4_ct_vxp' |
3289 | uboot_in_boot_part = True |
3290 | serial_tty = 'ttyAMA0' |
3291 | - extra_serial_opts = 'console=tty0 console=%s,38400n8' % serial_tty |
3292 | - live_serial_opts = 'serialtty=%s' % serial_tty |
3293 | + _extra_serial_opts = 'console=tty0 console=%s,38400n8' |
3294 | + _live_serial_opts = 'serialtty=%s' |
3295 | kernel_addr = '0x60008000' |
3296 | initrd_addr = '0x81000000' |
3297 | load_addr = kernel_addr |
3298 | @@ -741,6 +956,14 @@ |
3299 | # only allows for FAT16 |
3300 | fat_size = 16 |
3301 | |
3302 | + @classproperty |
3303 | + def live_serial_opts(cls): |
3304 | + return cls._live_serial_opts % cls.serial_tty |
3305 | + |
3306 | + @classproperty |
3307 | + def extra_serial_opts(cls): |
3308 | + return cls._extra_serial_opts % cls.serial_tty |
3309 | + |
3310 | @classmethod |
3311 | def _make_boot_files(cls, boot_env, chroot_dir, boot_dir, |
3312 | boot_device_or_file, k_img_data, i_img_data, |
3313 | @@ -748,17 +971,10 @@ |
3314 | make_uImage(cls.load_addr, k_img_data, boot_dir) |
3315 | make_uInitrd(i_img_data, boot_dir) |
3316 | |
3317 | -class SMDKV310Config(BoardConfig): |
3318 | - uboot_flavor = 'smdkv310' |
3319 | - serial_tty = 'ttySAC1' |
3320 | - extra_serial_opts = 'console=%s,115200n8' % serial_tty |
3321 | - kernel_addr = '0x40007000' |
3322 | - initrd_addr = '0x42000000' |
3323 | - load_addr = '0x40008000' |
3324 | - kernel_flavors = ['s5pv310'] |
3325 | - boot_script = 'boot.scr' |
3326 | - mmc_part_offset = 1 |
3327 | - mmc_option = '0:2' |
3328 | +class SamsungConfig(BoardConfig): |
3329 | + @classproperty |
3330 | + def extra_serial_opts(cls): |
3331 | + return cls._extra_serial_opts % cls.serial_tty |
3332 | |
3333 | @classmethod |
3334 | def get_sfdisk_cmd(cls, should_align_boot_part=False): |
3335 | @@ -773,46 +989,23 @@ |
3336 | |
3337 | # FAT boot partition |
3338 | boot_start, boot_end, boot_len = align_partition( |
3339 | - loaders_end + 1, BOOT_MIN_SIZE_S, PART_ALIGN_S, PART_ALIGN_S) |
3340 | + loaders_end + 1, cls.BOOT_MIN_SIZE_S, PART_ALIGN_S, PART_ALIGN_S) |
3341 | |
3342 | # root partition |
3343 | # we ignore _root_end / _root_len and return a sfdisk command to |
3344 | # instruct the use of all remaining space; XXX if we had some root size |
3345 | # config, we could do something more sensible |
3346 | root_start, _root_end, _root_len = align_partition( |
3347 | - boot_end + 1, ROOT_MIN_SIZE_S, PART_ALIGN_S, PART_ALIGN_S) |
3348 | + boot_end + 1, cls.ROOT_MIN_SIZE_S, PART_ALIGN_S, PART_ALIGN_S) |
3349 | |
3350 | return '%s,%s,0xDA\n%s,%s,0x0C,*\n%s,,,-' % ( |
3351 | loaders_start, loaders_len, boot_start, boot_len, root_start) |
3352 | |
3353 | @classmethod |
3354 | - def _get_boot_env(cls, is_live, is_lowmem, consoles, rootfs_uuid, |
3355 | - d_img_data): |
3356 | - boot_env = super(SMDKV310Config, cls)._get_boot_env( |
3357 | - is_live, is_lowmem, consoles, rootfs_uuid, d_img_data) |
3358 | - |
3359 | - boot_env["ethact"] = "smc911x-0" |
3360 | - boot_env["ethaddr"] = "00:40:5c:26:0a:5b" |
3361 | - |
3362 | - return boot_env |
3363 | - |
3364 | - @classmethod |
3365 | def _make_boot_files(cls, boot_env, chroot_dir, boot_dir, |
3366 | boot_device_or_file, k_img_data, i_img_data, |
3367 | d_img_data): |
3368 | - spl_file = os.path.join( |
3369 | - chroot_dir, 'usr', 'lib', 'u-boot', cls.uboot_flavor, |
3370 | - 'v310_mmc_spl.bin') |
3371 | - # XXX need to check that the length of spl_file is smaller than |
3372 | - # SAMSUNG_V310_BL1_LEN |
3373 | - _dd(spl_file, boot_device_or_file, seek=SAMSUNG_V310_BL1_START) |
3374 | - |
3375 | - uboot_file = os.path.join( |
3376 | - chroot_dir, 'usr', 'lib', 'u-boot', cls.uboot_flavor, 'u-boot.bin') |
3377 | - # XXX need to check that the length of uboot_file is smaller than |
3378 | - # SAMSUNG_V310_BL2_LEN |
3379 | - _dd(uboot_file, boot_device_or_file, seek=SAMSUNG_V310_BL2_START) |
3380 | - |
3381 | + cls.install_samsung_boot_loader(chroot_dir, boot_device_or_file) |
3382 | env_size = SAMSUNG_V310_ENV_LEN * SECTOR_SIZE |
3383 | env_file = make_flashable_env(boot_env, env_size) |
3384 | _dd(env_file, boot_device_or_file, seek=SAMSUNG_V310_ENV_START) |
3385 | @@ -825,6 +1018,84 @@ |
3386 | boot_script_path = os.path.join(boot_dir, cls.boot_script) |
3387 | make_boot_script(boot_env, boot_script_path) |
3388 | |
3389 | + @classmethod |
3390 | + def _get_samsung_spl(cls, chroot_dir): |
3391 | + spl_dir = os.path.join( |
3392 | + chroot_dir, 'usr', 'lib', 'u-boot', cls.uboot_flavor) |
3393 | + old_spl_path = os.path.join(spl_dir, 'v310_mmc_spl.bin') |
3394 | + new_spl_path = os.path.join(spl_dir, 'u-boot-mmc-spl.bin') |
3395 | + |
3396 | + spl_file = old_spl_path |
3397 | + # The new upstream u-boot filename has changed |
3398 | + if not os.path.exists(spl_file): |
3399 | + spl_file = new_spl_path |
3400 | + |
3401 | + if not os.path.exists(spl_file): |
3402 | + # missing SPL loader |
3403 | + raise AssertionError("Couldn't find the SPL file, tried %s and %s" |
3404 | + % (old_spl_path, new_spl_path)) |
3405 | + return spl_file |
3406 | + |
3407 | + @classmethod |
3408 | + def _get_samsung_uboot(cls, chroot_dir): |
3409 | + uboot_file = os.path.join( |
3410 | + chroot_dir, 'usr', 'lib', 'u-boot', cls.uboot_flavor, |
3411 | + 'u-boot.bin') |
3412 | + return uboot_file |
3413 | + |
3414 | + @classmethod |
3415 | + def install_samsung_boot_loader(cls, chroot_dir, boot_device_or_file): |
3416 | + spl_file = cls._get_samsung_spl(chroot_dir) |
3417 | + bl1_max_size = SAMSUNG_V310_BL1_LEN * SECTOR_SIZE |
3418 | + assert os.path.getsize(spl_file) <= bl1_max_size, ( |
3419 | + "%s is larger than %s" % (spl_file, bl1_max_size)) |
3420 | + _dd(spl_file, boot_device_or_file, seek=SAMSUNG_V310_BL1_START) |
3421 | + |
3422 | + with cls.hardwarepack_handler: |
3423 | + uboot_file = cls.get_file( |
3424 | + 'u_boot', default=cls._get_samsung_uboot(chroot_dir)) |
3425 | + bl2_max_size = SAMSUNG_V310_BL2_LEN * SECTOR_SIZE |
3426 | + assert os.path.getsize(uboot_file) <= bl2_max_size, ( |
3427 | + "%s is larger than %s" % (uboot_file, bl2_max_size)) |
3428 | + _dd(uboot_file, boot_device_or_file, seek=SAMSUNG_V310_BL2_START) |
3429 | + |
3430 | + |
3431 | +class SMDKV310Config(SamsungConfig): |
3432 | + uboot_flavor = 'smdkv310' |
3433 | + serial_tty = 'ttySAC1' |
3434 | + _extra_serial_opts = 'console=%s,115200n8' |
3435 | + kernel_addr = '0x40007000' |
3436 | + initrd_addr = '0x42000000' |
3437 | + load_addr = '0x40008000' |
3438 | + kernel_flavors = ['s5pv310'] |
3439 | + boot_script = 'boot.scr' |
3440 | + mmc_part_offset = 1 |
3441 | + mmc_option = '0:2' |
3442 | + |
3443 | + @classmethod |
3444 | + def _get_boot_env(cls, is_live, is_lowmem, consoles, rootfs_uuid, |
3445 | + d_img_data): |
3446 | + boot_env = super(SamsungConfig, cls)._get_boot_env( |
3447 | + is_live, is_lowmem, consoles, rootfs_uuid, d_img_data) |
3448 | + |
3449 | + boot_env["ethact"] = "smc911x-0" |
3450 | + boot_env["ethaddr"] = "00:40:5c:26:0a:5b" |
3451 | + |
3452 | + return boot_env |
3453 | + |
3454 | + |
3455 | +class OrigenConfig(SamsungConfig): |
3456 | + uboot_flavor = 'origen' |
3457 | + serial_tty = 'ttySAC2' |
3458 | + _extra_serial_opts = 'console=%s,115200n8' |
3459 | + kernel_addr = '0x40007000' |
3460 | + initrd_addr = '0x42000000' |
3461 | + load_addr = '0x40008000' |
3462 | + kernel_flavors = ['origen'] |
3463 | + boot_script = 'boot.scr' |
3464 | + mmc_part_offset = 1 |
3465 | + mmc_option = '0:2' |
3466 | + |
3467 | |
3468 | board_configs = { |
3469 | 'beagle': BeagleConfig, |
3470 | @@ -837,9 +1108,10 @@ |
3471 | 'efikamx': EfikamxConfig, |
3472 | 'efikasb': EfikasbConfig, |
3473 | 'mx51evk': Mx51evkConfig, |
3474 | - 'mx53loco' : Mx53LoCoConfig, |
3475 | + 'mx53loco': Mx53LoCoConfig, |
3476 | 'overo': OveroConfig, |
3477 | 'smdkv310': SMDKV310Config, |
3478 | + 'origen': OrigenConfig, |
3479 | } |
3480 | |
3481 | |
3482 | @@ -961,13 +1233,13 @@ |
3483 | return tmpfile |
3484 | |
3485 | |
3486 | -def install_mx5_boot_loader(imx_file, boot_device_or_file): |
3487 | +def install_mx5_boot_loader(imx_file, boot_device_or_file, loader_min_size): |
3488 | # bootloader partition starts at +1s but we write the file at +2s, so we |
3489 | # need to check that the bootloader partition minus 1s is at least as large |
3490 | # as the u-boot binary; note that the real bootloader partition might be |
3491 | # larger than LOADER_MIN_SIZE_S, but if u-boot is larger it's a sign we |
3492 | # need to bump LOADER_MIN_SIZE_S |
3493 | - max_size = (LOADER_MIN_SIZE_S - 1) * SECTOR_SIZE |
3494 | + max_size = (loader_min_size - 1) * SECTOR_SIZE |
3495 | assert os.path.getsize(imx_file) <= max_size, ( |
3496 | "%s is larger than guaranteed bootloader partition size" % imx_file) |
3497 | _dd(imx_file, boot_device_or_file, seek=2) |
3498 | @@ -1008,4 +1280,3 @@ |
3499 | ["cp", "-v", boot_script_path, "%s/boot.ini" % boot_disk], |
3500 | as_root=True) |
3501 | proc.wait() |
3502 | - |
3503 | |
3504 | === modified file 'linaro_image_tools/media_create/partitions.py' |
3505 | --- linaro_image_tools/media_create/partitions.py 2011-05-31 06:45:22 +0000 |
3506 | +++ linaro_image_tools/media_create/partitions.py 2011-07-18 14:39:34 +0000 |
3507 | @@ -3,7 +3,7 @@ |
3508 | # Author: Guilherme Salgado <guilherme.salgado@linaro.org> |
3509 | # |
3510 | # This file is part of Linaro Image Tools. |
3511 | -# |
3512 | +# |
3513 | # Linaro Image Tools is free software: you can redistribute it and/or modify |
3514 | # it under the terms of the GNU General Public License as published by |
3515 | # the Free Software Foundation, either version 3 of the License, or |
3516 | @@ -28,6 +28,7 @@ |
3517 | Device, |
3518 | Disk, |
3519 | PARTITION_NORMAL, |
3520 | + PARTITION_EXTENDED, |
3521 | ) |
3522 | |
3523 | from linaro_image_tools import cmd_runner |
3524 | @@ -71,9 +72,8 @@ |
3525 | bootfs = partitions[0] |
3526 | system = partitions[1] |
3527 | cache = partitions[2] |
3528 | - data = partitions[4] |
3529 | - sdcard = partitions[5] |
3530 | - |
3531 | + data = partitions[3] |
3532 | + sdcard = partitions[4] |
3533 | |
3534 | print "\nFormating boot partition\n" |
3535 | proc = cmd_runner.run( |
3536 | @@ -98,6 +98,7 @@ |
3537 | |
3538 | return bootfs, system, cache, data, sdcard |
3539 | |
3540 | + |
3541 | # I wonder if it'd make sense to convert this into a small shim which calls |
3542 | # the appropriate function for the given type of device? I think it's still |
3543 | # small enough that there's not much benefit in doing that, but if it grows we |
3544 | @@ -296,18 +297,28 @@ |
3545 | # Here we can use parted.Device to read the partitions because we're |
3546 | # reading from a regular file rather than a block device. If it was a |
3547 | # block device we'd need root rights. |
3548 | + vfat_partition = None |
3549 | disk = Disk(Device(image_file)) |
3550 | partition_info = [] |
3551 | for partition in disk.partitions: |
3552 | - geometry = partition.geometry |
3553 | - partition_info.append((geometry.start * SECTOR_SIZE, |
3554 | - geometry.length * SECTOR_SIZE)) |
3555 | + # Will ignore any partitions before boot and of type EXTENDED |
3556 | + if 'boot' in partition.getFlagsAsString(): |
3557 | + vfat_partition = partition |
3558 | + geometry = partition.geometry |
3559 | + partition_info.append((geometry.start * SECTOR_SIZE, |
3560 | + geometry.length * SECTOR_SIZE)) |
3561 | + elif (vfat_partition is not None and |
3562 | + partition.type != PARTITION_EXTENDED): |
3563 | + geometry = partition.geometry |
3564 | + partition_info.append((geometry.start * SECTOR_SIZE, |
3565 | + geometry.length * SECTOR_SIZE)) |
3566 | # NB: don't use vfat_partition.nextPartition() as that might return |
3567 | # a partition of type PARTITION_FREESPACE; it's much easier to |
3568 | # iterate disk.partitions which only returns |
3569 | # parted.PARTITION_NORMAL partitions |
3570 | - |
3571 | - assert len(partition_info) == 6 |
3572 | + assert vfat_partition is not None, ( |
3573 | + "Couldn't find boot partition on %s" % image_file) |
3574 | + assert len(partition_info) == 5 |
3575 | return partition_info |
3576 | |
3577 | |
3578 | @@ -347,6 +358,7 @@ |
3579 | return boot_partition, system_partition, cache_partition, \ |
3580 | data_partition, sdcard_partition |
3581 | |
3582 | + |
3583 | def get_boot_and_root_partitions_for_media(media, board_config): |
3584 | """Return the device files for the boot and root partitions of media. |
3585 | |
3586 | |
3587 | === modified file 'linaro_image_tools/media_create/rootfs.py' |
3588 | --- linaro_image_tools/media_create/rootfs.py 2011-04-05 09:26:47 +0000 |
3589 | +++ linaro_image_tools/media_create/rootfs.py 2011-07-18 14:39:34 +0000 |
3590 | @@ -19,6 +19,7 @@ |
3591 | |
3592 | import glob |
3593 | import os |
3594 | +import subprocess |
3595 | import tempfile |
3596 | |
3597 | from linaro_image_tools import cmd_runner |
3598 | @@ -107,13 +108,26 @@ |
3599 | flash_kernel, "UBOOT_PART=%s" % target_boot_dev) |
3600 | |
3601 | |
3602 | +def _list_files(directory): |
3603 | + """List the files and dirs under the given directory. |
3604 | + |
3605 | + Runs as root because we want to list everything, including stuff that may |
3606 | + not be world-readable. |
3607 | + """ |
3608 | + p = cmd_runner.run( |
3609 | + ['find', directory, '-maxdepth', '1', '-mindepth', '1'], |
3610 | + stdout=subprocess.PIPE, as_root=True) |
3611 | + stdout, _ = p.communicate() |
3612 | + return stdout.split() |
3613 | + |
3614 | + |
3615 | def move_contents(from_, root_disk): |
3616 | """Move everything under from_ to the given root disk. |
3617 | |
3618 | Uses sudo for moving. |
3619 | """ |
3620 | assert os.path.isdir(from_), "%s is not a directory" % from_ |
3621 | - files = glob.glob(os.path.join(from_, '*')) |
3622 | + files = _list_files(from_) |
3623 | mv_cmd = ['mv'] |
3624 | mv_cmd.extend(sorted(files)) |
3625 | mv_cmd.append(root_disk) |
3626 | |
3627 | === modified file 'linaro_image_tools/media_create/tests/test_media_create.py' |
3628 | --- linaro_image_tools/media_create/tests/test_media_create.py 2011-06-14 09:45:13 +0000 |
3629 | +++ linaro_image_tools/media_create/tests/test_media_create.py 2011-07-18 14:39:34 +0000 |
3630 | @@ -28,7 +28,10 @@ |
3631 | import textwrap |
3632 | import time |
3633 | import types |
3634 | +import struct |
3635 | +import tarfile |
3636 | |
3637 | +from StringIO import StringIO |
3638 | from testtools import TestCase |
3639 | |
3640 | from linaro_image_tools import cmd_runner |
3641 | @@ -38,9 +41,11 @@ |
3642 | boards, |
3643 | partitions, |
3644 | rootfs, |
3645 | + android_boards, |
3646 | ) |
3647 | from linaro_image_tools.media_create.boards import ( |
3648 | - LOADER_MIN_SIZE_S, |
3649 | + SAMSUNG_V310_BL1_START, |
3650 | + SAMSUNG_V310_BL2_START, |
3651 | SECTOR_SIZE, |
3652 | align_up, |
3653 | align_partition, |
3654 | @@ -56,6 +61,11 @@ |
3655 | _get_file_matching, |
3656 | _get_mlo_file, |
3657 | _run_mkimage, |
3658 | + HardwarepackHandler, |
3659 | + BoardConfig, |
3660 | + ) |
3661 | +from linaro_image_tools.media_create.android_boards import ( |
3662 | + android_board_configs, |
3663 | ) |
3664 | from linaro_image_tools.media_create.chroot_utils import ( |
3665 | copy_file, |
3666 | @@ -113,6 +123,359 @@ |
3667 | sudo_args = " ".join(cmd_runner.SUDO_ARGS) |
3668 | |
3669 | |
3670 | +class TestHardwarepackHandler(TestCaseWithFixtures): |
3671 | + def setUp(self): |
3672 | + super(TestHardwarepackHandler, self).setUp() |
3673 | + self.tar_dir_fixture = CreateTempDirFixture() |
3674 | + self.useFixture(self.tar_dir_fixture) |
3675 | + |
3676 | + self.tarball_fixture = CreateTarballFixture( |
3677 | + self.tar_dir_fixture.get_temp_dir()) |
3678 | + self.useFixture(self.tarball_fixture) |
3679 | + |
3680 | + self.metadata = ( |
3681 | + "NAME=ahwpack\nVERSION=4\nARCHITECTURE=armel\nORIGIN=linaro\n") |
3682 | + |
3683 | + def add_to_tarball(self, files, tarball=None): |
3684 | + if tarball is None: |
3685 | + tarball = self.tarball_fixture.get_tarball() |
3686 | + tar_file = tarfile.open(tarball, mode='w:gz') |
3687 | + for filename, data in files: |
3688 | + tarinfo = tarfile.TarInfo(filename) |
3689 | + tarinfo.size = len(data) |
3690 | + tar_file.addfile(tarinfo, StringIO(data)) |
3691 | + tar_file.close() |
3692 | + return tarball |
3693 | + |
3694 | + def test_get_format_1(self): |
3695 | + data = '1.0' |
3696 | + format = "%s\n" % data |
3697 | + tarball = self.add_to_tarball( |
3698 | + [('FORMAT', format), ('metadata', self.metadata)]) |
3699 | + hp = HardwarepackHandler([tarball]) |
3700 | + with hp: |
3701 | + self.assertEquals(hp.get_format(), data) |
3702 | + |
3703 | + def test_get_format_2(self): |
3704 | + data = '2.0' |
3705 | + format = "%s\n" % data |
3706 | + tarball = self.add_to_tarball( |
3707 | + [('FORMAT', format), ('metadata', self.metadata)]) |
3708 | + hp = HardwarepackHandler([tarball]) |
3709 | + with hp: |
3710 | + self.assertEquals(hp.get_format(), data) |
3711 | + |
3712 | + def test_get_unknown_format_raises(self): |
3713 | + data = '9.9' |
3714 | + format = "%s\n" % data |
3715 | + tarball = self.add_to_tarball( |
3716 | + [('FORMAT', format), ('metadata', self.metadata)]) |
3717 | + hp = HardwarepackHandler([tarball]) |
3718 | + with hp: |
3719 | + self.assertRaises(AssertionError, hp.get_format) |
3720 | + |
3721 | + def test_mixed_formats(self): |
3722 | + format1 = "%s\n" % '1.0' |
3723 | + format2 = "%s\n" % '2.0' |
3724 | + tarball1 = self.add_to_tarball( |
3725 | + [('FORMAT', format1), ('metadata', self.metadata)], |
3726 | + tarball=self.tarball_fixture.get_tarball()) |
3727 | + tarball_fixture2 = CreateTarballFixture( |
3728 | + self.tar_dir_fixture.get_temp_dir(), reldir='tarfile2', |
3729 | + filename='secondtarball.tar.gz') |
3730 | + self.useFixture(tarball_fixture2) |
3731 | + tarball2 = self.add_to_tarball( |
3732 | + [('FORMAT', format2), ('metadata', self.metadata)], |
3733 | + tarball=tarball_fixture2.get_tarball()) |
3734 | + hp = HardwarepackHandler([tarball2, tarball1]) |
3735 | + with hp: |
3736 | + self.assertEquals(hp.get_format(), '1.0and2.0') |
3737 | + |
3738 | + def test_identical_formats_ok(self): |
3739 | + format1 = "%s\n" % '2.0' |
3740 | + format2 = "%s\n" % '2.0' |
3741 | + tarball1 = self.add_to_tarball( |
3742 | + [('FORMAT', format1), ('metadata', self.metadata)], |
3743 | + tarball=self.tarball_fixture.get_tarball()) |
3744 | + tarball_fixture2 = CreateTarballFixture( |
3745 | + self.tar_dir_fixture.get_temp_dir(), reldir='tarfile2', |
3746 | + filename='secondtarball.tar.gz') |
3747 | + self.useFixture(tarball_fixture2) |
3748 | + tarball2 = self.add_to_tarball( |
3749 | + [('FORMAT', format2), ('metadata', self.metadata)], |
3750 | + tarball=tarball_fixture2.get_tarball()) |
3751 | + hp = HardwarepackHandler([tarball1, tarball2]) |
3752 | + with hp: |
3753 | + self.assertEquals(hp.get_format(), '2.0') |
3754 | + |
3755 | + def test_get_metadata(self): |
3756 | + data = 'data to test' |
3757 | + metadata = self.metadata + "TEST=%s\n" % data |
3758 | + tarball = self.add_to_tarball( |
3759 | + [('metadata', metadata)]) |
3760 | + hp = HardwarepackHandler([tarball]) |
3761 | + with hp: |
3762 | + test_data, _ = hp.get_field(hp.main_section, 'test') |
3763 | + self.assertEqual(test_data, data) |
3764 | + |
3765 | + def test_preserves_formatters(self): |
3766 | + data = '%s%d' |
3767 | + metadata = self.metadata + "TEST=%s\n" % data |
3768 | + tarball = self.add_to_tarball( |
3769 | + [('metadata', metadata)]) |
3770 | + hp = HardwarepackHandler([tarball]) |
3771 | + with hp: |
3772 | + test_data, _ = hp.get_field(hp.main_section, 'test') |
3773 | + self.assertEqual(test_data, data) |
3774 | + |
3775 | + def test_creates_tempdir(self): |
3776 | + tarball = self.add_to_tarball( |
3777 | + [('metadata', self.metadata)]) |
3778 | + hp = HardwarepackHandler([tarball]) |
3779 | + with hp: |
3780 | + self.assertTrue(os.path.exists(hp.tempdir)) |
3781 | + |
3782 | + def test_tempfiles_are_removed(self): |
3783 | + tempdir = None |
3784 | + tarball = self.add_to_tarball( |
3785 | + [('metadata', self.metadata)]) |
3786 | + hp = HardwarepackHandler([tarball]) |
3787 | + with hp: |
3788 | + tempdir = hp.tempdir |
3789 | + self.assertFalse(os.path.exists(tempdir)) |
3790 | + |
3791 | + def test_get_file(self): |
3792 | + data = 'test file contents\n' |
3793 | + metadata_file = 'TESTFILE' |
3794 | + file_in_archive = 'testfile' |
3795 | + metadata = self.metadata + "%s=%s\n" % (metadata_file, file_in_archive) |
3796 | + tarball = self.add_to_tarball( |
3797 | + [('metadata', metadata), |
3798 | + (file_in_archive, data)]) |
3799 | + hp = HardwarepackHandler([tarball]) |
3800 | + with hp: |
3801 | + test_file = hp.get_file(metadata_file) |
3802 | + self.assertEquals(data, open(test_file, 'r').read()) |
3803 | + |
3804 | + |
3805 | +class TestSetMetadata(TestCaseWithFixtures): |
3806 | + |
3807 | + class MockHardwarepackHandler(HardwarepackHandler): |
3808 | + metadata_dict = {} |
3809 | + |
3810 | + def __enter__(self): |
3811 | + return self |
3812 | + |
3813 | + def get_field(self, section, field): |
3814 | + try: |
3815 | + return self.metadata_dict[field], None |
3816 | + except: |
3817 | + return None, None |
3818 | + |
3819 | + def get_format(self): |
3820 | + return '2.0' |
3821 | + |
3822 | + def get_file(self, file_alias): |
3823 | + return None |
3824 | + |
3825 | + def test_does_not_set_if_old_format(self): |
3826 | + self.useFixture(MockSomethingFixture( |
3827 | + linaro_image_tools.media_create.boards, 'HardwarepackHandler', |
3828 | + self.MockHardwarepackHandler)) |
3829 | + |
3830 | + class config(BoardConfig): |
3831 | + pass |
3832 | + config.set_metadata('ahwpack.tar.gz') |
3833 | + self.assertEquals(None, config.kernel_addr) |
3834 | + |
3835 | + def test_sets_kernel_addr(self): |
3836 | + self.useFixture(MockSomethingFixture( |
3837 | + linaro_image_tools.media_create.boards, 'HardwarepackHandler', |
3838 | + self.MockHardwarepackHandler)) |
3839 | + field_to_test = 'kernel_addr' |
3840 | + data_to_set = '0x8123ABCD' |
3841 | + self.MockHardwarepackHandler.metadata_dict = { |
3842 | + field_to_test: data_to_set, |
3843 | + } |
3844 | + class config(BoardConfig): |
3845 | + pass |
3846 | + config.set_metadata('ahwpack.tar.gz') |
3847 | + self.assertEquals(data_to_set, config.kernel_addr) |
3848 | + |
3849 | + def test_sets_initrd_addr(self): |
3850 | + self.useFixture(MockSomethingFixture( |
3851 | + linaro_image_tools.media_create.boards, 'HardwarepackHandler', |
3852 | + self.MockHardwarepackHandler)) |
3853 | + field_to_test = 'initrd_addr' |
3854 | + data_to_set = '0x8123ABCD' |
3855 | + self.MockHardwarepackHandler.metadata_dict = { |
3856 | + field_to_test: data_to_set, |
3857 | + } |
3858 | + class config(BoardConfig): |
3859 | + pass |
3860 | + config.set_metadata('ahwpack.tar.gz') |
3861 | + self.assertEquals(data_to_set, config.initrd_addr) |
3862 | + |
3863 | + def test_sets_load_addr(self): |
3864 | + self.useFixture(MockSomethingFixture( |
3865 | + linaro_image_tools.media_create.boards, 'HardwarepackHandler', |
3866 | + self.MockHardwarepackHandler)) |
3867 | + field_to_test = 'load_addr' |
3868 | + data_to_set = '0x8123ABCD' |
3869 | + self.MockHardwarepackHandler.metadata_dict = { |
3870 | + field_to_test: data_to_set, |
3871 | + } |
3872 | + class config(BoardConfig): |
3873 | + pass |
3874 | + config.set_metadata('ahwpack.tar.gz') |
3875 | + self.assertEquals(data_to_set, config.load_addr) |
3876 | + |
3877 | + def test_sets_serial_tty(self): |
3878 | + self.useFixture(MockSomethingFixture( |
3879 | + linaro_image_tools.media_create.boards, 'HardwarepackHandler', |
3880 | + self.MockHardwarepackHandler)) |
3881 | + field_to_test = 'serial_tty' |
3882 | + data_to_set = 'ttyAA' |
3883 | + self.MockHardwarepackHandler.metadata_dict = { |
3884 | + field_to_test: data_to_set, |
3885 | + } |
3886 | + class config(BoardConfig): |
3887 | + pass |
3888 | + config.set_metadata('ahwpack.tar.gz') |
3889 | + self.assertEquals(data_to_set, config.serial_tty) |
3890 | + |
3891 | + def test_sets_wired_interfaces(self): |
3892 | + self.useFixture(MockSomethingFixture( |
3893 | + linaro_image_tools.media_create.boards, 'HardwarepackHandler', |
3894 | + self.MockHardwarepackHandler)) |
3895 | + field_to_test = 'wired_interfaces' |
3896 | + data_to_set = 'eth0 eth1' |
3897 | + self.MockHardwarepackHandler.metadata_dict = { |
3898 | + field_to_test: data_to_set, |
3899 | + } |
3900 | + class config(BoardConfig): |
3901 | + pass |
3902 | + config.set_metadata('ahwpack.tar.gz') |
3903 | + self.assertEquals(data_to_set, config.wired_interfaces) |
3904 | + |
3905 | + def test_sets_wireless_interfaces(self): |
3906 | + self.useFixture(MockSomethingFixture( |
3907 | + linaro_image_tools.media_create.boards, 'HardwarepackHandler', |
3908 | + self.MockHardwarepackHandler)) |
3909 | + field_to_test = 'wireless_interfaces' |
3910 | + data_to_set = 'wlan0 wl1' |
3911 | + self.MockHardwarepackHandler.metadata_dict = { |
3912 | + field_to_test: data_to_set, |
3913 | + } |
3914 | + class config(BoardConfig): |
3915 | + pass |
3916 | + config.set_metadata('ahwpack.tar.gz') |
3917 | + self.assertEquals(data_to_set, config.wireless_interfaces) |
3918 | + |
3919 | + def test_sets_mmc_id(self): |
3920 | + self.useFixture(MockSomethingFixture( |
3921 | + linaro_image_tools.media_create.boards, 'HardwarepackHandler', |
3922 | + self.MockHardwarepackHandler)) |
3923 | + field_to_test = 'mmc_id' |
3924 | + data_to_set = '1' |
3925 | + self.MockHardwarepackHandler.metadata_dict = { |
3926 | + field_to_test: data_to_set, |
3927 | + } |
3928 | + class config(BoardConfig): |
3929 | + pass |
3930 | + config.set_metadata('ahwpack.tar.gz') |
3931 | + self.assertEquals(data_to_set, config.mmc_id) |
3932 | + |
3933 | + def test_sets_boot_min_size(self): |
3934 | + self.useFixture(MockSomethingFixture( |
3935 | + linaro_image_tools.media_create.boards, 'HardwarepackHandler', |
3936 | + self.MockHardwarepackHandler)) |
3937 | + field_to_test = 'boot_min_size' |
3938 | + data_to_set = '100' |
3939 | + expected = align_up(int(data_to_set) * 1024 * 1024, |
3940 | + SECTOR_SIZE) / SECTOR_SIZE |
3941 | + self.MockHardwarepackHandler.metadata_dict = { |
3942 | + field_to_test: data_to_set, |
3943 | + } |
3944 | + class config(BoardConfig): |
3945 | + pass |
3946 | + config.set_metadata('ahwpack.tar.gz') |
3947 | + self.assertEquals(expected, config.BOOT_MIN_SIZE_S) |
3948 | + |
3949 | + def test_sets_root_min_size(self): |
3950 | + self.useFixture(MockSomethingFixture( |
3951 | + linaro_image_tools.media_create.boards, 'HardwarepackHandler', |
3952 | + self.MockHardwarepackHandler)) |
3953 | + field_to_test = 'root_min_size' |
3954 | + data_to_set = '3' |
3955 | + expected = align_up(int(data_to_set) * 1024 * 1024, |
3956 | + SECTOR_SIZE) / SECTOR_SIZE |
3957 | + self.MockHardwarepackHandler.metadata_dict = { |
3958 | + field_to_test: data_to_set, |
3959 | + } |
3960 | + class config(BoardConfig): |
3961 | + pass |
3962 | + config.set_metadata('ahwpack.tar.gz') |
3963 | + self.assertEquals(expected, config.ROOT_MIN_SIZE_S) |
3964 | + |
3965 | + def test_sets_loader_min_size(self): |
3966 | + self.useFixture(MockSomethingFixture( |
3967 | + linaro_image_tools.media_create.boards, 'HardwarepackHandler', |
3968 | + self.MockHardwarepackHandler)) |
3969 | + field_to_test = 'loader_min_size' |
3970 | + data_to_set = '2' |
3971 | + expected = align_up(int(data_to_set) * 1024 * 1024, |
3972 | + SECTOR_SIZE) / SECTOR_SIZE |
3973 | + self.MockHardwarepackHandler.metadata_dict = { |
3974 | + field_to_test: data_to_set, |
3975 | + } |
3976 | + class config(BoardConfig): |
3977 | + pass |
3978 | + config.set_metadata('ahwpack.tar.gz') |
3979 | + self.assertEquals(expected, config.LOADER_MIN_SIZE_S) |
3980 | + |
3981 | + def test_sets_partition_layout_32(self): |
3982 | + self.useFixture(MockSomethingFixture( |
3983 | + linaro_image_tools.media_create.boards, 'HardwarepackHandler', |
3984 | + self.MockHardwarepackHandler)) |
3985 | + field_to_test = 'partition_layout' |
3986 | + data_to_set = 'bootfs_rootfs' |
3987 | + self.MockHardwarepackHandler.metadata_dict = { |
3988 | + field_to_test: data_to_set, |
3989 | + } |
3990 | + class config(BoardConfig): |
3991 | + pass |
3992 | + config.set_metadata('ahwpack.tar.gz') |
3993 | + self.assertEquals(32, config.fat_size) |
3994 | + |
3995 | + def test_sets_partition_layout_16(self): |
3996 | + self.useFixture(MockSomethingFixture( |
3997 | + linaro_image_tools.media_create.boards, 'HardwarepackHandler', |
3998 | + self.MockHardwarepackHandler)) |
3999 | + field_to_test = 'partition_layout' |
4000 | + data_to_set = 'bootfs16_rootfs' |
4001 | + self.MockHardwarepackHandler.metadata_dict = { |
4002 | + field_to_test: data_to_set, |
4003 | + } |
4004 | + class config(BoardConfig): |
4005 | + pass |
4006 | + config.set_metadata('ahwpack.tar.gz') |
4007 | + self.assertEquals(16, config.fat_size) |
4008 | + |
4009 | + def test_sets_partition_layout_raises(self): |
4010 | + self.useFixture(MockSomethingFixture( |
4011 | + linaro_image_tools.media_create.boards, 'HardwarepackHandler', |
4012 | + self.MockHardwarepackHandler)) |
4013 | + field_to_test = 'partition_layout' |
4014 | + data_to_set = 'bootfs_bogus_rootfs' |
4015 | + self.MockHardwarepackHandler.metadata_dict = { |
4016 | + field_to_test: data_to_set, |
4017 | + } |
4018 | + class config(BoardConfig): |
4019 | + pass |
4020 | + self.assertRaises(AssertionError, config.set_metadata, 'ahwpack.tar.gz') |
4021 | + |
4022 | + |
4023 | class TestGetMLOFile(TestCaseWithFixtures): |
4024 | |
4025 | def test_mlo_from_new_xloader(self): |
4026 | @@ -150,6 +513,325 @@ |
4027 | AssertionError, _get_mlo_file, tempdir) |
4028 | |
4029 | |
4030 | +def _create_uboot_dir(root, flavor): |
4031 | + path = os.path.join(root, 'usr', 'lib', 'u-boot', flavor) |
4032 | + os.makedirs(path) |
4033 | + return path |
4034 | + |
4035 | + |
4036 | +class TestGetSMDKSPL(TestCaseWithFixtures): |
4037 | + config = boards.SMDKV310Config |
4038 | + |
4039 | + def test_no_file_present(self): |
4040 | + tempdir = self.useFixture(CreateTempDirFixture()).get_temp_dir() |
4041 | + self.assertRaises( |
4042 | + AssertionError, self.config._get_samsung_spl, tempdir) |
4043 | + |
4044 | + def test_old_file_present(self): |
4045 | + tempdir = self.useFixture(CreateTempDirFixture()).get_temp_dir() |
4046 | + path = _create_uboot_dir(tempdir, self.config.uboot_flavor) |
4047 | + spl_path = os.path.join(path, 'v310_mmc_spl.bin') |
4048 | + open(spl_path, 'w').close() |
4049 | + self.assertEquals(spl_path, self.config._get_samsung_spl(tempdir)) |
4050 | + |
4051 | + def test_new_file_present(self): |
4052 | + tempdir = self.useFixture(CreateTempDirFixture()).get_temp_dir() |
4053 | + path = _create_uboot_dir(tempdir, self.config.uboot_flavor) |
4054 | + spl_path = os.path.join(path, 'u-boot-mmc-spl.bin') |
4055 | + open(spl_path, 'w').close() |
4056 | + self.assertEquals(spl_path, self.config._get_samsung_spl(tempdir)) |
4057 | + |
4058 | + def test_prefers_old_path(self): |
4059 | + tempdir = self.useFixture(CreateTempDirFixture()).get_temp_dir() |
4060 | + path = _create_uboot_dir(tempdir, self.config.uboot_flavor) |
4061 | + old_spl_path = os.path.join(path, 'v310_mmc_spl.bin') |
4062 | + new_spl_path = os.path.join(path, 'u-boot-mmc-spl.bin') |
4063 | + open(old_spl_path, 'w').close() |
4064 | + open(new_spl_path, 'w').close() |
4065 | + self.assertEquals(old_spl_path, self.config._get_samsung_spl(tempdir)) |
4066 | + |
4067 | + |
4068 | +class TestGetSMDKUboot(TestCaseWithFixtures): |
4069 | + config = boards.SMDKV310Config |
4070 | + |
4071 | + def test_uses_uboot_flavour(self): |
4072 | + chroot_dir = "chroot" |
4073 | + uboot_file = os.path.join(chroot_dir, 'usr', 'lib', 'u-boot', |
4074 | + self.config.uboot_flavor, 'u-boot.bin') |
4075 | + self.assertEquals( |
4076 | + uboot_file, self.config._get_samsung_uboot(chroot_dir)) |
4077 | + |
4078 | + |
4079 | +class TestGetOrigenSPL(TestCaseWithFixtures): |
4080 | + config = boards.OrigenConfig |
4081 | + |
4082 | + def test_no_file_present(self): |
4083 | + tempdir = self.useFixture(CreateTempDirFixture()).get_temp_dir() |
4084 | + self.assertRaises( |
4085 | + AssertionError, self.config._get_samsung_spl, tempdir) |
4086 | + |
4087 | + def test_new_file_present(self): |
4088 | + tempdir = self.useFixture(CreateTempDirFixture()).get_temp_dir() |
4089 | + path = _create_uboot_dir(tempdir, self.config.uboot_flavor) |
4090 | + spl_path = os.path.join(path, 'u-boot-mmc-spl.bin') |
4091 | + open(spl_path, 'w').close() |
4092 | + self.assertEquals(spl_path, self.config._get_samsung_spl(tempdir)) |
4093 | + |
4094 | + |
4095 | +class TestGetOrigenUboot(TestGetSMDKUboot): |
4096 | + config = boards.OrigenConfig |
4097 | + |
4098 | + |
4099 | +class TestCreateToc(TestCaseWithFixtures): |
4100 | + ''' Tests boards.SnowballEmmcConfig.create_toc()''' |
4101 | + |
4102 | + def setUp(self): |
4103 | + ''' Create a temporary directory to work in''' |
4104 | + super(TestCreateToc, self).setUp() |
4105 | + self.tempdir = self.useFixture(CreateTempDirFixture()).get_temp_dir() |
4106 | + #Create the test's input data structures |
4107 | + zero = '\x00\x00\x00\x00' |
4108 | + line1 = zero + zero + zero + zero + zero + 'b' + zero + zero + \ |
4109 | + '\x00\x00\x00' |
4110 | + maxint = '\xFF\xFF\xFF\x7F' |
4111 | + minint = '\xFF\xFF\xFF\xFF' |
4112 | + line2 = maxint + maxint + zero + minint + minint + \ |
4113 | + 'hello' + zero + '\x00\x00\x00' |
4114 | + line3 = '\x01\x00\x00\x00' '\x64\x00\x00\x00' + zero + \ |
4115 | + '\x05\x00\x00\x00' '\x05\x00\x00\x00' \ |
4116 | + 'hello' + zero + '\x00\x00\x00' |
4117 | + self.expected = line1 + line2 + line3 |
4118 | + |
4119 | + def create_files_structure(self, src_data): |
4120 | + ''' Creates the data structure that the tested function |
4121 | + needs as input''' |
4122 | + files = [] |
4123 | + for line in src_data: |
4124 | + files.append({'section_name': line[5], |
4125 | + 'filename': 'N/A', |
4126 | + 'align': line[3], |
4127 | + 'offset': line[0], |
4128 | + 'size': line[1], |
4129 | + 'load_adress': 'N/A'}) |
4130 | + return files |
4131 | + |
4132 | + def test_create_toc_normal_case(self): |
4133 | + ''' Creates a toc file, and then reads the created |
4134 | + file and compares it to precomputed data''' |
4135 | + correct_data = [(0, 0, 0, 0, 0, 'b'), |
4136 | + (0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF, -1, -1, 'hello'), |
4137 | + (1, 100, 1000, 5, 10, 'hello')] |
4138 | + files = self.create_files_structure(correct_data) |
4139 | + filename = os.path.join(self.tempdir, 'toc') |
4140 | + with open(filename, 'w') as f: |
4141 | + boards.SnowballEmmcConfig.create_toc(f, files) |
4142 | + with open(filename, 'r') as f: |
4143 | + actual = f.read() |
4144 | + self.assertEquals(96, len(actual)) |
4145 | + for i in range(len(actual)): |
4146 | + self.assertEquals(self.expected[i], actual[i], 'Mismatch at ix' \ |
4147 | + ' %d, ref=%c, actual=%c' % (i, self.expected[i], actual[i])) |
4148 | + |
4149 | + def test_create_toc_error_too_large_section_name(self): |
4150 | + '''Verify that trying to write past the end of the |
4151 | + section name field raises an exception''' |
4152 | + illegal_name_data = [(0, 0, 0, 0, 0, 'Too_longName')] |
4153 | + files = self.create_files_structure(illegal_name_data) |
4154 | + with open(os.path.join(self.tempdir, 'toc'), 'w') as f: |
4155 | + self.assertRaises(AssertionError, |
4156 | + boards.SnowballEmmcConfig.create_toc, |
4157 | + f, files) |
4158 | + |
4159 | + def test_create_toc_error_negative_unsigned(self): |
4160 | + '''Verify that trying to write a negative number to an unsigned |
4161 | + field raises an exception''' |
4162 | + illegal_unsigned_data = [(-3, 0, 0, 0, 0, 'xxx')] |
4163 | + files = self.create_files_structure(illegal_unsigned_data) |
4164 | + with open(os.path.join(self.tempdir, 'toc'), 'w') as f: |
4165 | + self.assertRaises(struct.error, |
4166 | + boards.SnowballEmmcConfig.create_toc, |
4167 | + f, files) |
4168 | + |
4169 | + |
4170 | +class TestSnowballBootFiles(TestCaseWithFixtures): |
4171 | + ''' Tests boards.SnowballEmmcConfig.install_snowball_boot_loader()''' |
4172 | + ''' Tests boards.SnowballEmmcConfig._make_boot_files()''' |
4173 | + ''' Tests boards.SnowballEmmcConfig.get_file_info()''' |
4174 | + |
4175 | + def setUp(self): |
4176 | + ''' Create temporary directory to work in''' |
4177 | + super(TestSnowballBootFiles, self).setUp() |
4178 | + self.tempdir = self.useFixture(CreateTempDirFixture()).get_temp_dir() |
4179 | + self.temp_bootdir_path = os.path.join(self.tempdir, 'boot') |
4180 | + if not os.path.exists(self.temp_bootdir_path): |
4181 | + os.makedirs(self.temp_bootdir_path) |
4182 | + |
4183 | + def setupFiles(self): |
4184 | + ''' Adds some files in the temp dir that the tested function |
4185 | + can use as input: |
4186 | + * A config file, which the tested function reads to |
4187 | + discover which binary files should be written to |
4188 | + the loader partition. |
4189 | + * Test versions of the binary files themselves, |
4190 | + containing dummy data. |
4191 | + Returns the expected value that the tested function should |
4192 | + return, given these input files. ''' |
4193 | + src_data = [('ISSW', 'boot_image_issw.bin', -1, 0, '5'), |
4194 | + ('X-LOADER', 'boot_image_x-loader.bin', -1, 0, '6'), |
4195 | + ('MEM_INIT', 'mem_init.bin', 0, 0x160000, '7'), |
4196 | + ('PWR_MGT', 'power_management.bin', 0, 0x170000, '8'), |
4197 | + ('NORMAL', 'u-boot.bin', 0, 0xBA0000, '9'), |
4198 | + ('UBOOT_ENV', 'u-boot-env.bin', 0, 0x00C1F000, '10')] |
4199 | + # Create a config file |
4200 | + cfg_file = os.path.join(self.temp_bootdir_path, |
4201 | + boards.SnowballEmmcConfig.SNOWBALL_STARTUP_FILES_CONFIG) |
4202 | + with open(cfg_file, 'w') as f: |
4203 | + for line in src_data: |
4204 | + # Write comments, so we test that the parser can read them |
4205 | + f.write('#Yet another comment\n') |
4206 | + f.write('%s %s %i %#x %s\n' % line) |
4207 | + expected = [] |
4208 | + # Define dummy binary files, containing nothing but their own |
4209 | + # section names. |
4210 | + for line in src_data: |
4211 | + with open(os.path.join(self.temp_bootdir_path, line[1]), 'w') as f: |
4212 | + f.write(line[0]) |
4213 | + #define the expected values read from the config file |
4214 | + expected = [] |
4215 | + ofs = [boards.SnowballEmmcConfig.TOC_SIZE, |
4216 | + boards.SnowballEmmcConfig.TOC_SIZE + len('ISSW'), 0x160000, |
4217 | + 0x170000, 0xBA0000, 0xC1F000] |
4218 | + size = [len('ISSW'), len('X-LOADER'), len('MEM_INIT'), \ |
4219 | + len('PWR_MGT'), len('NORMAL'), len('UBOOT_ENV')] |
4220 | + i = 0 |
4221 | + for line in src_data: |
4222 | + filename = os.path.join(self.temp_bootdir_path, line[1]) |
4223 | + expected.append({'section_name': line[0], |
4224 | + 'filename': filename, |
4225 | + 'align': int(line[2]), |
4226 | + 'offset': ofs[i], |
4227 | + 'size': long(size[i]), |
4228 | + 'load_adress': line[4]}) |
4229 | + i += 1 |
4230 | + return expected |
4231 | + |
4232 | + def test_file_name_size(self): |
4233 | + ''' Test using a to large toc file ''' |
4234 | + _, toc_filename = tempfile.mkstemp() |
4235 | + atexit.register(os.unlink, toc_filename) |
4236 | + filedata = 'X' |
4237 | + bytes = boards.SnowballEmmcConfig.TOC_SIZE + 1 |
4238 | + tmpfile = open(toc_filename, 'wb') |
4239 | + for n in xrange(bytes): |
4240 | + tmpfile.write(filedata) |
4241 | + tmpfile.close() |
4242 | + files = self.setupFiles() |
4243 | + self.assertRaises(AssertionError, |
4244 | + boards.SnowballEmmcConfig.install_snowball_boot_loader, |
4245 | + toc_filename, files, "boot_device_or_file", |
4246 | + boards.SnowballEmmcConfig.SNOWBALL_LOADER_START_S) |
4247 | + |
4248 | + def test_install_snowball_boot_loader_toc(self): |
4249 | + fixture = self.useFixture(MockCmdRunnerPopenFixture()) |
4250 | + toc_filename = self.createTempFileAsFixture() |
4251 | + files = self.setupFiles() |
4252 | + boards.SnowballEmmcConfig.install_snowball_boot_loader(toc_filename, |
4253 | + files, "boot_device_or_file", |
4254 | + boards.SnowballEmmcConfig.SNOWBALL_LOADER_START_S) |
4255 | + expected = [ |
4256 | + '%s dd if=%s of=boot_device_or_file bs=512 conv=notrunc' \ |
4257 | + ' seek=%s' % (sudo_args, toc_filename, |
4258 | + boards.SnowballEmmcConfig.SNOWBALL_LOADER_START_S), |
4259 | + '%s dd if=%s/boot_image_issw.bin of=boot_device_or_file bs=512' \ |
4260 | + ' conv=notrunc seek=257' % (sudo_args, self.temp_bootdir_path), |
4261 | + '%s rm %s/boot_image_issw.bin' % (sudo_args, |
4262 | + self.temp_bootdir_path), |
4263 | + '%s dd if=%s/boot_image_x-loader.bin of=boot_device_or_file' \ |
4264 | + ' bs=1 conv=notrunc seek=131588' |
4265 | + % (sudo_args, self.temp_bootdir_path), |
4266 | + '%s rm %s/boot_image_x-loader.bin' % (sudo_args, |
4267 | + self.temp_bootdir_path), |
4268 | + '%s dd if=%s/mem_init.bin of=boot_device_or_file bs=512' \ |
4269 | + ' conv=notrunc seek=3072' % (sudo_args, self.temp_bootdir_path), |
4270 | + '%s rm %s/mem_init.bin' % (sudo_args, self.temp_bootdir_path), |
4271 | + '%s dd if=%s/power_management.bin of=boot_device_or_file bs=512' \ |
4272 | + ' conv=notrunc seek=3200' % (sudo_args, self.temp_bootdir_path), |
4273 | + '%s rm %s/power_management.bin' % (sudo_args, |
4274 | + self.temp_bootdir_path), |
4275 | + '%s dd if=%s/u-boot.bin of=boot_device_or_file bs=512' \ |
4276 | + ' conv=notrunc seek=24064' % (sudo_args, self.temp_bootdir_path), |
4277 | + '%s rm %s/u-boot.bin' % (sudo_args, self.temp_bootdir_path), |
4278 | + '%s dd if=%s/u-boot-env.bin of=boot_device_or_file bs=512' |
4279 | + ' conv=notrunc seek=25080' % (sudo_args, self.temp_bootdir_path), |
4280 | + '%s rm %s/u-boot-env.bin' % (sudo_args, self.temp_bootdir_path)] |
4281 | + |
4282 | + self.assertEqual(expected, fixture.mock.commands_executed) |
4283 | + |
4284 | + def test_snowball_make_boot_files(self): |
4285 | + fixture = self.useFixture(MockCmdRunnerPopenFixture()) |
4286 | + self.useFixture(MockSomethingFixture(tempfile, 'mkstemp', |
4287 | + lambda: (-1, '/tmp/temp_snowball_make_boot_files'))) |
4288 | + self.setupFiles() |
4289 | + k_img_file = os.path.join(self.tempdir, 'vmlinuz-1-ux500') |
4290 | + i_img_file = os.path.join(self.tempdir, 'initrd.img-1-ux500') |
4291 | + |
4292 | + boot_env = board_configs['snowball_emmc']._get_boot_env( |
4293 | + is_live=False, is_lowmem=False, consoles=[], |
4294 | + rootfs_uuid="test_boot_env_uuid", d_img_data=None) |
4295 | + boards.SnowballEmmcConfig._make_boot_files(boot_env, self.tempdir, |
4296 | + self.temp_bootdir_path, 'boot_device_or_file', k_img_file, |
4297 | + i_img_file, None) |
4298 | + expected = [ |
4299 | + '%s mkimage -A arm -O linux -T kernel -C none -a 0x00008000 -e' \ |
4300 | + ' 0x00008000 -n Linux -d %s %s/boot/uImage' % (sudo_args, |
4301 | + k_img_file, self.tempdir), |
4302 | + '%s cp /tmp/temp_snowball_make_boot_files %s/boot/boot.txt' |
4303 | + % (sudo_args, self.tempdir), |
4304 | + '%s mkimage -A arm -O linux -T script -C none -a 0 -e 0 -n boot' \ |
4305 | + ' script -d %s/boot/boot.txt %s/boot/flash.scr' |
4306 | + % (sudo_args, self.tempdir, self.tempdir), |
4307 | + '%s dd if=/tmp/temp_snowball_make_boot_files' \ |
4308 | + ' of=boot_device_or_file bs=512 conv=notrunc seek=256' |
4309 | + % (sudo_args), |
4310 | + '%s dd if=%s/boot/boot_image_issw.bin of=boot_device_or_file' \ |
4311 | + ' bs=512 conv=notrunc seek=257' % (sudo_args, self.tempdir), |
4312 | + '%s rm %s/boot_image_issw.bin' % (sudo_args, |
4313 | + self.temp_bootdir_path), |
4314 | + '%s dd if=%s/boot/boot_image_x-loader.bin of=boot_device_or_file' \ |
4315 | + ' bs=1 conv=notrunc seek=131588' % (sudo_args, self.tempdir), |
4316 | + '%s rm %s/boot_image_x-loader.bin' % (sudo_args, |
4317 | + self.temp_bootdir_path), |
4318 | + '%s dd if=%s/boot/mem_init.bin of=boot_device_or_file bs=512' \ |
4319 | + ' conv=notrunc seek=3072' % (sudo_args, self.tempdir), |
4320 | + '%s rm %s/mem_init.bin' % (sudo_args, self.temp_bootdir_path), |
4321 | + '%s dd if=%s/boot/power_management.bin of=boot_device_or_file' \ |
4322 | + ' bs=512 conv=notrunc seek=3200' % (sudo_args, self.tempdir), |
4323 | + '%s rm %s/power_management.bin' % (sudo_args, |
4324 | + self.temp_bootdir_path), |
4325 | + '%s dd if=%s/boot/u-boot.bin of=boot_device_or_file bs=512' \ |
4326 | + ' conv=notrunc seek=24064' % (sudo_args, self.tempdir), |
4327 | + '%s rm %s/u-boot.bin' % (sudo_args, self.temp_bootdir_path), |
4328 | + '%s dd if=%s/boot/u-boot-env.bin of=boot_device_or_file bs=512' \ |
4329 | + ' conv=notrunc seek=25080' % (sudo_args, self.tempdir), |
4330 | + '%s rm %s/u-boot-env.bin' % (sudo_args, self.temp_bootdir_path), |
4331 | + '%s rm /tmp/temp_snowball_make_boot_files' % (sudo_args), |
4332 | + '%s rm %s/startfiles.cfg' % (sudo_args, self.temp_bootdir_path)] |
4333 | + |
4334 | + self.assertEqual(expected, fixture.mock.commands_executed) |
4335 | + |
4336 | + def test_missing_files(self): |
4337 | + '''When the files cannot be read, an IOError should be raised''' |
4338 | + self.assertRaises(IOError, |
4339 | + boards.SnowballEmmcConfig.get_file_info, |
4340 | + self.tempdir) |
4341 | + |
4342 | + def test_normal_case(self): |
4343 | + expected = self.setupFiles() |
4344 | + actual = boards.SnowballEmmcConfig.get_file_info( |
4345 | + self.temp_bootdir_path) |
4346 | + self.assertEquals(expected, actual) |
4347 | + |
4348 | + |
4349 | class TestBootSteps(TestCaseWithFixtures): |
4350 | |
4351 | def setUp(self): |
4352 | @@ -199,6 +881,10 @@ |
4353 | def test_mx5_steps(self): |
4354 | class SomeMx5Config(boards.Mx5Config): |
4355 | uboot_flavor = 'uboot_flavor' |
4356 | + SomeMx5Config.hardwarepack_handler = ( |
4357 | + TestSetMetadata.MockHardwarepackHandler('ahwpack.tar.gz')) |
4358 | + SomeMx5Config.hardwarepack_handler.get_format = ( |
4359 | + lambda: '1.0') |
4360 | self.make_boot_files(SomeMx5Config) |
4361 | expected = [ |
4362 | 'install_mx5_boot_loader', 'make_uImage', 'make_uInitrd', |
4363 | @@ -206,9 +892,40 @@ |
4364 | self.assertEqual(expected, self.funcs_calls) |
4365 | |
4366 | def test_smdkv310_steps(self): |
4367 | + def mock_func_creator(name): |
4368 | + return classmethod( |
4369 | + lambda *args, **kwargs: self.funcs_calls.append(name)) |
4370 | + |
4371 | + self.useFixture(MockSomethingFixture( |
4372 | + linaro_image_tools.media_create.boards.SMDKV310Config, |
4373 | + 'install_samsung_boot_loader', |
4374 | + mock_func_creator('install_samsung_boot_loader'))) |
4375 | + boards.SMDKV310Config.hardwarepack_handler = ( |
4376 | + TestSetMetadata.MockHardwarepackHandler('ahwpack.tar.gz')) |
4377 | + boards.SMDKV310Config.hardwarepack_handler.get_format = ( |
4378 | + lambda: '1.0') |
4379 | self.make_boot_files(boards.SMDKV310Config) |
4380 | expected = [ |
4381 | - '_dd', '_dd', 'make_flashable_env', '_dd', 'make_uImage', |
4382 | + 'install_samsung_boot_loader', 'make_flashable_env', '_dd', 'make_uImage', |
4383 | + 'make_uInitrd', 'make_boot_script'] |
4384 | + self.assertEqual(expected, self.funcs_calls) |
4385 | + |
4386 | + def test_origen_steps(self): |
4387 | + def mock_func_creator(name): |
4388 | + return classmethod( |
4389 | + lambda *args, **kwargs: self.funcs_calls.append(name)) |
4390 | + |
4391 | + self.useFixture(MockSomethingFixture( |
4392 | + linaro_image_tools.media_create.boards.OrigenConfig, |
4393 | + 'install_samsung_boot_loader', |
4394 | + mock_func_creator('install_samsung_boot_loader'))) |
4395 | + boards.OrigenConfig.hardwarepack_handler = ( |
4396 | + TestSetMetadata.MockHardwarepackHandler('ahwpack.tar.gz')) |
4397 | + boards.OrigenConfig.hardwarepack_handler.get_format = ( |
4398 | + lambda: '1.0') |
4399 | + self.make_boot_files(boards.OrigenConfig) |
4400 | + expected = [ |
4401 | + 'install_samsung_boot_loader', 'make_flashable_env', '_dd', 'make_uImage', |
4402 | 'make_uInitrd', 'make_boot_script'] |
4403 | self.assertEqual(expected, self.funcs_calls) |
4404 | |
4405 | @@ -354,6 +1071,23 @@ |
4406 | '1,8191,0xDA\n8192,106496,0x0C,*\n114688,,,-', |
4407 | board_configs['smdkv310'].get_sfdisk_cmd()) |
4408 | |
4409 | + def test_origen(self): |
4410 | + self.assertEquals( |
4411 | + '1,8191,0xDA\n8192,106496,0x0C,*\n114688,,,-', |
4412 | + board_configs['origen'].get_sfdisk_cmd()) |
4413 | + |
4414 | + def test_panda_android(self): |
4415 | + self.assertEqual( |
4416 | + '63,270272,0x0C,*\n270336,524288,L\n794624,524288,L\n' \ |
4417 | + '1318912,-,E\n1318912,1048576,L\n2367488,,,-', |
4418 | + android_boards.AndroidPandaConfig.get_sfdisk_cmd()) |
4419 | + |
4420 | + def test_snowball_emmc_android(self): |
4421 | + self.assertEqual( |
4422 | + '256,7936,0xDA\n8192,262144,0x0C,*\n270336,524288,L\n' \ |
4423 | + '794624,-,E\n794624,524288,L\n1318912,1048576,L\n2367488,,,-', |
4424 | + android_boards.AndroidSnowballEmmcConfig.get_sfdisk_cmd()) |
4425 | + |
4426 | |
4427 | class TestGetBootCmd(TestCase): |
4428 | |
4429 | @@ -396,6 +1130,18 @@ |
4430 | 'ethaddr': '00:40:5c:26:0a:5b'} |
4431 | self.assertEqual(expected, boot_commands) |
4432 | |
4433 | + def test_origen(self): |
4434 | + boot_commands = board_configs['origen']._get_boot_env( |
4435 | + is_live=False, is_lowmem=False, consoles=[], |
4436 | + rootfs_uuid="deadbeef", d_img_data=None) |
4437 | + expected = { |
4438 | + 'bootargs': 'console=ttySAC2,115200n8 root=UUID=deadbeef ' |
4439 | + 'rootwait ro', |
4440 | + 'bootcmd': 'fatload mmc 0:2 0x40007000 uImage; ' |
4441 | + 'fatload mmc 0:2 0x42000000 uInitrd; ' |
4442 | + 'bootm 0x40007000 0x42000000'} |
4443 | + self.assertEqual(expected, boot_commands) |
4444 | + |
4445 | def test_ux500(self): |
4446 | boot_commands = board_configs['ux500']._get_boot_env( |
4447 | is_live=False, is_lowmem=False, consoles=[], |
4448 | @@ -509,6 +1255,41 @@ |
4449 | self.assertEqual(expected, boot_commands) |
4450 | |
4451 | |
4452 | +class TestGetBootCmdAndroid(TestCase): |
4453 | + def test_panda(self): |
4454 | + # XXX: To fix bug 697824 we have to change class attributes of our |
4455 | + # OMAP board configs, and some tests do that so to make sure they |
4456 | + # don't interfere with us we'll reset that before doing anything. |
4457 | + config = android_board_configs['panda'] |
4458 | + config.serial_tty = config._serial_tty |
4459 | + boot_commands = config._get_boot_env(consoles=[]) |
4460 | + expected = { |
4461 | + 'bootargs': 'console=tty0 console=ttyO2,115200n8 ' |
4462 | + 'rootwait ro earlyprintk fixrtc ' |
4463 | + 'nocompcache vram=48M omapfb.vram=0:24M,1:24M ' |
4464 | + 'mem=456M@0x80000000 mem=512M@0xA0000000 ' |
4465 | + 'init=/init androidboot.console=ttyO2', |
4466 | + 'bootcmd': 'fatload mmc 0:1 0x80200000 uImage; ' |
4467 | + 'fatload mmc 0:1 0x81600000 uInitrd; ' |
4468 | + 'bootm 0x80200000 0x81600000'} |
4469 | + self.assertEqual(expected, boot_commands) |
4470 | + |
4471 | + def test_android_snowball_emmc(self): |
4472 | + boot_commands = (android_boards.AndroidSnowballEmmcConfig. |
4473 | + _get_boot_env(consoles=[])) |
4474 | + expected = { |
4475 | + 'bootargs': 'console=tty0 console=ttyAMA2,115200n8 ' |
4476 | + 'rootwait ro earlyprintk ' |
4477 | + 'rootdelay=1 fixrtc nocompcache ' |
4478 | + 'mem=128M@0 mali.mali_mem=64M@128M mem=24M@192M ' |
4479 | + 'hwmem=167M@216M mem_issw=1M@383M mem=640M@384M ' |
4480 | + 'vmalloc=256M init=/init androidboot.console=ttyAMA2', |
4481 | + 'bootcmd': 'fatload mmc 1:1 0x00100000 uImage; ' |
4482 | + 'fatload mmc 1:1 0x08000000 uInitrd; ' |
4483 | + 'bootm 0x00100000 0x08000000'} |
4484 | + self.assertEqual(expected, boot_commands) |
4485 | + |
4486 | + |
4487 | class TestUnpackBinaryTarball(TestCaseWithFixtures): |
4488 | |
4489 | def setUp(self): |
4490 | @@ -607,7 +1388,8 @@ |
4491 | def test_install_mx5_boot_loader(self): |
4492 | fixture = self._mock_Popen() |
4493 | imx_file = self.createTempFileAsFixture() |
4494 | - install_mx5_boot_loader(imx_file, "boot_device_or_file") |
4495 | + install_mx5_boot_loader(imx_file, "boot_device_or_file", |
4496 | + BoardConfig.LOADER_MIN_SIZE_S) |
4497 | expected = [ |
4498 | '%s dd if=%s of=boot_device_or_file bs=512 ' |
4499 | 'conv=notrunc seek=2' % (sudo_args, imx_file)] |
4500 | @@ -616,9 +1398,10 @@ |
4501 | def test_install_mx5_boot_loader_too_large(self): |
4502 | self.useFixture(MockSomethingFixture( |
4503 | os.path, "getsize", |
4504 | - lambda s: (LOADER_MIN_SIZE_S - 1) * SECTOR_SIZE + 1)) |
4505 | + lambda s: (BoardConfig.LOADER_MIN_SIZE_S - 1) * SECTOR_SIZE + 1)) |
4506 | self.assertRaises(AssertionError, |
4507 | - install_mx5_boot_loader, "imx_file", "boot_device_or_file") |
4508 | + install_mx5_boot_loader, "imx_file", "boot_device_or_file", |
4509 | + BoardConfig.LOADER_MIN_SIZE_S) |
4510 | |
4511 | def test_install_omap_boot_loader(self): |
4512 | fixture = self._mock_Popen() |
4513 | @@ -630,6 +1413,58 @@ |
4514 | '%s cp -v chroot_dir/MLO boot_disk' % sudo_args, 'sync'] |
4515 | self.assertEqual(expected, fixture.mock.commands_executed) |
4516 | |
4517 | + def test_install_smdk_u_boot(self): |
4518 | + fixture = self._mock_Popen() |
4519 | + uboot_flavor = boards.SMDKV310Config.uboot_flavor |
4520 | + self.useFixture(MockSomethingFixture( |
4521 | + boards.SMDKV310Config, '_get_samsung_spl', |
4522 | + classmethod(lambda cls, chroot_dir: "%s/%s/SPL" % ( |
4523 | + chroot_dir, uboot_flavor)))) |
4524 | + self.useFixture(MockSomethingFixture( |
4525 | + boards.SMDKV310Config, '_get_samsung_uboot', |
4526 | + classmethod(lambda cls, chroot_dir: "%s/%s/uboot" % ( |
4527 | + chroot_dir, uboot_flavor)))) |
4528 | + boards.SMDKV310Config.hardwarepack_handler = ( |
4529 | + TestSetMetadata.MockHardwarepackHandler('ahwpack.tar.gz')) |
4530 | + boards.SMDKV310Config.hardwarepack_handler.get_format = ( |
4531 | + lambda: '1.0') |
4532 | + self.useFixture(MockSomethingFixture(os.path, 'getsize', |
4533 | + lambda file: 1)) |
4534 | + boards.SMDKV310Config.install_samsung_boot_loader( |
4535 | + "chroot_dir", "boot_disk") |
4536 | + expected = [ |
4537 | + '%s dd if=chroot_dir/%s/SPL of=boot_disk bs=512 conv=notrunc ' |
4538 | + 'seek=%d' % (sudo_args, uboot_flavor, SAMSUNG_V310_BL1_START), |
4539 | + '%s dd if=chroot_dir/%s/uboot of=boot_disk bs=512 conv=notrunc ' |
4540 | + 'seek=%d' % (sudo_args, uboot_flavor, SAMSUNG_V310_BL2_START)] |
4541 | + self.assertEqual(expected, fixture.mock.commands_executed) |
4542 | + |
4543 | + def test_install_origen_u_boot(self): |
4544 | + fixture = self._mock_Popen() |
4545 | + uboot_flavor = boards.OrigenConfig.uboot_flavor |
4546 | + self.useFixture(MockSomethingFixture( |
4547 | + boards.OrigenConfig, '_get_samsung_spl', |
4548 | + classmethod(lambda cls, chroot_dir: "%s/%s/SPL" % ( |
4549 | + chroot_dir, uboot_flavor)))) |
4550 | + self.useFixture(MockSomethingFixture( |
4551 | + boards.OrigenConfig, '_get_samsung_uboot', |
4552 | + classmethod(lambda cls, chroot_dir: "%s/%s/uboot" % ( |
4553 | + chroot_dir, uboot_flavor)))) |
4554 | + boards.OrigenConfig.hardwarepack_handler = ( |
4555 | + TestSetMetadata.MockHardwarepackHandler('ahwpack.tar.gz')) |
4556 | + boards.OrigenConfig.hardwarepack_handler.get_format = ( |
4557 | + lambda: '1.0') |
4558 | + self.useFixture(MockSomethingFixture(os.path, 'getsize', |
4559 | + lambda file: 1)) |
4560 | + boards.OrigenConfig.install_samsung_boot_loader( |
4561 | + "chroot_dir", "boot_disk") |
4562 | + expected = [ |
4563 | + '%s dd if=chroot_dir/%s/SPL of=boot_disk bs=512 conv=notrunc ' |
4564 | + 'seek=%d' % (sudo_args, uboot_flavor, SAMSUNG_V310_BL1_START), |
4565 | + '%s dd if=chroot_dir/%s/uboot of=boot_disk bs=512 conv=notrunc ' |
4566 | + 'seek=%d' % (sudo_args, uboot_flavor, SAMSUNG_V310_BL2_START)] |
4567 | + self.assertEqual(expected, fixture.mock.commands_executed) |
4568 | + |
4569 | def test_get_plain_boot_script_contents(self): |
4570 | boot_env = {'bootargs': 'mybootargs', 'bootcmd': 'mybootcmd'} |
4571 | boot_script_data = get_plain_boot_script_contents(boot_env) |
4572 | @@ -820,6 +1655,25 @@ |
4573 | [('1,8191,0xDA\n8192,106496,0x0C,*\n114688,,,-', HEADS, |
4574 | SECTORS, '', self.media.path)], sfdisk_fixture.mock.calls) |
4575 | |
4576 | + def test_create_partitions_for_origen(self): |
4577 | + # For this board we create a one cylinder partition at the beginning. |
4578 | + popen_fixture = self.useFixture(MockCmdRunnerPopenFixture()) |
4579 | + sfdisk_fixture = self.useFixture(MockRunSfdiskCommandsFixture()) |
4580 | + |
4581 | + create_partitions( |
4582 | + board_configs['origen'], self.media, HEADS, SECTORS, '') |
4583 | + |
4584 | + self.assertEqual( |
4585 | + ['%s parted -s %s mklabel msdos' % (sudo_args, self.media.path), |
4586 | + 'sync'], |
4587 | + popen_fixture.mock.commands_executed) |
4588 | + # Notice that we create all partitions in a single sfdisk run because |
4589 | + # every time we run sfdisk it actually repartitions the device, |
4590 | + # erasing any partitions created previously. |
4591 | + self.assertEqual( |
4592 | + [('1,8191,0xDA\n8192,106496,0x0C,*\n114688,,,-', HEADS, |
4593 | + SECTORS, '', self.media.path)], sfdisk_fixture.mock.calls) |
4594 | + |
4595 | def test_create_partitions_for_beagle(self): |
4596 | popen_fixture = self.useFixture(MockCmdRunnerPopenFixture()) |
4597 | sfdisk_fixture = self.useFixture(MockRunSfdiskCommandsFixture()) |
4598 | @@ -893,13 +1747,21 @@ |
4599 | (63 * SECTOR_SIZE, 32768 * SECTOR_SIZE), |
4600 | (32831 * SECTOR_SIZE, 65536 * SECTOR_SIZE), |
4601 | (98367 * SECTOR_SIZE, 65536 * SECTOR_SIZE), |
4602 | - (294975 * SECTOR_SIZE, (self.android_image_size - |
4603 | - 294975 * SECTOR_SIZE)), |
4604 | ((294975 + ext_part_size) * SECTOR_SIZE, |
4605 | (131072 - ext_part_size) * SECTOR_SIZE), |
4606 | ((426047 + ext_part_size) * SECTOR_SIZE, |
4607 | self.android_image_size - (426047 + ext_part_size) * SECTOR_SIZE) |
4608 | ] |
4609 | + |
4610 | + self.android_snowball_offsets_and_sizes = [ |
4611 | + (8192 * SECTOR_SIZE, 24639 * SECTOR_SIZE), |
4612 | + (32831 * SECTOR_SIZE, 65536 * SECTOR_SIZE), |
4613 | + ((98367 + ext_part_size)* SECTOR_SIZE, |
4614 | + (65536 - ext_part_size) * SECTOR_SIZE), |
4615 | + (294975 * SECTOR_SIZE, 131072 * SECTOR_SIZE), |
4616 | + ((426047 + ext_part_size) * SECTOR_SIZE, |
4617 | + self.android_image_size - (426047 + ext_part_size) * SECTOR_SIZE) |
4618 | + ] |
4619 | |
4620 | def tearDown(self): |
4621 | super(TestPartitionSetup, self).tearDown() |
4622 | @@ -916,6 +1778,13 @@ |
4623 | '63,32768,0x0C,*\n32831,65536,L\n98367,65536,L\n294975,-,E\n' \ |
4624 | '294975,131072,L\n426047,,,-', '%s' % self.android_image_size) |
4625 | |
4626 | + def _create_snowball_android_tmpfile(self): |
4627 | + # raw, boot, system, cache, (extended), userdata and sdcard partitions |
4628 | + return self._create_qemu_img_with_partitions( |
4629 | + '256,7936,0xDA\n8192,24639,0x0C,*\n32831,65536,L\n' \ |
4630 | + '98367,-,E\n98367,65536,L\n294975,131072,L\n' \ |
4631 | + '426047,,,-', '%s' % self.android_image_size) |
4632 | + |
4633 | def test_convert_size_no_suffix(self): |
4634 | self.assertEqual(524288, convert_size_to_bytes('524288')) |
4635 | |
4636 | @@ -945,6 +1814,15 @@ |
4637 | self.android_offsets_and_sizes): |
4638 | self.assertEqual(device_pair, expected_pair) |
4639 | |
4640 | + def test_calculate_snowball_android_partition_size_and_offset(self): |
4641 | + tmpfile = self._create_snowball_android_tmpfile() |
4642 | + device_info = calculate_android_partition_size_and_offset(tmpfile) |
4643 | + # We use map(None, ...) since it would catch if the lists are not of |
4644 | + # equal length and zip() would not in all cases. |
4645 | + for device_pair, expected_pair in map(None, device_info, |
4646 | + self.android_snowball_offsets_and_sizes): |
4647 | + self.assertEqual(device_pair, expected_pair) |
4648 | + |
4649 | def test_partition_numbering(self): |
4650 | # another Linux partition at +24 MiB after the boot/root parts |
4651 | tmpfile = self._create_qemu_img_with_partitions( |
4652 | @@ -1054,7 +1932,7 @@ |
4653 | |
4654 | # get_boot_and_root_loopback_devices will also setup two exit handlers |
4655 | # to de-register the loopback devices set up above. |
4656 | - self.assertEqual(6, len(atexit_fixture.mock.funcs)) |
4657 | + self.assertEqual(5, len(atexit_fixture.mock.funcs)) |
4658 | popen_fixture.mock.calls = [] |
4659 | atexit_fixture.mock.run_funcs() |
4660 | # We did not really run losetup above (as it requires root) so here we |
4661 | @@ -1065,7 +1943,6 @@ |
4662 | '%s losetup -d ' % sudo_args, |
4663 | '%s losetup -d ' % sudo_args, |
4664 | '%s losetup -d ' % sudo_args, |
4665 | - '%s losetup -d ' % sudo_args, |
4666 | '%s losetup -d ' % sudo_args], |
4667 | popen_fixture.mock.commands_executed) |
4668 | |
4669 | @@ -1159,6 +2036,9 @@ |
4670 | |
4671 | self.config = c |
4672 | self.config.boot_script = 'boot_script' |
4673 | + self.config.hardwarepack_handler = \ |
4674 | + TestSetMetadata.MockHardwarepackHandler('ahwpack.tar.gz') |
4675 | + self.config.hardwarepack_handler.get_format = lambda: '1.0' |
4676 | self.popen_fixture = self.useFixture(MockCmdRunnerPopenFixture()) |
4677 | self.useFixture(MockSomethingFixture( |
4678 | self.config, 'make_boot_files', self.save_args)) |
4679 | @@ -1241,6 +2121,14 @@ |
4680 | os.makedirs(contents_bin) |
4681 | os.makedirs(contents_etc) |
4682 | |
4683 | + # Must mock rootfs._list_files() because populate_rootfs() uses its |
4684 | + # return value but since we mock cmd_runner.run() _list_files() would |
4685 | + # return an invalid value. |
4686 | + def mock_list_files(directory): |
4687 | + return [contents_bin, contents_etc] |
4688 | + self.useFixture(MockSomethingFixture( |
4689 | + rootfs, '_list_files', mock_list_files)) |
4690 | + |
4691 | populate_rootfs( |
4692 | contents_dir, root_disk, partition='/dev/rootfs', |
4693 | rootfs_type='ext3', rootfs_uuid='uuid', should_create_swap=True, |
4694 | @@ -1282,10 +2170,27 @@ |
4695 | fixture.mock.commands_executed[0]) |
4696 | self.assertEqual('UBOOT_PART=/dev/mmcblk0p1', open(tmpfile).read()) |
4697 | |
4698 | + def test_list_files(self): |
4699 | + tempdir = self.useFixture(CreateTempDirFixture()).tempdir |
4700 | + # We don't want to mock cmd_runner.run() because we're testing the |
4701 | + # command that it runs, but we need to monkey-patch SUDO_ARGS because |
4702 | + # we don't want to use 'sudo' in tests. |
4703 | + orig_sudo_args = cmd_runner.SUDO_ARGS |
4704 | + def restore_sudo_args(): |
4705 | + cmd_runner.SUDO_ARGS = orig_sudo_args |
4706 | + self.addCleanup(restore_sudo_args) |
4707 | + cmd_runner.SUDO_ARGS = [] |
4708 | + file1 = self.createTempFileAsFixture(dir=tempdir) |
4709 | + self.assertEqual([file1], rootfs._list_files(tempdir)) |
4710 | + |
4711 | def test_move_contents(self): |
4712 | tempdir = self.useFixture(CreateTempDirFixture()).tempdir |
4713 | popen_fixture = self.useFixture(MockCmdRunnerPopenFixture()) |
4714 | file1 = self.createTempFileAsFixture(dir=tempdir) |
4715 | + def mock_list_files(directory): |
4716 | + return [file1] |
4717 | + self.useFixture(MockSomethingFixture( |
4718 | + rootfs, '_list_files', mock_list_files)) |
4719 | |
4720 | move_contents(tempdir, '/tmp/') |
4721 | |
4722 | |
4723 | === modified file 'setup.py' |
4724 | --- setup.py 2011-05-26 20:32:40 +0000 |
4725 | +++ setup.py 2011-07-18 14:39:34 +0000 |
4726 | @@ -5,7 +5,7 @@ |
4727 | |
4728 | DistUtilsExtra.auto.setup( |
4729 | name="linaro-image-tools", |
4730 | - version="0.4.8.1", |
4731 | + version="2011.06-1.1", |
4732 | description="Tools to create and write Linaro images", |
4733 | url="https://launchpad.net/linaro-image-tools", |
4734 | license="GPL v3 or later", |