Merge lp:~xnox/usb-creator/nexus7 into lp:usb-creator

Proposed by Dimitri John Ledkov
Status: Merged
Merged at revision: 407
Proposed branch: lp:~xnox/usb-creator/nexus7
Merge into: lp:usb-creator
Diff against target: 944 lines (+376/-103)
15 files modified
bin/usb-creator-gtk (+16/-5)
debian/changelog (+6/-0)
debian/rules (+3/-0)
debian/usb-creator-common.install (+1/-0)
debian/usb-creator-gtk.upstart (+24/-0)
gui/ubuntu-nexus7-USAGE-NOTICE-en.txt (+21/-0)
gui/usbcreator-gtk.ui (+61/-26)
setup.py (+2/-0)
usbcreator/backends/base/backend.py (+17/-2)
usbcreator/backends/fastboot/__init__.py (+1/-0)
usbcreator/backends/fastboot/backend.py (+68/-0)
usbcreator/backends/udisks/backend.py (+0/-11)
usbcreator/frontends/gtk/frontend.py (+111/-57)
usbcreator/install.py (+36/-2)
usbcreator/misc.py (+9/-0)
To merge this branch: bzr merge lp:~xnox/usb-creator/nexus7
Reviewer Review Type Date Requested Status
Evan (community) Approve
James Hunt Pending
The Ubuntu Nexus7 Team Pending
Review via email: mp+144753@code.launchpad.net
To post a comment you must log in.
Revision history for this message
Evan (ev) wrote :

Minor nit: instead of keeping a self.fastboot_mode, you could just check the backend type.

Also, would it not make more sense to put the progress bar into pulse mode for the flash commands, since we don't get progress feedback from them? This would give the user more of an indication that something is happening.

Other than that, this looks good! Thanks Dmitrijs.

review: Approve
Revision history for this message
Dimitri John Ledkov (xnox) wrote :

good point about backend type check. I'll see if I can refactor this.

erase boot, erase userdata, flash boot, reboot : all take about 1 second.
flash userdata: takes about 120 seconds for 8GB size image ( I am expecting linear extrapolation for 16GB sized images).
But it did look "frozen" during flahshing userdata hence the switch to pulse.

It's ok, but not great. Fastboot is not giving progress output, I guess I can add that but that's a low priority patch for some time later.

Revision history for this message
Evan (ev) wrote :

> good point about backend type check. I'll see if I can refactor this.

Cool, thanks.

> erase boot, erase userdata, flash boot, reboot : all take about 1 second.
> flash userdata: takes about 120 seconds for 8GB size image ( I am expecting
> linear extrapolation for 16GB sized images).
> But it did look "frozen" during flahshing userdata hence the switch to pulse.

Noted.

> It's ok, but not great. Fastboot is not giving progress output, I guess I can
> add that but that's a low priority patch for some time later.

Yeah, I wouldn't imagine it to be a huge priority.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'bin/usb-creator-gtk'
2--- bin/usb-creator-gtk 2012-05-04 09:29:27 +0000
3+++ bin/usb-creator-gtk 2013-01-24 17:05:29 +0000
4@@ -1,4 +1,4 @@
5-#!/usr/bin/python
6+#!/usr/bin/python3
7
8 # Copyright (C) 2009 Canonical Ltd.
9
10@@ -27,6 +27,7 @@
11 os.environ['USBCREATOR_LOCAL'] = '1'
12 from usbcreator.frontends.gtk import GtkFrontend
13 from usbcreator.backends.udisks import UDisksBackend
14+from usbcreator.backends.fastboot import FastbootBackend
15 from usbcreator.misc import sane_path, setup_gettext, setup_logging, text_type
16
17 sane_path()
18@@ -56,13 +57,23 @@
19 help=_('allow writing to system-internal devices'))
20 parser.add_option('--show-all', dest='show_all', action='store_true',
21 help=_('Show all devices'))
22+parser.add_option('--fastboot', dest='fastboot', action='store_true',
23+ help=_('Use fastboot backend to flash Android devices.'))
24 (options, args) = parser.parse_args()
25
26 try:
27- backend = UDisksBackend(allow_system_internal=options.allow_system_internal,
28- show_all=options.show_all)
29- frontend = GtkFrontend(backend, options.img, options.persistent,
30- allow_system_internal=options.allow_system_internal)
31+ if options.fastboot:
32+ options.persistent = False
33+ backend = FastbootBackend()
34+ else:
35+ backend = UDisksBackend(
36+ allow_system_internal=options.allow_system_internal,
37+ show_all=options.show_all)
38+ frontend = GtkFrontend(
39+ backend, options.img, options.persistent,
40+ allow_system_internal=options.allow_system_internal,
41+ fastboot_mode=options.fastboot,
42+ )
43 except DBusException as e:
44 # FIXME evand 2009-07-09: Wouldn't service activation pick this up
45 # automatically?
46
47=== modified file 'debian/changelog'
48--- debian/changelog 2013-01-17 18:01:26 +0000
49+++ debian/changelog 2013-01-24 17:05:29 +0000
50@@ -1,3 +1,9 @@
51+usb-creator (0.2.45) UNRELEASED; urgency=low
52+
53+ * Support flashing devices using fastboot (e.g. Nexus7).
54+
55+ -- Dmitrijs Ledkovs <dmitrij.ledkov@ubuntu.com> Wed, 16 Jan 2013 13:54:16 +0000
56+
57 usb-creator (0.2.44) raring; urgency=low
58
59 * Revert sync remount flag. It's too slow.
60
61=== modified file 'debian/rules'
62--- debian/rules 2012-11-09 00:42:18 +0000
63+++ debian/rules 2013-01-24 17:05:29 +0000
64@@ -35,6 +35,9 @@
65 find . -path "$(vendor_dir)/*.svg" -exec cp {} $(dest) \;
66 dh_install
67
68+override_dh_installinit:
69+ dh_installinit --upstart-only
70+
71 override_dh_installmenu:
72 ifneq (,$(wildcard $(vendor_dir)/*.xpm))
73 mkdir -p $(xpm_gtk) $(xpm_kde)
74
75=== modified file 'debian/usb-creator-common.install'
76--- debian/usb-creator-common.install 2010-05-14 16:50:14 +0000
77+++ debian/usb-creator-common.install 2013-01-24 17:05:29 +0000
78@@ -5,6 +5,7 @@
79 usr/lib/python*/*/usbcreator/frontends/base/*
80 usr/lib/python*/*/usbcreator/*.py
81 usr/share/usb-creator/usb-creator-helper
82+usr/share/usb-creator/ubuntu-nexus7-USAGE-NOTICE-en.txt
83 usr/share/polkit-1/actions/*
84 usr/share/dbus-1/system-services/*
85 etc/dbus-1/system.d/*
86
87=== added file 'debian/usb-creator-gtk.upstart'
88--- debian/usb-creator-gtk.upstart 1970-01-01 00:00:00 +0000
89+++ debian/usb-creator-gtk.upstart 2013-01-24 17:05:29 +0000
90@@ -0,0 +1,24 @@
91+# usb-creator-gtk
92+
93+# This really should be enchanced user session job
94+# and not a system one!
95+# Then the hacks to get DISPLAY & user can go away.
96+# Also the udev test are ugly =/
97+
98+author "Dmitrijs Ledkovs <xnox@ubuntu.com>"
99+
100+start on (usb-device-added)
101+pre-start script
102+ [ x"$ID_VENDOR_ID" != x"18d1" ] && { stop; exit 0; }
103+ [ x"$ID_MODEL_ID" != x"4e40" ] && { [ x"$ID_MODEL_ID" != x"d001" ] && { stop; exit 0; } }
104+end script
105+
106+script
107+test -f /usr/share/acpi-support/power-funcs || exit 0
108+. /usr/share/acpi-support/power-funcs
109+
110+getXconsole
111+if [ x"$XAUTHORITY" != x"" ]; then
112+ sudo -u $user DISPLAY="$DISPLAY" usb-creator-gtk --fastboot
113+fi
114+end script
115
116=== added file 'gui/ubuntu-nexus7-USAGE-NOTICE-en.txt'
117--- gui/ubuntu-nexus7-USAGE-NOTICE-en.txt 1970-01-01 00:00:00 +0000
118+++ gui/ubuntu-nexus7-USAGE-NOTICE-en.txt 2013-01-24 17:05:29 +0000
119@@ -0,0 +1,21 @@
120+"Ubuntu for Google Nexus 7" is released for free non-commercial use on
121+the Google Nexus 7 only. It is provided without warranty, even the
122+implied warranty of merchantability, satisfaction or fitness for a
123+particular use. See the licence included with each program for details.
124+ Some licences may grant additional rights; this notice shall not limit
125+your rights under each program's licence. Licences for each program are
126+available in the usr/share/doc directory. Source code for Ubuntu can be
127+downloaded from archive.ubuntu.com. Ubuntu, the Ubuntu logo and
128+Canonical are registered trademarks of Canonical Ltd. All other
129+trademarks are the property of their respective owners.
130+
131+"Ubuntu for Google Nexus 7" is released for limited use due to the
132+inclusion of the following hardware drivers:
133+
134+[Wireless] - [Broadcom Corporation]
135+[Bluetooth] - [Broadcom Corporation]
136+[Graphics] - [NVIDIA Corporation]
137+[Video Codecs] - [NVIDIA Corporation]
138+
139+The original components and licenses can be found at:
140+https://developers.google.com/android/nexus/drivers#grouper
141
142=== modified file 'gui/usbcreator-gtk.ui'
143--- gui/usbcreator-gtk.ui 2012-02-20 20:05:55 +0000
144+++ gui/usbcreator-gtk.ui 2013-01-24 17:05:29 +0000
145@@ -1,13 +1,56 @@
146 <?xml version="1.0" encoding="UTF-8"?>
147 <interface>
148- <requires lib="gtk+" version="2.24"/>
149- <!-- interface-naming-policy toplevel-contextual -->
150+ <!-- interface-requires gtk+ 3.0 -->
151 <object class="GtkAdjustment" id="adjustment1">
152 <property name="upper">100</property>
153 <property name="step_increment">1</property>
154 <property name="page_increment">10</property>
155 <property name="page_size">10</property>
156 </object>
157+ <object class="GtkDialog" id="eula_dialog">
158+ <property name="can_focus">False</property>
159+ <property name="border_width">5</property>
160+ <property name="title" translatable="yes">Legal Notice</property>
161+ <property name="type_hint">dialog</property>
162+ <child internal-child="vbox">
163+ <object class="GtkBox" id="dialog-vbox6">
164+ <property name="can_focus">False</property>
165+ <property name="orientation">vertical</property>
166+ <property name="spacing">2</property>
167+ <child internal-child="action_area">
168+ <object class="GtkButtonBox" id="dialog-action_area6">
169+ <property name="can_focus">False</property>
170+ <property name="layout_style">end</property>
171+ <child>
172+ <placeholder/>
173+ </child>
174+ <child>
175+ <placeholder/>
176+ </child>
177+ </object>
178+ <packing>
179+ <property name="expand">False</property>
180+ <property name="fill">True</property>
181+ <property name="pack_type">end</property>
182+ <property name="position">0</property>
183+ </packing>
184+ </child>
185+ <child>
186+ <object class="GtkTextView" id="eula_text">
187+ <property name="visible">True</property>
188+ <property name="can_focus">False</property>
189+ <property name="vexpand">True</property>
190+ <property name="editable">False</property>
191+ </object>
192+ <packing>
193+ <property name="expand">False</property>
194+ <property name="fill">True</property>
195+ <property name="position">1</property>
196+ </packing>
197+ </child>
198+ </object>
199+ </child>
200+ </object>
201 <object class="GtkDialog" id="failed_dialog">
202 <property name="can_focus">True</property>
203 <property name="title" translatable="yes">Installation Failed</property>
204@@ -18,11 +61,11 @@
205 <property name="type_hint">dialog</property>
206 <property name="gravity">center</property>
207 <child internal-child="vbox">
208- <object class="GtkVBox" id="dialog-vbox5">
209+ <object class="GtkBox" id="dialog-vbox5">
210 <property name="visible">True</property>
211 <property name="can_focus">False</property>
212 <child internal-child="action_area">
213- <object class="GtkHButtonBox" id="dialog-action_area5">
214+ <object class="GtkButtonBox" id="dialog-action_area5">
215 <property name="visible">True</property>
216 <property name="can_focus">False</property>
217 <property name="layout_style">end</property>
218@@ -33,7 +76,6 @@
219 <property name="can_focus">True</property>
220 <property name="can_default">True</property>
221 <property name="receives_default">False</property>
222- <property name="use_action_appearance">False</property>
223 <property name="use_stock">True</property>
224 </object>
225 <packing>
226@@ -123,11 +165,11 @@
227 <property name="type_hint">dialog</property>
228 <property name="gravity">center</property>
229 <child internal-child="vbox">
230- <object class="GtkVBox" id="dialog-vbox3">
231+ <object class="GtkBox" id="dialog-vbox3">
232 <property name="visible">True</property>
233 <property name="can_focus">False</property>
234 <child internal-child="action_area">
235- <object class="GtkHButtonBox" id="dialog-action_area3">
236+ <object class="GtkButtonBox" id="dialog-action_area3">
237 <property name="visible">True</property>
238 <property name="can_focus">False</property>
239 <property name="layout_style">end</property>
240@@ -136,7 +178,6 @@
241 <property name="label" translatable="yes">Test Disk</property>
242 <property name="can_focus">True</property>
243 <property name="receives_default">True</property>
244- <property name="use_action_appearance">False</property>
245 </object>
246 <packing>
247 <property name="expand">False</property>
248@@ -151,7 +192,6 @@
249 <property name="can_focus">True</property>
250 <property name="can_default">True</property>
251 <property name="receives_default">False</property>
252- <property name="use_action_appearance">False</property>
253 <property name="use_stock">True</property>
254 </object>
255 <packing>
256@@ -305,7 +345,6 @@
257 <property name="visible">True</property>
258 <property name="can_focus">True</property>
259 <property name="receives_default">False</property>
260- <property name="use_action_appearance">False</property>
261 <property name="use_stock">True</property>
262 </object>
263 <packing>
264@@ -335,11 +374,11 @@
265 <property name="type_hint">dialog</property>
266 <property name="gravity">center</property>
267 <child internal-child="vbox">
268- <object class="GtkVBox" id="dialog-vbox10">
269+ <object class="GtkBox" id="dialog-vbox10">
270 <property name="visible">True</property>
271 <property name="can_focus">False</property>
272 <child internal-child="action_area">
273- <object class="GtkHButtonBox" id="dialog-action_area10">
274+ <object class="GtkButtonBox" id="dialog-action_area10">
275 <property name="visible">True</property>
276 <property name="can_focus">False</property>
277 <property name="layout_style">end</property>
278@@ -350,7 +389,6 @@
279 <property name="can_focus">True</property>
280 <property name="can_default">True</property>
281 <property name="receives_default">False</property>
282- <property name="use_action_appearance">False</property>
283 <property name="use_stock">True</property>
284 </object>
285 <packing>
286@@ -366,7 +404,6 @@
287 <property name="can_focus">True</property>
288 <property name="can_default">True</property>
289 <property name="receives_default">False</property>
290- <property name="use_action_appearance">False</property>
291 <property name="use_stock">True</property>
292 <signal name="clicked" handler="quit" swapped="no"/>
293 </object>
294@@ -509,18 +546,20 @@
295 </child>
296 <child>
297 <object class="GtkScrolledWindow" id="scrolledwindow1">
298+ <property name="height_request">70</property>
299 <property name="visible">True</property>
300 <property name="can_focus">True</property>
301 <property name="hscrollbar_policy">never</property>
302- <property name="vscrollbar_policy">automatic</property>
303 <property name="shadow_type">in</property>
304- <property name="height_request">70</property>
305 <child>
306 <object class="GtkTreeView" id="source_treeview">
307 <property name="visible">True</property>
308 <property name="can_focus">True</property>
309 <property name="headers_clickable">False</property>
310 <property name="rubber_banding">True</property>
311+ <child internal-child="selection">
312+ <object class="GtkTreeSelection" id="treeview-selection1"/>
313+ </child>
314 </object>
315 </child>
316 </object>
317@@ -551,7 +590,6 @@
318 <property name="visible">True</property>
319 <property name="can_focus">True</property>
320 <property name="receives_default">True</property>
321- <property name="use_action_appearance">False</property>
322 <signal name="clicked" handler="add_file_source_dialog" swapped="no"/>
323 </object>
324 <packing>
325@@ -607,17 +645,19 @@
326 </child>
327 <child>
328 <object class="GtkScrolledWindow" id="scrolledwindow2">
329+ <property name="height_request">70</property>
330 <property name="visible">True</property>
331 <property name="can_focus">True</property>
332 <property name="hscrollbar_policy">never</property>
333- <property name="vscrollbar_policy">automatic</property>
334 <property name="shadow_type">in</property>
335- <property name="height_request">70</property>
336 <child>
337 <object class="GtkTreeView" id="dest_treeview">
338 <property name="visible">True</property>
339 <property name="can_focus">True</property>
340 <property name="headers_clickable">False</property>
341+ <child internal-child="selection">
342+ <object class="GtkTreeSelection" id="treeview-selection2"/>
343+ </child>
344 </object>
345 </child>
346 </object>
347@@ -659,7 +699,6 @@
348 <property name="label">gtk-open</property>
349 <property name="can_focus">True</property>
350 <property name="receives_default">True</property>
351- <property name="use_action_appearance">False</property>
352 <property name="use_stock">True</property>
353 <signal name="clicked" handler="open_dest_folder" swapped="no"/>
354 </object>
355@@ -674,7 +713,6 @@
356 <property name="visible">True</property>
357 <property name="can_focus">True</property>
358 <property name="receives_default">True</property>
359- <property name="use_action_appearance">False</property>
360 <signal name="clicked" handler="format_dest_clicked" swapped="no"/>
361 <child>
362 <object class="GtkHBox" id="hbox3">
363@@ -767,7 +805,7 @@
364 <property name="visible">True</property>
365 <property name="can_focus">True</property>
366 <property name="receives_default">False</property>
367- <property name="use_action_appearance">False</property>
368+ <property name="xalign">0.5</property>
369 <property name="active">True</property>
370 <property name="draw_indicator">True</property>
371 </object>
372@@ -837,7 +875,7 @@
373 <property name="visible">True</property>
374 <property name="can_focus">True</property>
375 <property name="receives_default">False</property>
376- <property name="use_action_appearance">False</property>
377+ <property name="xalign">0.5</property>
378 <property name="active">True</property>
379 <property name="draw_indicator">True</property>
380 <property name="group">persist_enabled</property>
381@@ -877,7 +915,6 @@
382 <property name="can_focus">True</property>
383 <property name="receives_default">True</property>
384 <property name="border_width">4</property>
385- <property name="use_action_appearance">False</property>
386 <property name="use_stock">True</property>
387 </object>
388 <packing>
389@@ -894,7 +931,6 @@
390 <property name="can_focus">True</property>
391 <property name="receives_default">True</property>
392 <property name="border_width">4</property>
393- <property name="use_action_appearance">False</property>
394 <property name="use_stock">True</property>
395 <signal name="clicked" handler="quit" swapped="no"/>
396 </object>
397@@ -914,7 +950,6 @@
398 <property name="has_default">True</property>
399 <property name="receives_default">True</property>
400 <property name="border_width">4</property>
401- <property name="use_action_appearance">False</property>
402 <signal name="clicked" handler="install" swapped="no"/>
403 </object>
404 <packing>
405
406=== modified file 'setup.py'
407--- setup.py 2012-01-21 13:31:38 +0000
408+++ setup.py 2013-01-24 17:05:29 +0000
409@@ -20,11 +20,13 @@
410 'usbcreator.frontends.base',
411 'usbcreator.backends',
412 'usbcreator.backends.base',
413+ 'usbcreator.backends.fastboot',
414 'usbcreator.backends.udisks',
415 ],
416 scripts=['bin/usb-creator-gtk','bin/usb-creator-kde'],
417 data_files=[('share/usb-creator', ['gui/usbcreator-gtk.ui']),
418 ('share/usb-creator', ['bin/usb-creator-helper']),
419+ ('share/usb-creator', ['gui/ubuntu-nexus7-USAGE-NOTICE-en.txt']),
420 ('share/icons/hicolor/scalable/apps', ['desktop/usb-creator-gtk.svg', 'desktop/usb-creator-kde.svg']),
421 ('share/kde4/apps/usb-creator-kde', ['gui/usbcreator-kde.ui']),
422 ('/etc/dbus-1/system.d', ['dbus/com.ubuntu.USBCreator.conf']),
423
424=== modified file 'usbcreator/backends/base/backend.py'
425--- usbcreator/backends/base/backend.py 2012-11-09 00:42:18 +0000
426+++ usbcreator/backends/base/backend.py 2013-01-24 17:05:29 +0000
427@@ -75,6 +75,19 @@
428 def get_current_source(self):
429 return self.current_source
430
431+ # Common helpers
432+
433+ def _device_removed(self, device):
434+ logging.debug('Device has been removed from the system: %s' % device)
435+ if device in self.sources:
436+ if misc.callable(self.source_removed_cb):
437+ self.source_removed_cb(device)
438+ self.sources.pop(device)
439+ elif device in self.targets:
440+ if misc.callable(self.target_removed_cb):
441+ self.target_removed_cb(device)
442+ self.targets.pop(device)
443+
444 # Signals.
445
446 def source_added_cb(self, drive):
447@@ -170,11 +183,13 @@
448 return changed
449
450 def install(self, source, target, persist, device=None,
451- allow_system_internal=False):
452+ allow_system_internal=False,
453+ fastboot_mode=False):
454 logging.debug('Starting install thread.')
455 self.install_thread = usbcreator.install.install(
456 source, target, persist, device=device,
457- allow_system_internal=allow_system_internal)
458+ allow_system_internal=allow_system_internal,
459+ fastboot_mode=fastboot_mode)
460 # Connect signals.
461 self.install_thread.success = self.success_cb
462 self.install_thread.failure = self.failure_cb
463
464=== added directory 'usbcreator/backends/fastboot'
465=== added file 'usbcreator/backends/fastboot/__init__.py'
466--- usbcreator/backends/fastboot/__init__.py 1970-01-01 00:00:00 +0000
467+++ usbcreator/backends/fastboot/__init__.py 2013-01-24 17:05:29 +0000
468@@ -0,0 +1,1 @@
469+from usbcreator.backends.fastboot.backend import FastbootBackend
470
471=== added file 'usbcreator/backends/fastboot/backend.py'
472--- usbcreator/backends/fastboot/backend.py 1970-01-01 00:00:00 +0000
473+++ usbcreator/backends/fastboot/backend.py 2013-01-24 17:05:29 +0000
474@@ -0,0 +1,68 @@
475+import logging
476+
477+from gi.repository import GUdev
478+from gi.repository import GLib
479+
480+from usbcreator.backends.base import Backend
481+from usbcreator import misc
482+
483+KNOWN_IDS = {
484+ 'ID_VENDOR_ID': ('18d1',),
485+ 'ID_MODEL_ID': ('4e40', 'd001',),
486+}
487+
488+class FastbootBackend(Backend):
489+ def __init__(self):
490+ Backend.__init__(self)
491+ logging.debug('FastbootBackend')
492+ self.client = GUdev.Client(subsystems=['usb'])
493+
494+ def on_uevent(self, action, device):
495+ logging.debug('action: %s' % action)
496+ logging.debug('device: %s' % device.get_sysfs_path())
497+
498+ for key,ids in KNOWN_IDS.items():
499+ result = device.get_property(key)
500+ if result not in ids:
501+ logging.debug('Unknown %s: %s' % (key, result))
502+ return
503+
504+ [logging.debug('%s=%s' % (k, device.get_property(k))) for k in device.get_property_keys()]
505+
506+ key = device.get_property('ID_SERIAL_SHORT')
507+
508+ if action == 'add':
509+ self.targets[key] = {
510+ 'vendor' : device.get_property('ID_VENDOR_FROM_DATABASE'),
511+ 'model' : device.get_property('ID_MODEL'),
512+ 'label' : '',
513+ 'device' : device.get_property('ID_SERIAL_SHORT'),
514+ 'status' : misc.CAN_USE,
515+ }
516+ if misc.callable(self.target_added_cb):
517+ self.target_added_cb(key)
518+ elif action == 'remove':
519+ self._device_removed(key)
520+
521+ def detect_devices(self):
522+ def _on_uevent(client, action, device):
523+ self.on_uevent(action, device)
524+
525+ self.client.connect('uevent', _on_uevent)
526+ # Just in case, go over already attached devices
527+ for device in self.client.query_by_subsystem('usb'):
528+ self.on_uevent('add', device)
529+
530+ def update_free(self):
531+ # No progress yet.
532+ return True
533+
534+ def _is_casper_cd(self, filename):
535+ # no cds for us
536+ return None
537+
538+ def unmount(self):
539+ return
540+
541+ def shutdown(self):
542+ return
543
544=== modified file 'usbcreator/backends/udisks/backend.py'
545--- usbcreator/backends/udisks/backend.py 2012-07-06 12:49:06 +0000
546+++ usbcreator/backends/udisks/backend.py 2013-01-24 17:05:29 +0000
547@@ -229,17 +229,6 @@
548 else:
549 logging.debug('not adding device: 0 byte disk.')
550
551- def _device_removed(self, device):
552- logging.debug('Device has been removed from the system: %s' % device)
553- if device in self.sources:
554- if misc.callable(self.source_removed_cb):
555- self.source_removed_cb(device)
556- self.sources.pop(device)
557- elif device in self.targets:
558- if misc.callable(self.target_removed_cb):
559- self.target_removed_cb(device)
560- self.targets.pop(device)
561-
562 # Device manipulation functions.
563 def _is_casper_cd(self, filename):
564 cmd = ['isoinfo', '-J', '-i', filename, '-x', '/.disk/info']
565
566=== modified file 'usbcreator/frontends/gtk/frontend.py'
567--- usbcreator/frontends/gtk/frontend.py 2013-01-10 14:58:41 +0000
568+++ usbcreator/frontends/gtk/frontend.py 2013-01-24 17:05:29 +0000
569@@ -30,8 +30,10 @@
570
571 if 'USBCREATOR_LOCAL' in os.environ:
572 ui_path = os.path.join(os.getcwd(), 'gui/usbcreator-gtk.ui')
573+ eula_path = os.path.join(os.getcwd(), 'gui/ubuntu-nexus7-USAGE-NOTICE-en.txt')
574 else:
575 ui_path = '/usr/share/usb-creator/usbcreator-gtk.ui'
576+ eula_path = '/usr/share/usb-creator/ubuntu-nexus7-USAGE-NOTICE-en.txt'
577
578 GObject.threads_init()
579 Gdk.threads_init()
580@@ -60,10 +62,12 @@
581 DBusGMainLoop(set_as_default=True)
582
583 def __init__(self, backend, img=None, persistent=True,
584- allow_system_internal=False):
585+ allow_system_internal=False,
586+ fastboot_mode=False):
587
588 self.allow_system_internal = allow_system_internal
589-
590+ self.fastboot_mode = fastboot_mode
591+
592 self.all_widgets = set()
593
594 self.builder = Gtk.Builder()
595@@ -98,11 +102,6 @@
596 self.finished_exit.connect('clicked', lambda x: self.finished_dialog.hide())
597 self.failed_exit.connect('clicked', lambda x: self.failed_exit.hide())
598 self.progress_cancel_button.connect('clicked', lambda x: self.warning_dialog.show())
599- # we currently do not have help
600- self.button_help.hide()
601- #self.button_help.connect('clicked', lambda x: Gtk.show_uri(self.button_help.get_screen(),
602- # 'ghelp:usb-creator',
603- # Gtk.get_current_event_time()))
604
605 def format_value(scale, value):
606 return misc.format_mb_size(value)
607@@ -129,6 +128,30 @@
608 # Pulse state.
609 self.pulsing = False
610
611+ # Hide erase in fastboot mode
612+ if self.fastboot_mode:
613+ self.format_dest.hide()
614+ self.intro_label.set_text(_('To run Ubuntu from a portable device, it needs to be set up first.'))
615+ self.label2.set_text(_('Source disc image (.img):'))
616+ self.label3.set_text(_('Target device:'))
617+ self.window.set_title(_('Ubuntu Core Installer'))
618+ self.button_install.set_label(_('Install Ubuntu Core'))
619+ self.button_help.set_label(_('Legal'))
620+ self.button_help.connect('clicked', self.show_eula)
621+ self.eula_dialog.add_buttons(
622+ Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL,
623+ Gtk.STOCK_OK, Gtk.ResponseType.OK
624+ )
625+ with open(eula_path, 'r') as f:
626+ text = ''.join(f.readlines())
627+ self.eula_text.get_buffer().set_text(text)
628+ else:
629+ # we currently do not have help
630+ self.button_help.hide()
631+ #self.button_help.connect('clicked', lambda x: Gtk.show_uri(self.button_help.get_screen(),
632+ # 'ghelp:usb-creator',
633+ # Gtk.get_current_event_time()))
634+
635 self.setup_sources_treeview()
636 self.setup_targets_treeview()
637 self.persist_vbox.set_sensitive(False)
638@@ -345,6 +368,8 @@
639 cell_name.set_property('ellipsize', Pango.EllipsizeMode.END)
640 cell_pixbuf = Gtk.CellRendererPixbuf()
641 column_name = Gtk.TreeViewColumn(_('CD-Drive/Image'))
642+ if self.fastboot_mode:
643+ column_name = Gtk.TreeViewColumn(_('Image'))
644 column_name.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE)
645 column_name.set_resizable(True)
646 column_name.set_expand(True)
647@@ -355,15 +380,16 @@
648 column_name.set_cell_data_func(cell_name, column_data_func, 0)
649 column_name.set_cell_data_func(cell_pixbuf, pixbuf_data_func, None)
650
651- cell_version = Gtk.CellRendererText()
652- cell_version.set_property('ellipsize', Pango.EllipsizeMode.END)
653- column_name = Gtk.TreeViewColumn(_('OS Version'), cell_version)
654- column_name.set_cell_data_func(cell_version, column_data_func, 1)
655- column_name.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE)
656- column_name.set_resizable(True)
657- column_name.set_expand(True)
658- column_name.set_min_width(75)
659- self.source_treeview.append_column(column_name)
660+ if not self.fastboot_mode:
661+ cell_version = Gtk.CellRendererText()
662+ cell_version.set_property('ellipsize', Pango.EllipsizeMode.END)
663+ column_name = Gtk.TreeViewColumn(_('OS Version'), cell_version)
664+ column_name.set_cell_data_func(cell_version, column_data_func, 1)
665+ column_name.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE)
666+ column_name.set_resizable(True)
667+ column_name.set_expand(True)
668+ column_name.set_min_width(75)
669+ self.source_treeview.append_column(column_name)
670
671 cell_size = Gtk.CellRendererText()
672 cell_size.set_property('ellipsize', Pango.EllipsizeMode.END)
673@@ -416,16 +442,20 @@
674 m.row_changed(m.get_path(iterator), iterator)
675 break
676 iterator = m.iter_next(iterator)
677+
678+ target = self.backend.targets[udi]
679+
680 # Update persistence maximum value.
681- self.persist_vbox.set_sensitive(False)
682- self.persist_enabled_vbox.set_sensitive(False)
683- target = self.backend.targets[udi]
684- persist_mb = target['persist'] / 1024 / 1024
685- if persist_mb > misc.MIN_PERSISTENCE:
686- self.persist_vbox.set_sensitive(True)
687- self.persist_enabled_vbox.set_sensitive(True)
688- self.persist_value.set_range(misc.MIN_PERSISTENCE, persist_mb)
689- self.persist_value.set_value(misc.MIN_PERSISTENCE)
690+ if not self.fastboot_mode:
691+ self.persist_vbox.set_sensitive(False)
692+ self.persist_enabled_vbox.set_sensitive(False)
693+ persist_mb = target['persist'] / 1024 / 1024
694+ if persist_mb > misc.MIN_PERSISTENCE:
695+ self.persist_vbox.set_sensitive(True)
696+ self.persist_enabled_vbox.set_sensitive(True)
697+ self.persist_value.set_range(misc.MIN_PERSISTENCE, persist_mb)
698+ self.persist_value.set_value(misc.MIN_PERSISTENCE)
699+
700 # Update install button state.
701 status = target['status']
702 source = self.backend.get_current_source()
703@@ -467,6 +497,9 @@
704 if udi:
705 self.update_target(udi)
706
707+ if self.fastboot_mode:
708+ return
709+
710 dev = self.backend.targets[udi]
711 p = dev['parent']
712 if p and p in self.backend.targets:
713@@ -546,45 +579,51 @@
714 column_name.set_cell_data_func(cell_name, column_data_func, 0)
715 column_name.set_cell_data_func(cell_pixbuf, pixbuf_data_func, None)
716
717- cell_name = Gtk.CellRendererText()
718- cell_name.set_property('ellipsize', Pango.EllipsizeMode.END)
719- column_name = Gtk.TreeViewColumn(_('Label'), cell_name)
720- column_name.set_cell_data_func(cell_name, column_data_func, 1)
721- column_name.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE)
722- column_name.set_resizable(True)
723- column_name.set_expand(True)
724- column_name.set_min_width(75)
725- self.dest_treeview.append_column(column_name)
726-
727- cell_capacity = Gtk.CellRendererText()
728- cell_capacity.set_property('ellipsize', Pango.EllipsizeMode.END)
729- column_name = Gtk.TreeViewColumn(_('Capacity'), cell_capacity)
730- column_name.set_cell_data_func(cell_capacity, column_data_func, 2)
731- column_name.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE)
732- column_name.set_resizable(True)
733- column_name.set_expand(False)
734- column_name.set_min_width(75)
735- self.dest_treeview.append_column(column_name)
736-
737- cell_free = Gtk.CellRendererText()
738- cell_free.set_property('ellipsize', Pango.EllipsizeMode.END)
739- column_name = Gtk.TreeViewColumn(_('Free Space'), cell_free)
740- column_name.set_cell_data_func(cell_free, column_data_func, 3)
741- column_name.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE)
742- column_name.set_resizable(True)
743- column_name.set_expand(False)
744- column_name.set_min_width(75)
745- self.dest_treeview.append_column(column_name)
746+ if not self.fastboot_mode:
747+ cell_name = Gtk.CellRendererText()
748+ cell_name.set_property('ellipsize', Pango.EllipsizeMode.END)
749+ column_name = Gtk.TreeViewColumn(_('Label'), cell_name)
750+ column_name.set_cell_data_func(cell_name, column_data_func, 1)
751+ column_name.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE)
752+ column_name.set_resizable(True)
753+ column_name.set_expand(True)
754+ column_name.set_min_width(75)
755+ self.dest_treeview.append_column(column_name)
756+
757+ cell_capacity = Gtk.CellRendererText()
758+ cell_capacity.set_property('ellipsize', Pango.EllipsizeMode.END)
759+ column_name = Gtk.TreeViewColumn(_('Capacity'), cell_capacity)
760+ column_name.set_cell_data_func(cell_capacity, column_data_func, 2)
761+ column_name.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE)
762+ column_name.set_resizable(True)
763+ column_name.set_expand(False)
764+ column_name.set_min_width(75)
765+ self.dest_treeview.append_column(column_name)
766+
767+ cell_free = Gtk.CellRendererText()
768+ cell_free.set_property('ellipsize', Pango.EllipsizeMode.END)
769+ column_name = Gtk.TreeViewColumn(_('Free Space'), cell_free)
770+ column_name.set_cell_data_func(cell_free, column_data_func, 3)
771+ column_name.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE)
772+ column_name.set_resizable(True)
773+ column_name.set_expand(False)
774+ column_name.set_min_width(75)
775+ self.dest_treeview.append_column(column_name)
776
777 def add_file_source_dialog(self, *args):
778 filename = ''
779 chooser = Gtk.FileChooserDialog(title=None,action=Gtk.FileChooserAction.OPEN,
780 buttons=(Gtk.STOCK_CANCEL,Gtk.ResponseType.CANCEL,Gtk.STOCK_OPEN,Gtk.ResponseType.OK))
781- for p, n in (('*.iso', _('CD Images')), ('*.img', _('Disk Images'))):
782+ def _add_filter(p, n):
783 filter = Gtk.FileFilter()
784 filter.add_pattern(p)
785 filter.set_name(n)
786 chooser.add_filter(filter)
787+
788+ if not self.fastboot_mode:
789+ _add_filter('*.iso', _('CD Images'))
790+ _add_filter('*.img', _('Disk Images'))
791+
792 folder = os.path.expanduser('~')
793 chooser.set_current_folder(folder)
794 response = chooser.run()
795@@ -599,6 +638,9 @@
796 source = self.get_source()
797 target = self.get_target()
798 persist = self.get_persistence()
799+ if self.fastboot_mode and not misc.check_eula():
800+ if self.show_eula() == Gtk.ResponseType.CANCEL:
801+ return
802 # TODO evand 2009-07-31: Make these the default values in the
803 # GtkBuilder file.
804 starting_up = _('Starting up...')
805@@ -610,8 +652,10 @@
806 self.unity.show_progress()
807 self.delete_timeout(self.update_loop)
808 try:
809- self.backend.install(source, target, persist,
810- allow_system_internal=self.allow_system_internal)
811+ self.backend.install(
812+ source, target, persist,
813+ allow_system_internal=self.allow_system_internal,
814+ fastboot_mode=self.fastboot_mode)
815 except:
816 self._fail()
817
818@@ -663,6 +707,12 @@
819 retry_dialog.destroy()
820 return response == Gtk.ResponseType.YES
821
822+ def show_eula(self, unused=None):
823+ response = self.eula_dialog.run()
824+ if response == Gtk.ResponseType.OK:
825+ misc.check_eula(True)
826+ self.eula_dialog.hide()
827+ return response
828
829 def quit(self, *args):
830 self.backend.cancel_install()
831@@ -706,6 +756,10 @@
832 except dbus.DBusException:
833 logging.exception('Error checking for kvm:')
834
835+ if self.fastboot_mode:
836+ self.finished_dialog_label.set_text(
837+ _('Installation is complete. Your device is rebooting into Ubuntu Core.'))
838+ self.kvm_test.hide()
839 self.finished_dialog.run()
840 self.backend.shutdown()
841 Gtk.main_quit()
842
843=== modified file 'usbcreator/install.py'
844--- usbcreator/install.py 2012-05-04 10:35:51 +0000
845+++ usbcreator/install.py 2013-01-24 17:05:29 +0000
846@@ -26,6 +26,7 @@
847 from threading import Thread, Event
848 import logging
849 from hashlib import md5
850+import time
851
852 if sys.platform != 'win32':
853 from usbcreator.misc import MAX_DBUS_TIMEOUT
854@@ -65,13 +66,15 @@
855
856 class install(Thread):
857 def __init__(self, source, target, persist, device=None,
858- allow_system_internal=False):
859+ allow_system_internal=False,
860+ fastboot_mode=False):
861 Thread.__init__(self)
862 self.source = source
863 self.target = target
864 self.persist = persist
865 self.device = device
866 self.allow_system_internal = allow_system_internal
867+ self.fastboot_mode = fastboot_mode
868 self._stopevent = Event()
869 self.progress_thread = None
870 logging.debug('install thread source: %s' % source)
871@@ -137,7 +140,13 @@
872 if ext not in ['.iso', '.img']:
873 self._failure(_('The extension "%s" is not supported.') %
874 ext)
875- if ext == '.iso':
876+ if self.fastboot_mode:
877+ self.bootimg = os.path.splitext(self.source)[0] + '.bootimg'
878+ if not os.path.isfile(self.bootimg):
879+ self._failure(_('Missing matching "%s" for source image %s.') %
880+ (self.bootimg, self.source))
881+ self.fastboot_install()
882+ elif ext == '.iso':
883 if sys.platform == 'win32':
884 self.cdimage_install()
885 else:
886@@ -394,6 +403,31 @@
887 except dbus.DBusException:
888 self._failure(failure_msg)
889
890+ def _fastboot_command(self, cmd):
891+ fastboot_cmd = ['fastboot', '-s', self.target]
892+ fastboot_cmd.extend(cmd)
893+ popen(fastboot_cmd)
894+
895+ def fastboot_install(self):
896+ self.progress(0, 3*60+9, True)
897+ self.progress_message(_('Erasing boot partition...'))
898+ self._fastboot_command(['erase', 'boot'])
899+ self.progress(5, 3*60+7, True)
900+ self.progress_message(_('Erasing user partition...'))
901+ self._fastboot_command(['erase', 'userdata'])
902+ self.progress(10, 3*60+5, True)
903+ self.progress_message(_('Flashing boot partition...'))
904+ self._fastboot_command(['flash', 'boot', self.bootimg])
905+ self.progress(15, 3*60+3, True)
906+ self.progress_message(_('Flashing user partition...'))
907+ self.progress_pulse()
908+ self._fastboot_command(['flash', 'userdata', self.source])
909+ self.progress_pulse_stop()
910+ self.progress(95, 1, True)
911+ self.progress_message(_('Rebooting device...'))
912+ self._fastboot_command(['reboot'])
913+ self.progress(100, 0, True)
914+
915 def cdimage_install(self):
916 # Build.
917
918
919=== modified file 'usbcreator/misc.py'
920--- usbcreator/misc.py 2012-11-09 01:23:47 +0000
921+++ usbcreator/misc.py 2013-01-24 17:05:29 +0000
922@@ -35,6 +35,8 @@
923 MAX_LOG_SIZE = 1024 * 1024 * 1
924 MAX_LOG_BACKUP = 0
925
926+EULA_STAMP = '.ubuntu-nexus7-installer.notice-accepted'
927+
928 if sys.platform != 'win32':
929 # TODO xnox 20121109 should not hard-code timeouts, instead should
930 # do async dbus calls with a qt or glib main loop running.
931@@ -78,6 +80,13 @@
932 log.addHandler(handler)
933 log.setLevel(logging.DEBUG)
934
935+def check_eula(save=False):
936+ eula_stamp = os.path.expanduser('~/' + EULA_STAMP)
937+ if save:
938+ with open(eula_stamp, 'w') as f:
939+ pass
940+ return os.path.isfile(eula_stamp)
941+
942 def format_size(size):
943 """Format a partition size."""
944 # Taken from ubiquity's ubiquity/misc.py

Subscribers

People subscribed via source and target branches