Merge lp:~salgado/linaro-image-tools/bug-789093 into lp:~salgado/linaro-image-tools/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
Reviewer Review Type Date Requested Status
Linaro Maintainers Pending
Review via email: mp+68248@code.launchpad.net

Description of the change

Make sure rootfs.move_contents() doesn't skip files that are not
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",

Subscribers

People subscribed via source and target branches

to all changes: