2
# vim:expandtab:autoindent:tabstop=4:shiftwidth=4:filetype=python:tw=0
4
this is the documentation...
7
# import arranged alphabetically
12
from gettext import gettext as _
20
import gtk, gtk.glade, pango
24
import firmwaretools.trace_decorator as trace_decorator
25
import firmwaretools.guihelpers as guihelpers
26
import firmwaretools.repository as repository
27
import firmwaretools.clifuncs
28
import firmwaretools.package
30
PROGRAM_NAME="Firmware Inventory and Update GUI"
33
class CommandAlreadyExecuted(Exception): pass
34
class CommandAlreadyUndone(Exception): pass
35
class Command(object):
36
def __init__(self, object, method, args, kargs):
47
raise CommandAlreadyExecuted()
50
self.memento = self.object.getMemento()
51
self.method(*self.args, **self.kargs)
55
raise CommandAlreadyUndone()
58
self.object.setMemento(self.memento)
60
# use only for pin/unpin, it is more efficent as it doesnt save full memento
61
class UpdateSetPinCommand(Command):
64
raise CommandAlreadyExecuted()
67
self.memento = self.object.getMemento(deviceHint = self.args[0])
68
self.method(*self.args, **self.kargs)
70
class InventoryFirmware:
71
GLADE_FILE = '/glade/inventory_firmware_gui.glade'
72
def __init__(self, ini):
73
self.wTree = gtk.glade.XML(TOPDIR + self.GLADE_FILE)
74
self.wTree.signal_autoconnect(self)
75
self.main_window = self.wTree.get_widget("MainWindow")
76
self.wTree.get_widget("about_dialog").destroy()
79
self.toolbarAllowDowngrade = self.wTree.get_widget("toolbar_allow_downgrade")
80
self.toolbarAllowReflash = self.wTree.get_widget("toolbar_allow_reflash")
81
self.menuAllowDowngrade = self.wTree.get_widget("menu_allow_downgrade")
82
self.menuAllowReflash = self.wTree.get_widget("menu_allow_reflash")
83
self.recursiveCallback=0
86
self.numDowngradeSelected = 0
87
self.numReflashSelected = 0
89
# set up command stack, used for undo/redo
94
self._setupInventoryTreeView()
95
self._setupBootstrapTreeView()
96
self._setupUpdateStatusTreeView()
98
# get handle to status bar
99
self.statusBar = self.wTree.get_widget("main_window_status_bar")
100
ctx = self.statusBar.get_context_id("main")
101
self.statusBar.push(ctx, "Ready")
103
# disable input in main window until we are finished initializing...
104
self.main_window.set_sensitive(0)
107
self.main_window.show()
109
# set status == collecting inventory
110
ctx = self.statusBar.get_context_id("inventory")
111
self.statusBar.push(ctx, _("Performing system inventory..."))
112
guihelpers.gtkYield() # make sure current GUI is fully displayed
114
# special function to make sure GUI updates smoothly while we
115
# generate the update set
116
def myYield(*args, **kargs):
117
# eats all its args...
118
guihelpers.gtkYield()
121
r = firmwaretools.repository.Repository( ini.get("main", "storage_topdir") )
122
firmwaretools.package.RepositoryPackage.mainIni = ini
124
# the following two lines are equivalent, but runLongProcess() does the
125
# action in a background thread so the GUI will update while it works.
126
#self.updateSet = repository.generateUpdateSet(r, firmwaretools.clifuncs.runInventory(ini), cb=(myYield, None))
127
self.updateSet = guihelpers.runLongProcessGtk(repository.generateUpdateSet, args=(r, firmwaretools.clifuncs.runInventory(ini)), kargs={'cb':(myYield, None)})
129
self._populateInventoryTree()
130
self._populateBootstrapTree(ini)
131
self.inventoryTreeView.expand_all()
134
# set status == ready
135
self.statusBar.pop(ctx)
136
self.main_window.set_sensitive(1)
138
def _setupBootstrapTreeView(self):
139
# create model for bootstrap treeview
140
self.bootstrapTreeView = self.wTree.get_widget("bootstrap_treeview")
141
self.bootstrapTreeModel= gtk.TreeStore(gobject.TYPE_STRING, gobject.TYPE_STRING, gobject.TYPE_STRING)
142
self.bootstrapTreeView.set_model(self.bootstrapTreeModel)
143
self.BOOTSTRAP_COLUMN_BOOTSTRAP_NAME = 0
144
self.BOOTSTRAP_COLUMN_DEVICE_NAME = 1
145
self.BOOTSTRAP_COLUMN_FW_VER = 2
147
# add column headers to the inventory treeview
148
self.bootstrapTreeView.set_headers_visible(True)
150
# add column: Display name for devices, version select for updates
151
renderer=gtk.CellRendererText()
152
column=gtk.TreeViewColumn(_("Bootstrap Name"),renderer, text=self.BOOTSTRAP_COLUMN_BOOTSTRAP_NAME)
153
column.set_resizable(True)
154
self.bootstrapTreeView.append_column(column)
156
# add column: Display name for devices, version select for updates
157
renderer=gtk.CellRendererText()
158
column=gtk.TreeViewColumn(_("Device Name"),renderer, text=self.BOOTSTRAP_COLUMN_DEVICE_NAME)
159
column.set_resizable(True)
160
self.bootstrapTreeView.append_column(column)
162
# add column: Display name for devices, version select for updates
163
renderer=gtk.CellRendererText()
164
column=gtk.TreeViewColumn(_("Firmware Version"),renderer, text=self.BOOTSTRAP_COLUMN_FW_VER)
165
column.set_resizable(True)
166
self.bootstrapTreeView.append_column(column)
168
# let us select multiple releases
169
self.bootstrapTreeView.get_selection().set_mode(gtk.SELECTION_MULTIPLE)
171
def _setupUpdateStatusTreeView(self):
172
# create model for update status treeview
173
self.updateStatusTreeView = self.wTree.get_widget("status_treeview")
174
self.updateStatusTreeModel= gtk.TreeStore( object, object, int )
175
self.updateStatusTreeView.set_model(self.updateStatusTreeModel)
176
self.STATUS_COLUMN_DEVICE = 0
177
self.STATUS_COLUMN_PACKAGE = 1
178
self.STATUS_COLUMN_SERIAL = 2
180
# add column headers to the inventory treeview
181
self.updateStatusTreeView.set_headers_visible(True)
183
# status, component, status description, log?
185
# add column: Display name for devices, version select for updates
186
renderer=gtk.CellRendererText()
187
column=gtk.TreeViewColumn(_("Status"),renderer)
188
column.set_resizable(True)
189
column.set_cell_data_func(renderer, self.cell_data_func_us_status)
190
self.updateStatusTreeView.append_column(column)
192
# add column: Display name for devices, version select for updates
193
renderer=gtk.CellRendererText()
194
column=gtk.TreeViewColumn(_("Component"),renderer)
195
column.set_resizable(True)
196
column.set_cell_data_func(renderer, self.cell_data_func_us_component)
197
self.updateStatusTreeView.append_column(column)
199
# add column: Display name for devices, version select for updates
200
renderer=gtk.CellRendererText()
201
column=gtk.TreeViewColumn(_("Current Version"),renderer)
202
column.set_resizable(True)
203
column.set_cell_data_func(renderer, self.cell_data_func_us_cur_version)
204
self.updateStatusTreeView.append_column(column)
206
# add column: Display name for devices, version select for updates
207
renderer=gtk.CellRendererText()
208
column=gtk.TreeViewColumn(_("Update Version"),renderer)
209
column.set_resizable(True)
210
column.set_cell_data_func(renderer, self.cell_data_func_us_update_version)
211
self.updateStatusTreeView.append_column(column)
213
# add column: Display name for devices, version select for updates
214
renderer=gtk.CellRendererText()
215
column=gtk.TreeViewColumn(_("Status Description"),renderer)
216
column.set_resizable(True)
217
column.set_cell_data_func(renderer, self.cell_data_func_us_status_description)
218
self.updateStatusTreeView.append_column(column)
220
# let us select multiple releases
221
self.updateStatusTreeView.get_selection().set_mode(gtk.SELECTION_MULTIPLE)
223
def _setupInventoryTreeView(self):
224
# create model for inventory treeview
225
self.inventoryTreeView = self.wTree.get_widget("inventory_treeview")
226
self.inventoryTreeModel= gtk.TreeStore(
227
object, # device or package
228
gobject.TYPE_BOOLEAN, # for device == enable update for device (checkbox),
229
# for package == update to this package
230
gobject.TYPE_INT, # flags
231
gobject.TYPE_INT, # update serial
233
self.inventoryTreeView.set_model(self.inventoryTreeModel)
234
self.INVENTORY_COLUMN_DEVICE = 0
235
self.INVENTORY_COLUMN_DEVICE_ENABLE_UPDATE = 1
236
self.INVENTORY_COLUMN_FLAGS = 2
237
self.INVENTORY_COLUMN_SERIAL = 3
238
self.FLAG_REFLASH = 1
239
self.FLAG_DOWNGRADE = 2
241
# add column headers to the inventory treeview
242
self.inventoryTreeView.set_headers_visible(True)
244
# select, status, criticality, package name, component, type (bios/firmware/driver), current ver, repo ver
246
# add column: Flash yes/no checkbox column
247
renderer=gtk.CellRendererToggle()
248
renderer.set_property("radio", False)
249
renderer.set_property('activatable', True)
250
renderer.connect('toggled', self.toggle_device_cb, self.inventoryTreeModel)
251
column=gtk.TreeViewColumn(_("Flash"),renderer)
252
column.add_attribute(renderer, "active", self.INVENTORY_COLUMN_DEVICE_ENABLE_UPDATE)
253
column.set_cell_data_func(renderer, self.cell_data_func_iv_toggle)
254
self.inventoryTreeView.append_column(column)
256
# add column: Display name for devices, version select for updates
257
renderer=gtk.CellRendererToggle()
258
renderer.set_property("radio", True)
259
renderer.set_property('activatable', True)
260
renderer.connect('toggled', self.toggle_update_cb, self.inventoryTreeModel)
261
column=gtk.TreeViewColumn(_("Device Name"),renderer)
262
column.add_attribute(renderer, "active", self.INVENTORY_COLUMN_DEVICE_ENABLE_UPDATE)
263
column.set_resizable(True)
264
renderer=gtk.CellRendererText()
265
column.pack_start(renderer)
266
column.set_cell_data_func(renderer, self.cell_data_func_iv_display_name)
267
self.inventoryTreeView.append_column(column)
268
self.inventoryTreeView.set_expander_column(column)
270
# add column: Firmware version
271
renderer = gtk.CellRendererText()
272
column=gtk.TreeViewColumn(_("Current Version"),renderer)
273
column.set_cell_data_func(renderer, self.cell_data_func_iv_version)
274
column.set_resizable(True)
275
self.inventoryTreeView.append_column(column)
277
# let us select multiple releases
278
self.inventoryTreeView.get_selection().set_mode(gtk.SELECTION_MULTIPLE)
281
# this is a helper function to initially populate the tree model.
282
# should only ever be called once.
283
def _populateInventoryTree(self):
284
self.inventoryTreeModel.clear()
285
for device in self.updateSet.iterDevices():
286
guihelpers.gtkYield()
289
if self.updateSet.getUpdatePackageForDevice(device) is not None:
291
iter = self.inventoryTreeModel.append(None, [device, toggle, flags, 0])
292
for availPkg in self.updateSet.iterAvailableUpdates(device):
293
guihelpers.gtkYield()
295
if device.compareVersion(availPkg) == 0:
296
flags = flags | self.FLAG_REFLASH
297
if device.compareVersion(availPkg) > 0:
298
flags = flags | self.FLAG_DOWNGRADE
300
if self.updateSet.getUpdatePackageForDevice(device) == availPkg:
302
self.inventoryTreeModel.append(iter, [availPkg, toggle, flags, 0])
304
# this is a helper function to initially populate the tree model.
305
# should only ever be called once.
306
def _populateBootstrapTree(self, ini):
307
self.bootstrapTreeModel.clear()
308
for dev in firmwaretools.clifuncs.runBootstrapInventory(ini):
309
guihelpers.gtkYield()
310
self.bootstrapTreeModel.append(None, [dev.name, dev.displayname, dev.version])
312
def _populateUpdateStatusTree(self):
313
self.updateStatusTreeModel.clear()
314
for device, package in self.updateSet.generateInstallationOrder(returnDeviceToo=1):
315
self.updateStatusTreeModel.append(None, [device, package, 0])
317
# refresh the display when something happens behind the scenes. Should be rarely used.
319
self._refreshUpdateEnableToggles()
320
self._refreshAllowToggles()
321
self._refreshEnableUndoRedo()
323
# only refreshes the toggles and radio buttons to reflect current package set.
324
def _refreshUpdateEnableToggles(self):
325
for i in range(self.inventoryTreeModel.iter_n_children(None)):
326
device_path = self.inventoryTreeModel.get_path(self.inventoryTreeModel.iter_nth_child(None, i))
327
device = self.inventoryTreeModel[device_path][self.INVENTORY_COLUMN_DEVICE]
328
if self.updateSet.getUpdatePackageForDevice(device) is not None:
329
self.inventoryTreeModel[device_path][self.INVENTORY_COLUMN_DEVICE_ENABLE_UPDATE]=True
331
self.inventoryTreeModel[device_path][self.INVENTORY_COLUMN_DEVICE_ENABLE_UPDATE]=False
332
self._fixupChildren(self.inventoryTreeModel, self.inventoryTreeModel.get_iter(device_path))
334
# refreshes allow reflash/downgrade toggles
335
def _refreshAllowToggles(self):
336
self.recursiveCallback=1
337
self.menuAllowDowngrade.set_property("active", self.updateSet.allowDowngrade)
338
self.menuAllowReflash.set_property("active", self.updateSet.allowReflash)
339
self.toolbarAllowDowngrade.set_active(self.updateSet.allowDowngrade)
340
self.toolbarAllowReflash.set_active(self.updateSet.allowReflash)
342
if self.numDowngradeSelected:
343
self.menuAllowDowngrade.set_sensitive(0)
344
self.toolbarAllowDowngrade.set_sensitive(0)
346
self.menuAllowDowngrade.set_sensitive(1)
347
self.toolbarAllowDowngrade.set_sensitive(1)
349
if self.numReflashSelected:
350
self.menuAllowReflash.set_sensitive(0)
351
self.toolbarAllowReflash.set_sensitive(0)
353
self.menuAllowReflash.set_sensitive(1)
354
self.toolbarAllowReflash.set_sensitive(1)
356
self.recursiveCallback=0
358
# enables/disables the undo/redo/reset buttons so only valid actions are enabled
359
def _refreshEnableUndoRedo(self):
361
self.wTree.get_widget("reset_button").set_sensitive(1)
362
self.wTree.get_widget("reset_menu").set_sensitive(1)
363
self.wTree.get_widget("undo_button").set_sensitive(1)
364
self.wTree.get_widget("undo_menu").set_sensitive(1)
366
self.wTree.get_widget("reset_button").set_sensitive(0)
367
self.wTree.get_widget("reset_menu").set_sensitive(0)
368
self.wTree.get_widget("undo_button").set_sensitive(0)
369
self.wTree.get_widget("undo_menu").set_sensitive(0)
372
self.wTree.get_widget("redo_button").set_sensitive(1)
373
self.wTree.get_widget("redo_menu").set_sensitive(1)
375
self.wTree.get_widget("redo_button").set_sensitive(0)
376
self.wTree.get_widget("redo_menu").set_sensitive(0)
378
def cell_data_func_iv_display_name(self, column, cell, model, iter):
379
pyobj = model.get_value(iter,self.INVENTORY_COLUMN_DEVICE)
380
renderers = column.get_cell_renderers()
382
if isinstance(pyobj, firmwaretools.package.Device):
383
renderers[0].set_property("visible", False)
384
renderers[1].set_property("text", text)
386
flags = model.get_value(iter,self.INVENTORY_COLUMN_FLAGS)
387
renderers[0].set_property("visible", True)
388
parentIter = model.iter_parent(iter)
389
device = model.get_value(parentIter,self.INVENTORY_COLUMN_DEVICE)
390
text = str(pyobj.version)
392
renderers[1].set_property("text", _("Available Version: %s") % text)
393
renderers[0].set_property('activatable', True)
395
if not model.get_value(parentIter, self.INVENTORY_COLUMN_DEVICE_ENABLE_UPDATE):
396
renderers[0].set_property('activatable', False)
398
if self.updateSet.getSuggestedUpdatePackageForDevice(device) == pyobj:
400
renderers[1].set_property("text", _("Available Version: %s (suggested)") % text)
402
if flags & self.FLAG_REFLASH:
404
renderers[1].set_property("text", _("Available Version: %s (reflash)") % text)
405
if not self.updateSet.allowReflash:
406
renderers[0].set_property('activatable', False)
407
renderers[1].set_property("text", _("Available Version: %s (reflash disabled per policy)") % text)
408
if not pyobj.getCapability("can_reflash"):
409
renderers[0].set_property('activatable', False)
410
renderers[1].set_property("text", _("Available Version: %s (reflash disabled due to package limitations)") % text)
412
if flags & self.FLAG_DOWNGRADE:
414
renderers[1].set_property("text", _("Available Version: %s (downgrade)") % text)
415
if not self.updateSet.allowDowngrade:
416
renderers[0].set_property('activatable', False)
417
renderers[1].set_property("text", _("Available Version: %s (downgrade disabled per policy)") % text)
418
if not pyobj.getCapability("can_downgrade"):
419
renderers[0].set_property('activatable', False)
420
renderers[1].set_property("text", _("Available Version: %s (downgrade disabled due to package limitations)") % text)
423
def cell_data_func_iv_version(self, column, cell, model, iter):
424
pyobj = model.get_value(iter,self.INVENTORY_COLUMN_DEVICE)
425
if isinstance(pyobj, firmwaretools.package.Device):
426
cell.set_property("visible", True)
427
cell.set_property("text", pyobj.version)
429
cell.set_property("visible", False)
431
def cell_data_func_iv_toggle(self, column, cell, model, iter):
432
pyobj = model.get_value(iter,self.INVENTORY_COLUMN_DEVICE)
433
if isinstance(pyobj, firmwaretools.package.Device):
434
cell.set_property("visible", True)
436
cell.set_property("visible", False)
438
def toggle_device_cb(self, renderer, path, model, *args, **kargs):
439
model[path][self.INVENTORY_COLUMN_DEVICE_ENABLE_UPDATE] = not model[path][self.INVENTORY_COLUMN_DEVICE_ENABLE_UPDATE]
440
device = model[path][self.INVENTORY_COLUMN_DEVICE]
441
if model[path][self.INVENTORY_COLUMN_DEVICE_ENABLE_UPDATE]:
442
# unpin it and calculated pkg takes over
443
self._executeCommand(UpdateSetPinCommand(self.updateSet, self.updateSet.unPinDevice, (device,), {}))
445
# pin it to None to disable update for this device
446
self._executeCommand(UpdateSetPinCommand(self.updateSet, self.updateSet.pinUpdatePackage, (device, None), {}))
448
self._fixupChildren(model, model.get_iter(path))
449
self._refreshAllowToggles()
451
def toggle_update_cb(self, renderer, path, model, *args, **kargs):
452
# dont re-activate if it is already the active update
453
if not model[path][self.INVENTORY_COLUMN_DEVICE_ENABLE_UPDATE]:
454
iter = model.get_iter(path)
455
parentIter = model.iter_parent(iter)
456
device = model.get_value(parentIter, self.INVENTORY_COLUMN_DEVICE)
457
update = model[path][self.INVENTORY_COLUMN_DEVICE]
459
self._executeCommand(UpdateSetPinCommand(self.updateSet, self.updateSet.pinUpdatePackage, (device, update), {}))
460
self._fixupChildren(model, parentIter)
461
self._refreshAllowToggles()
463
# this method sets the enable toggle on packages appropriately
464
# it also interlocks the allow reflash/downgrade toggles
465
def _fixupChildren(self, model, iter):
466
for i in range(model.iter_n_children(iter)):
467
child_path = model.get_path(model.iter_nth_child(iter, i))
468
curValue = model[child_path][self.INVENTORY_COLUMN_DEVICE_ENABLE_UPDATE]
469
if model[child_path][self.INVENTORY_COLUMN_DEVICE] == self.updateSet.getUpdatePackageForDevice(model.get_value(iter,self.INVENTORY_COLUMN_DEVICE)):
470
if curValue == False and model[child_path][self.INVENTORY_COLUMN_FLAGS] & self.FLAG_DOWNGRADE:
471
self.numDowngradeSelected = self.numDowngradeSelected + 1
472
if curValue == False and model[child_path][self.INVENTORY_COLUMN_FLAGS] & self.FLAG_REFLASH:
473
self.numReflashSelected = self.numReflashSelected + 1
474
model[child_path][self.INVENTORY_COLUMN_DEVICE_ENABLE_UPDATE] = True
476
if curValue == True and model[child_path][self.INVENTORY_COLUMN_FLAGS] & self.FLAG_DOWNGRADE:
477
self.numDowngradeSelected = self.numDowngradeSelected - 1
478
if curValue == True and model[child_path][self.INVENTORY_COLUMN_FLAGS] & self.FLAG_REFLASH:
479
self.numReflashSelected = self.numReflashSelected - 1
480
model[child_path][self.INVENTORY_COLUMN_DEVICE_ENABLE_UPDATE] = False
482
# force update serial so rows get redisplayed
483
self.inventoryTreeModel[child_path][self.INVENTORY_COLUMN_SERIAL]= (
484
self.inventoryTreeModel[child_path][self.INVENTORY_COLUMN_SERIAL] + 1)
486
def on_allow_downgrade_toggled(self, widget, *args, **kargs):
487
# guard against executeCommand being called while we are in a refresh
488
if not self.recursiveCallback:
489
if self.numDowngradeSelected > 0:
492
active = widget.get_active()
493
self._executeCommand(Command(self.updateSet, self.updateSet.setAllowDowngrade, (active,), {}))
494
self._refreshAllowToggles()
495
# force update serial so rows get redisplayed
496
for i in range(self.inventoryTreeModel.iter_n_children(None)):
497
device_path = self.inventoryTreeModel.get_path(self.inventoryTreeModel.iter_nth_child(None, i))
498
self._fixupChildren(self.inventoryTreeModel, self.inventoryTreeModel.get_iter(device_path))
500
def on_allow_reflash_toggled(self, widget, *args, **kargs):
501
# guard against executeCommand being called while we are in a refresh
502
if not self.recursiveCallback:
503
if self.numReflashSelected > 0:
506
active = widget.get_active()
507
self._executeCommand(Command(self.updateSet, self.updateSet.setAllowReflash, (active,), {}))
508
self._refreshAllowToggles()
509
# force update serial so rows get redisplayed
510
for i in range(self.inventoryTreeModel.iter_n_children(None)):
511
device_path = self.inventoryTreeModel.get_path(self.inventoryTreeModel.iter_nth_child(None, i))
512
self._fixupChildren(self.inventoryTreeModel, self.inventoryTreeModel.get_iter(device_path))
514
def on_help_about(self, *args):
515
wTree = gtk.glade.XML(TOPDIR + self.GLADE_FILE, "about_dialog")
516
wTree.get_widget("about_dialog").set_property('name',PROGRAM_NAME)
517
wTree.get_widget("about_dialog").set_property('version',version)
518
wTree.get_widget("about_dialog").run() # modal until 'close'
519
wTree.get_widget("about_dialog").destroy()
521
def _executeCommand(self, command):
523
self.undoStack.append(command)
525
self._refreshEnableUndoRedo()
526
if len(self.undoStack) > 20:
527
self.undoStack = self.undoStack[-20:]
529
def on_undo_activate(self, *args, **kargs):
531
command = self.undoStack.pop()
533
self.redoStack.append(command)
537
def on_redo_activate(self, *args, **kargs):
539
command = self.redoStack.pop()
541
self.undoStack.append(command)
545
def on_reset_activate(self, *args, **kargs):
546
self.updateSet.reset()
549
self.updateSet.setAllowReflash(0)
550
self.updateSet.setAllowDowngrade(0)
553
def on_system_inventory_menu_activate(self, *args, **kargs):
554
notebook = self.wTree.get_widget("notebook")
555
widget = self.wTree.get_widget("inventory_vbox")
556
page = notebook.page_num(widget)
557
notebook.set_current_page(page)
559
def on_bootstrap_inventory_menu_activate(self, *args, **kargs):
560
notebook = self.wTree.get_widget("notebook")
561
widget = self.wTree.get_widget("bootstrap_scrolledwindow")
562
page = notebook.page_num(widget)
563
notebook.set_current_page(page)
565
def on_file_quit(self, *args):
566
self.on_quit_app( allowCancel = 1 )
568
def on_quit_app(self, *args, **kargs):
569
# check kargs['allowCancel']
572
def on_update_now_activate(self, *args, **kargs):
573
detailsStr = cStringIO.StringIO()
574
detailsStr.write( _("Going to update the following devices:\n\n") )
575
for device in self.updateSet.iterDevices():
576
pkg = self.updateSet.getUpdatePackageForDevice(device)
578
detailsStr.write("\t%s\n" % str(device))
579
detailsStr.write(_("\t\tFrom Version: %s\n") % device.version)
580
detailsStr.write(_("\t\tTo Version : %s\n") % pkg.version)
581
detailsStr.write("\n")
583
dialog = gtk.MessageDialog(parent=None,
585
type=gtk.MESSAGE_WARNING,
586
buttons=gtk.BUTTONS_NONE)
587
dialog.set_title(_("Update Firmware"))
588
dialog.set_markup(_( "<big>Your system will now be updated.</big>\n\nYou will not be able to come back to this page after you continue.\nPress the 'Show Details' button to see which devices are set to be updated."))
590
showButton = dialog.add_button(_("Show Details..."), 1)
591
dialog.add_button(_("Continue to update page..."), 2)
592
dialog.add_button(_("Cancel Update"), 3)
595
textview = gtk.TextView()
596
textview.set_editable(False)
597
textview.modify_font(pango.FontDescription("Monospace"))
598
sw = gtk.ScrolledWindow()
599
sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
602
frame.set_shadow_type(gtk.SHADOW_IN)
604
frame.set_border_width(6)
605
dialog.vbox.add(frame)
606
textbuffer = textview.get_buffer()
607
textbuffer.set_text(detailsStr.getvalue())
608
textview.set_size_request(gtk.gdk.screen_width()/2, gtk.gdk.screen_height()/3)
610
dialog.details = frame
611
dialog.set_position(gtk.WIN_POS_CENTER)
612
dialog.set_gravity(gtk.gdk.GRAVITY_CENTER)
620
dialog.details.show_all()
621
showButton.set_label(_("Hide Details"))
623
dialog.details.hide_all()
624
showButton.set_label(_("Show Details..."))
627
self._gotoUpdatePage()
633
def _gotoUpdatePage(self):
634
self._populateUpdateStatusTree()
635
notebook = self.wTree.get_widget("notebook")
636
widget = self.wTree.get_widget("update_status_scrolledwindow")
637
page = notebook.page_num(widget)
638
notebook.set_current_page(page)
640
view_menu = self.wTree.get_widget("view_menu")
641
view_menu.set_sensitive(0)
642
self.menuAllowDowngrade.set_sensitive(0)
643
self.menuAllowReflash.set_sensitive(0)
644
self.wTree.get_widget("update_now_menu").set_sensitive(0)
647
self._refreshEnableUndoRedo()
648
ctx = self.statusBar.get_context_id("update page")
649
self.statusBar.push(ctx, "Click 'Update Now' to begin update...")
651
def cell_data_func_us_status(self, column, cell, model, iter):
652
pkg = model.get_value(iter,self.STATUS_COLUMN_PACKAGE)
653
if pkg.getCapability('accurate_update_percentage'):
654
cell.set_property("text", "%s%%" % (pkg.getProgress()*100))
656
if pkg.status == "installing":
657
cell.set_property("text", firmwaretools.pycompat.spinner())
659
cell.set_property("text", "")
661
def cell_data_func_us_status_description(self, column, cell, model, iter):
662
pkg = model.get_value(iter,self.STATUS_COLUMN_PACKAGE)
663
cell.set_property("text", pkg.getStatusStr())
665
def cell_data_func_us_component(self, column, cell, model, iter):
666
device = model.get_value(iter,self.STATUS_COLUMN_DEVICE)
667
cell.set_property("text", str(device))
669
def cell_data_func_us_cur_version(self, column, cell, model, iter):
670
device = model.get_value(iter,self.STATUS_COLUMN_DEVICE)
671
cell.set_property("text", device.version)
673
def cell_data_func_us_update_version(self, column, cell, model, iter):
674
pkg = model.get_value(iter,self.STATUS_COLUMN_PACKAGE)
675
cell.set_property("text", pkg.version)
677
def on_really_update_now_button_clicked(self, *args, **kargs):
678
# disable update button...
679
ctx = self.statusBar.get_context_id("update page")
680
self.statusBar.pop(ctx)
681
self.statusBar.push(ctx, "Performing updates now...")
682
self.wTree.get_widget("really_update_now_button").set_sensitive(0)
685
for pkg in self.updateSet.generateInstallationOrder():
686
stop = self.wTree.get_widget("stop_on_errors").get_active()
688
ret = guihelpers.runLongProcessGtk(pkg.install, waitLoopFunction=self._refreshUpdateStatus)
690
except (firmwaretools.package.NoInstaller,), e:
691
print "package %s - %s does not have an installer available." % (pkg.name, pkg.version)
692
print "skipping this package for now."
693
except (Exception,), e:
695
print "Installation failed for package: %s - %s" % (pkg.name, pkg.version)
696
print "The error message from the low-level command was:"
700
print "stop on errors selected. error detected, so I'm stopping."
703
self._refreshUpdateStatus()
704
self.statusBar.pop(ctx)
706
self.statusBar.push(ctx, "All updates successfully completed.")
708
self.statusBar.push(ctx, "Some updates failed.")
710
def _refreshUpdateStatus(self):
711
# update serial # to force GUI to refresh
712
model = self.updateStatusTreeModel
713
for i in range(model.iter_n_children(None)):
714
path = model.get_path(model.iter_nth_child(None, i))
715
model[path][self.STATUS_COLUMN_SERIAL] = model[path][self.STATUS_COLUMN_SERIAL] + 1
722
TOPDIR = "/usr/share/firmware-tools/"
723
ini = ConfigParser.ConfigParser()
729
opts, args = getopt.getopt(sys.argv[1:], "c:fho:t:vw", ["help", "verbose", "warnings", "topdir=", "config=", "overrides=", "fake-mode"])
730
for option, argument in opts:
731
if option in ("-h", "--help"):
734
if option in ("-c", "--config"):
735
firmwaretools.clifuncs.getConfig(ini, [argument,])
737
if option in ("-o", "--override"):
738
overrides.append(argument)
739
if option in ("-v", "--verbose"):
740
verbose = verbose + 1
741
trace_decorator.debug["__main__"] = verbose
742
if option in ("-w", "--warnings"):
743
warnings = warnings + 1
744
if option in ("-t", "--topdir"):
746
if option in ("-f", "--fake-mode"):
747
os.environ['DEBUG_REPOSITORY'] = "1"
748
os.environ['DEBUG_INVENTORY'] = "1"
749
os.environ['DEBUG_BOOTSTRAP'] = "1"
750
import firmwaretools.mockrepository
751
import firmwaretools.mockpackage
753
# load standard configuration
755
firmwaretools.clifuncs.getConfig(ini, firmwaretools.clifuncs.configLocations)
757
for over in overrides:
758
section, key, value = over.split(",", 2)
759
if not ini.has_section(section):
760
ini.add_section(section)
761
ini.set(section, key, value)
763
#gnome.init(PROGRAM_NAME, version)
764
test = InventoryFirmware(ini)
767
except (getopt.GetoptError):
772
traceback.print_exc()
777
def _info(type, value, tb):
778
# exception dialog code from: Gustavo J A M Carneiro <gjc at inescporto.pt>
779
# http://www.daa.com.au/pipermail/pygtk/attachments/20030828/2d304204/gtkexcepthook.py
780
# license: "The license is whatever you want."
781
# http://www.daa.com.au/pipermail/pygtk/2003-August/005777.html
782
# Bugfixes by Michael Brown <michael_e_brown at dell.com>
783
dialog = gtk.MessageDialog(parent=None,
785
type=gtk.MESSAGE_WARNING,
786
buttons=gtk.BUTTONS_NONE,
788
"<big><b>A programming error has been detected during the execution of this program.</b></big>"
789
"\n\nIt probably isn't fatal, but should be reported to the developers nonetheless."))
790
dialog.set_title(_("Bug Detected"))
791
dialog.set_property("has-separator", False)
792
dialog.vbox.get_children()[0].get_children()[1].set_property("use-markup", True)
794
dialog.add_button(_("Show Details"), 1)
795
dialog.add_button(gtk.STOCK_CLOSE, gtk.RESPONSE_CLOSE)
798
textview = gtk.TextView()
799
textview.set_editable(False)
800
textview.modify_font(pango.FontDescription("Monospace"))
801
sw = gtk.ScrolledWindow()
802
sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
805
frame.set_shadow_type(gtk.SHADOW_IN)
807
frame.set_border_width(6)
808
dialog.vbox.add(frame)
809
textbuffer = textview.get_buffer()
810
trace = cStringIO.StringIO()
811
traceback.print_exception(type, value, tb, None, trace)
812
textbuffer.set_text(trace.getvalue())
813
textview.set_size_request(gtk.gdk.screen_width()/2, gtk.gdk.screen_height()/3)
815
dialog.details = frame
816
dialog.set_position(gtk.WIN_POS_CENTER)
817
dialog.set_gravity(gtk.gdk.GRAVITY_CENTER)
822
dialog.details.show_all()
823
dialog.action_area.get_children()[1].set_sensitive(0)
829
if __name__ == "__main__":
830
sys.excepthook = _info