Merge lp:~xnox/usb-creator/nexus7 into lp:usb-creator
- nexus7
- Merge into trunk
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 |
Related bugs: |
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 |
Commit message
Description of the change
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.
> 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.
Preview Diff
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 |
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.