1 #!/usr/bin/python2.4
   2 #
   3 # CDDL HEADER START
   4 #
   5 # The contents of this file are subject to the terms of the
   6 # Common Development and Distribution License (the "License").
   7 # You may not use this file except in compliance with the License.
   8 #
   9 # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  10 # or http://www.opensolaris.org/os/licensing.
  11 # See the License for the specific language governing permissions
  12 # and limitations under the License.
  13 #
  14 # When distributing Covered Code, include this CDDL HEADER in each
  15 # file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  16 # If applicable, add the following below this CDDL HEADER, with the
  17 # fields enclosed by brackets "[]" replaced with your own identifying
  18 # information: Portions Copyright [yyyy] [name of copyright owner]
  19 #
  20 # CDDL HEADER END
  21 #
  22 # Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
  23 # Use is subject to license terms.
  24 #
  25 
  26 CLIENT_API_VERSION = 0
  27 PKG_CLIENT_NAME = "packagemanager"
  28 
  29 import errno
  30 import gettext # XXX Temporary workaround
  31 import itertools
  32 import os
  33 import sys
  34 import time
  35 import datetime
  36 from threading import Thread
  37 from urllib2 import URLError
  38 try:
  39         import gobject
  40         import gtk
  41         import gtk.glade
  42         import pygtk
  43         pygtk.require("2.0")
  44 except ImportError:
  45         sys.exit(1)
  46 import pkg.client.imageplan as imageplan
  47 import pkg.client.progress as progress
  48 import pkg.misc
  49 from pkg import VERSION
  50 import pkg.client.api as api
  51 import pkg.client.api_errors as api_errors
  52 from pkg.misc import TransferTimedOutException
  53 from pkg.misc import CLIENT_DEFAULT_MEM_USE_KB
  54 import pkg.gui.enumerations as enumerations
  55 
  56 class InstallUpdate(progress.ProgressTracker):
  57         def __init__(self, install_list, parent, image_dir, \
  58             ips_update = False, action = -1):
  59                 if action == -1:
  60                         return
  61                 # XXX Workaround as BE is using msg(_("message")) 
  62                 # which bypasses the self._ mechanism the GUI is using
  63                 gettext.install("pkg","/usr/lib/locale")
  64                 progress.ProgressTracker.__init__(self)
  65                 self.update_list = []
  66                 self.parent = parent
  67                 self.ips_update = ips_update
  68                 self.ip = None
  69                 self.progress_stop_timer_thread = False
  70                 self.progress_stop_timer_running = False
  71                 self.prev_pkg = None
  72                 self.action = action
  73                 try:
  74                         self.api_o =  api.ImageInterface(image_dir, \
  75                                     CLIENT_API_VERSION, \
  76                                     self, None, PKG_CLIENT_NAME)
  77                 except (api_errors.VersionException,\
  78                     api_errors.NoImageException):
  79                         raise
  80                 w_tree_createplan = gtk.glade.XML(parent.gladefile, "createplandialog")
  81                 w_tree_installupdate = gtk.glade.XML(parent.gladefile, "installupdate")
  82                 w_tree_downloadingfiles = \
  83                     gtk.glade.XML(parent.gladefile, "downloadingfiles")
  84                 w_tree_installingdialog = \
  85                     gtk.glade.XML(parent.gladefile, "installingdialog") 
  86                 w_tree_networkdown = gtk.glade.XML(parent.gladefile, "networkdown")
  87                 self.w_createplan_dialog = \
  88                     w_tree_createplan.get_widget("createplandialog")     
  89                 self.w_next_button = \
  90                     w_tree_installupdate.get_widget("next")
  91                 self.w_cancel_button = \
  92                     w_tree_installupdate.get_widget("cancel")
  93                 self.w_createplan_progressbar = \
  94                     w_tree_createplan.get_widget("createplanprogress") 
  95                 self.w_createplan_textview = \
  96                     w_tree_createplan.get_widget("createplantextview")
  97                 self.w_createplan_label = \
  98                     w_tree_createplan.get_widget("packagedependencies")
  99                 self.w_createplancancel_button = \
 100                     w_tree_createplan.get_widget("cancelcreateplan")
 101                 self.w_canceldownload_button = \
 102                     w_tree_downloadingfiles.get_widget("canceldownload")
 103                 self.w_download_label = \
 104                     w_tree_downloadingfiles.get_widget("packagedependencies2")
 105                 self.w_installupdate_dialog = w_tree_installupdate.get_widget("installupdate")
 106                 self.w_summary_label = w_tree_installupdate.get_widget("packagenamelabel3")
 107                 self.w_review_treeview = w_tree_installupdate.get_widget("treeview1")
 108                 self.w_information_label = w_tree_installupdate.get_widget("label5")
 109                 self.w_downloadingfiles_dialog = \
 110                     w_tree_downloadingfiles.get_widget("downloadingfiles")
 111                 self.w_download_textview = \
 112                     w_tree_downloadingfiles.get_widget("downloadtextview")
 113                 self.w_download_progressbar = \
 114                     w_tree_downloadingfiles.get_widget("downloadprogress")
 115                 self.w_installing_dialog = \
 116                     w_tree_installingdialog.get_widget("installingdialog")
 117                 self.w_installingdialog_label = \
 118                     w_tree_installingdialog.get_widget("packagedependencies3")                    
 119                 self.w_installingdialog_expander = \
 120                     w_tree_installingdialog.get_widget("expander4")                     
 121                 self.w_installing_textview = \
 122                     w_tree_installingdialog.get_widget("installingtextview")
 123                 self.w_installing_progressbar = \
 124                     w_tree_installingdialog.get_widget("installingprogress")
 125                 self.w_networkdown_dialog = w_tree_networkdown.get_widget("networkdown")
 126                 self.w_createplan_progressbar.set_pulse_step(0.1)
 127                 installed_updated_column = gtk.TreeViewColumn('Installed/Updated')
 128                 self.w_review_treeview.append_column(installed_updated_column)
 129                 cell = gtk.CellRendererText()
 130                 installed_updated_column.pack_start(cell, True)
 131                 installed_updated_column.add_attribute(cell, 'text', 0)
 132                 self.w_review_treeview.expand_all()
 133 
 134                 if self.action == enumerations.REMOVE:
 135                         self.w_installupdate_dialog.set_title(self.parent._(\
 136                             "Remove Confirmation"))
 137                         self.w_information_label.set_text(\
 138                             self.parent._("This action affects other packages.\n" + \
 139                             "Review the packages to be removed.\n" + \
 140                             "Click Next to continue."))
 141                         self.w_installing_dialog.set_title(\
 142                             self.parent._("Removing Packages"))
 143                         self.w_createplan_dialog.set_title(\
 144                             self.parent._("Remove Check"))
 145                         self.w_installingdialog_label.set_text(\
 146                             self.parent._("Removing Packages..."))
 147 
 148                 try:
 149                         dic_createplan = \
 150                             {
 151                                 "on_cancelcreateplan_clicked": \
 152                                     self.__on_cancelcreateplan_clicked,
 153                             }
 154                         dic_installupdate = \
 155                             {
 156                                 "on_cancel_button_clicked": \
 157                                     self.__on_cancel_button_clicked,
 158                                 "on_next_button_clicked":self.__on_next_button_clicked,
 159                             }
 160                         dic_downloadingfiles = \
 161                             {
 162                                 "on_canceldownload_clicked": \
 163                                     self.__on_cancel_download_clicked,
 164                             }
 165                         dic_networkdown = \
 166                             {
 167                                 "on_networkdown_close_clicked": \
 168                                     self.__on_networkdown_close_clicked,
 169                             }
 170                         w_tree_createplan.signal_autoconnect(dic_createplan)
 171                         w_tree_installupdate.signal_autoconnect(dic_installupdate)
 172                         w_tree_downloadingfiles.signal_autoconnect(dic_downloadingfiles)
 173                         w_tree_networkdown.signal_autoconnect(dic_networkdown)
 174                 except AttributeError, error:
 175                         print self.parent._('GUI will not respond to any event! %s. \
 176                             Check installupdate.py signals') \
 177                             % error
 178                 # XXX Hidden until progress will give information about fmri                        
 179                 self.w_installingdialog_expander.hide()
 180                 pulse_t = Thread(target = self.__progressdialog_progress_pulse)
 181                 thread = Thread(target = self.__plan_the_install_updateimage_ex, \
 182                     args = (install_list, ))
 183                 pulse_t.start()
 184                 thread.start()
 185                 self.w_createplan_label.set_text(\
 186                     self.parent._("Checking package dependencies..."))
 187                 self.w_createplancancel_button.set_sensitive(True)           
 188                 self.w_createplan_dialog.show()
 189 
 190         def __on_cancelcreateplan_clicked(self, widget):
 191                 '''Handler for signal send by cancel button, which user might press during
 192                 evaluation stage - while the dialog is creating plan'''
 193                 if self.api_o.can_be_canceled():
 194                         Thread(target = self.api_o.cancel, args = ()).start()
 195                         self.w_createplan_label.set_text(\
 196                             self.parent._("Canceling..."))
 197                         self.w_createplancancel_button.set_sensitive(False)
 198 
 199         def __on_cancel_button_clicked(self, widget):
 200                 '''Handler for signal send by cancel button, which is available for the 
 201                 user after evaluation stage on the dialog showing what will be installed
 202                 or updated'''
 203                 self.api_o.reset()
 204                 self.w_installupdate_dialog.destroy()
 205 
 206         def __on_next_button_clicked(self, widget):
 207                 '''Handler for signal send by next button, which is available for the 
 208                 user after evaluation stage on the dialog showing what will be installed
 209                 or updated'''
 210                 self.w_installupdate_dialog.hide()
 211                 download_thread = Thread(target = self.__prepare_stage_ex, \
 212                     args = (self.api_o, ))
 213                 download_thread.start()
 214 
 215         def __on_cancel_download_clicked(self, widget):
 216                 '''Handler for signal send by cancel button, which user might press during
 217                 download stage.'''
 218                 if self.api_o.can_be_canceled():
 219                         Thread(target = self.api_o.cancel, args = ()).start()
 220                         self.w_download_label.set_text(\
 221                             self.parent._("Canceling..."))
 222                         self.w_canceldownload_button.set_sensitive(False)
 223 
 224         def __on_networkdown_close_clicked(self, widget):
 225                 '''Handler for signal send by close button on the dialog showing that
 226                 there was some problem with the network connection.'''
 227                 self.w_networkdown_dialog.destroy()
 228 
 229         def __update_createplan_progress(self, action):
 230                 buf = self.w_createplan_textview.get_buffer()
 231                 textiter = buf.get_end_iter()
 232                 buf.insert(textiter, action)
 233                 
 234         def __progressdialog_progress_pulse(self):
 235                 while not self.progress_stop_timer_thread:
 236                         gobject.idle_add(self.w_createplan_progressbar.pulse)
 237                         time.sleep(0.1)
 238 
 239         def __update_download_progress(self, cur_bytes, total_bytes):
 240                 prog = float(cur_bytes)/total_bytes
 241                 self.w_download_progressbar.set_fraction(prog)
 242                 size_a_str = ""
 243                 size_b_str = ""
 244                 if cur_bytes > 0:
 245                         size_a_str = pkg.misc.bytes_to_str(cur_bytes)
 246                 if total_bytes > 0:
 247                         size_b_str = pkg.misc.bytes_to_str(total_bytes)
 248                 c = "Downloaded: " + size_a_str + " / " + size_b_str
 249                 self.w_download_progressbar.set_text(c)
 250 
 251         def __update_install_progress(self, current, total):
 252                 prog = float(current)/total
 253                 self.w_installing_progressbar.set_fraction(prog)
 254 
 255         def __update_install_pulse(self):
 256                 while not self.progress_stop_timer_thread:
 257                         self.progress_stop_timer_running = True
 258                         gobject.idle_add(self.w_installing_progressbar.pulse)
 259                         time.sleep(0.1)
 260                 self.progress_stop_timer_running = False
 261 
 262         def __plan_the_install_updateimage_ex(self, list_of_packages):
 263                 try:
 264                         self.__plan_the_install_updateimage(list_of_packages)
 265                 except:
 266                         self.progress_stop_timer_thread = True
 267                         gobject.idle_add(self.w_createplan_dialog.hide)
 268                         msg = self.parent._("An unknown error occured while preparing the" + \
 269                             "\nlist of packages\n\nPlease let the developers know about this problem by filing" + \
 270                             "\na bug at http://defect.opensolaris.org")
 271                         msg += "\n\nException value: " + "\n" + str(sys.exc_value)
 272                         gobject.idle_add(self.parent.error_occured, msg)
 273                         sys.exc_clear()
 274                         return
 275 
 276         def __plan_the_install_updateimage(self, list_of_packages):
 277                 '''Function which plans the image'''
 278                 filters = []
 279                 verbose = False
 280                 noexecute = False
 281                 gobject.idle_add(self.__update_createplan_progress, \
 282                     self.parent._("Evaluation started.\n" + \
 283                         "Gathering packages information, please wait...\n"))
 284                 stuff_to_do = False
 285                 if self.action == enumerations.INSTALL_UPDATE:
 286                         try:
 287                                 stuff_to_do = self.api_o.plan_install(list_of_packages, \
 288                                     filters = [])
 289                         except (api_errors.InvalidCertException, \
 290                             api_errors.PlanCreationException, \
 291                             api_errors.InventoryException):
 292                                 raise
 293                         except api_errors.CanceledException:
 294                                 self.progress_stop_timer_thread = True
 295                                 gobject.idle_add(self.w_createplan_dialog.hide)
 296                                 return
 297                         except api_errors.CatalogRefreshException, er:
 298                                 # network problem
 299                                 self.progress_stop_timer_thread = True
 300                                 gobject.idle_add(self.w_createplan_dialog.hide)
 301                                 msg = self.parent._("Please check the network connection.\nIs the " + \
 302                                 "repository accessible?")
 303                                 gobject.idle_add(self.parent.error_occured, msg)
 304                                 return
 305 
 306                 elif self.action == enumerations.REMOVE:
 307                         try:
 308                                 stuff_to_do = self.api_o.plan_uninstall(list_of_packages, False, False)
 309                         except api_errors.PlanCreationException:
 310                                 raise
 311                         except api_errors.NonLeafPackageException, nlpe:
 312                                 gobject.idle_add(self.__afterplan_nonleaf_dialog, nlpe)
 313 
 314                 elif self.action == enumerations.IMAGE_UPDATE:  
 315                         try:
 316                                 # we are passing force, since we already checked if the
 317                                 # SUNWipkg and SUNWipkg-gui are up to date.
 318                                 stuff_to_do, opensolaris_image, cre = \
 319                                     self.api_o.plan_update_all(sys.argv[0], \
 320                                     refresh_catalogs = False, \
 321                                     noexecute = False, force = True)
 322                                 if cre and not cre.display_catalog_failures(cre):
 323                                         raise RuntimeError("Unexpected failure with catalog "
 324                                             "refresh during image-update while determining what"
 325                                             " to update.")
 326                         except (api_errors.CatalogRefreshException, \
 327                             api_errors.IpkgOutOfDateException, \
 328                             api_errors.PlanCreationException):
 329                                 pass
 330                         except api_errors.NetworkUnavailableException:
 331                                 self.progress_stop_timer_thread = True
 332                                 gobject.idle_add(self.w_createplan_dialog.hide)
 333                                 msg = self.parent._("Please check the network connection.\nIs the " + \
 334                                 "repository accessible?")
 335                                 gobject.idle_add(self.parent.error_occured, msg)
 336                                 return
 337                 if stuff_to_do:
 338                         gobject.idle_add(self.__afterplan_confirmation_dialog, self.api_o)
 339 
 340         def __prepare_stage_ex(self, api):
 341                 try:
 342                         self.__prepare_stage(api)
 343                 except:
 344                         self.progress_stop_timer_thread = True
 345                         gobject.idle_add(self.w_downloadingfiles_dialog.hide)
 346                         msg = self.parent._("An unknown error occured while downloading the files" + \
 347                             "\n\nPlease let the developers know about this problem by filing" + \
 348                             "\na bug at http://defect.opensolaris.org")
 349                         msg += "\n\nException value: " + "\n" + str(sys.exc_value)
 350                         gobject.idle_add(self.parent.error_occured, msg)
 351                         sys.exc_clear()
 352 
 353         def __prepare_stage(self, api):
 354                 gobject.idle_add(self.w_downloadingfiles_dialog.show)
 355                 text = self.parent._("Preparing to download packages, please wait...")
 356                 gobject.idle_add(self.__add_info_to_downloadtext, text)
 357                 try:
 358                         api.prepare()
 359                 except (api_errors.ProblematicPermissionsIndexException, \
 360                     api_errors.PlanMissingException):
 361                         raise
 362                 except api_errors.CanceledException:
 363                         self.progress_stop_timer_thread = True
 364                         gobject.idle_add(self.w_downloadingfiles_dialog.hide)
 365                         return
 366                 except TransferTimedOutException:
 367                         gobject.idle_add(self.w_downloadingfiles_dialog.hide)
 368                         gobject.idle_add(self.w_networkdown_dialog.show)
 369                         return
 370                 except URLError, e:
 371                         gobject.idle_add(self.w_downloadingfiles_dialog.hide)
 372                         gobject.idle_add(self.w_networkdown_dialog.show)
 373                         return
 374                 self.__execute_stage_ex(api)
 375                 
 376         def __execute_stage_ex(self, api):
 377                 try:
 378                         self.__execute_stage(api)
 379                 except:
 380                         self.progress_stop_timer_thread = True
 381                         gobject.idle_add(self.w_installing_dialog.hide)
 382                         msg = self.parent._("An unknown error occured while installing" + \
 383                             "\nupdating or removing packages" + \
 384                             "\n\nPlease let the developers know about this problem by filing" + \
 385                             "\na bug at http://defect.opensolaris.org")
 386                         msg += "\n\nException value: " + "\n" + str(sys.exc_value)
 387                         gobject.idle_add(self.parent.error_occured, msg)
 388                         sys.exc_clear()
 389                         return
 390 
 391         def __execute_stage(self, api):
 392                 text = self.parent._("Installing Packages...")
 393                 gobject.idle_add(self.w_downloadingfiles_dialog.hide)
 394                 gobject.idle_add(self.w_installingdialog_label.set_text, text)
 395                 gobject.idle_add(self.w_installing_dialog.show)
 396                 try:
 397                         api.execute_plan()
 398                 except (api_errors.CorruptedIndexException, \
 399                     api_errors.ProblematicPermissionsIndexException, \
 400                     api_errors.ImageplanStateException, \
 401                     api_errors.ImageUpdateOnLiveImageException, \
 402                     api_errors.PlanMissingException):
 403                         raise
 404                 gobject.idle_add(self.__operations_done)
 405 
 406         def __operations_done(self):
 407                 if self.parent != None:
 408                         if not self.ips_update and not self.action == \
 409                             enumerations.IMAGE_UPDATE:
 410                                 self.__update_package_list()
 411                 self.w_installing_dialog.hide()
 412 
 413                 if self.ips_update:
 414                         self.parent.shutdown_after_ips_update()
 415                 elif self.action == enumerations.IMAGE_UPDATE:
 416                         self.parent.shutdown_after_image_update()
 417 
 418         def __update_package_list(self):
 419                 self.parent.update_package_list(self.update_list)
 420 
 421         def __add_info_to_downloadtext(self, text):
 422                 '''Function which adds another line text in the "more details" download 
 423                 dialog'''
 424                 buf = self.w_download_textview.get_buffer()
 425                 textiter = buf.get_end_iter()
 426                 if text:
 427                         buf.insert(textiter, text + "\n")
 428 
 429         def __add_info_to_installtext(self, text):
 430                 '''Function which adds another line text in the "more details" install 
 431                 dialog'''
 432                 buf = self.w_installing_textview.get_buffer()
 433                 textiter = buf.get_end_iter()
 434                 buf.insert(textiter, text)
 435 
 436         def cat_output_start(self): 
 437                 return
 438 
 439         def cat_output_done(self): 
 440                 return
 441 
 442         def eval_output_start(self):
 443                 '''Called by progress tracker when the evaluation of the packages just 
 444                 started.'''
 445                 return
 446 
 447         def eval_output_progress(self):
 448                 '''Called by progress tracker each time some package was evaluated. The
 449                 call is being done by calling progress tracker evaluate_progress() 
 450                 function'''
 451                 cur_eval_fmri = self.eval_cur_fmri
 452                 gobject.idle_add(self.__update_createplan_progress, \
 453                     self.parent._("Evaluating: %s\n") % cur_eval_fmri)
 454 
 455         def eval_output_done(self):
 456                 ninst = self.eval_goal_install_npkgs
 457                 nupdt = self.eval_goal_update_npkgs
 458                 nremv = self.eval_goal_remove_npkgs
 459                 nbytes = self.dl_goal_nbytes
 460                 gobject.idle_add(self.__eval_output_done, \
 461                     ninst, nupdt, nremv, nbytes)
 462 
 463         def __eval_output_done(self, ninst, nupdt, nremv, nbytes):
 464                 label_text = ""
 465                 if nupdt > 0 and nupdt != 1:
 466                         label_text += \
 467                             self.parent._("%d packages will be updated\n") % nupdt
 468                 elif nupdt == 1:
 469                         label_text += \
 470                             self.parent._("%d package will be updated\n") % nupdt
 471                 if ninst > 0 and ninst != 1:
 472                         label_text += \
 473                             self.parent._("%d packages will be installed\n\n") % ninst
 474                 elif ninst == 1:
 475                         label_text += \
 476                             self.parent._("%d package will be installed\n\n") % ninst
 477                 if nremv > 0 and nremv != 1:
 478                         label_text += \
 479                             self.parent._("%d packages will be removed\n\n") % nremv
 480                 elif nremv == 1:
 481                         label_text += \
 482                             self.parent._("%d package will be removed\n\n") % nremv
 483                 if not nbytes:
 484                         nbytes = 0
 485                 if nbytes > 0:
 486                         size_str = pkg.misc.bytes_to_str(nbytes)
 487                         label_text += self.parent._("%s will be downloaded") % size_str
 488                 self.w_summary_label.set_text(label_text)
 489 
 490         def __afterplan_nonleaf_dialog(self, non_leaf_exception):
 491                 self.w_installupdate_dialog.set_title(self.parent._(\
 492                     "Remove Confirmation"))
 493                 self.w_information_label.set_text(\
 494                     self.parent._("This action couldn't be finished.\n" + \
 495                     "Some of the selected packages depends on other.\n" + \
 496                     "Please review the dependencies."))
 497                 self.w_next_button.hide()
 498                 self.w_cancel_button.set_label(self.parent._("Close"))
 499                 pkg_blocker = non_leaf_exception[0]
 500                 treestore = gtk.TreeStore(str)
 501                 pkg_iter = treestore.append(None, [pkg_blocker])
 502                 for pkg in non_leaf_exception[1]:
 503                         treestore.append(pkg_iter, [pkg])
 504                 self.w_review_treeview.set_model(treestore)
 505                 self.w_review_treeview.expand_all()
 506                 label_text = self.parent._("None of the packages will be removed")
 507                 self.w_summary_label.set_text(label_text)
 508                 self.progress_stop_timer_thread = True
 509                 self.w_createplan_dialog.hide()
 510                 self.w_installupdate_dialog.show()
 511 
 512 
 513         def __afterplan_confirmation_dialog(self, api):
 514                 updated_installed = \
 515                     [
 516                         ["Packages To Be Installed:"],
 517                         ["Packages To Be Updated:"],
 518                         ["Packages To Be Removed:"]
 519                     ]
 520                 treestore = gtk.TreeStore(str)
 521                 install_iter = None 
 522                 updated_iter = None
 523                 remove_iter = None
 524                 plan = api.describe().get_changes()
 525                 for pkg_plan in plan:
 526                         origin_fmri = pkg_plan[0]
 527                         destination_fmri = pkg_plan[1]
 528                         if origin_fmri and destination_fmri:
 529                                 if not updated_iter:
 530                                         updated_iter = treestore.append(None, \
 531                                             updated_installed[1])
 532                                 pkg = self.__get_pkgstr_from_pkginfo(destination_fmri)
 533                                 treestore.append(updated_iter, [pkg])
 534                         elif not origin_fmri and destination_fmri:
 535                                 if not install_iter:
 536                                         install_iter = treestore.append(None, \
 537                                             updated_installed[0])
 538                                 pkg = self.__get_pkgstr_from_pkginfo(destination_fmri)
 539                                 treestore.append(install_iter, [pkg])
 540                         elif origin_fmri and not destination_fmri:
 541                                 if not remove_iter:
 542                                         remove_iter = treestore.append(None, \
 543                                             updated_installed[2])
 544                                 pkg = self.__get_pkgstr_from_pkginfo(origin_fmri)
 545                                 treestore.append(remove_iter, [pkg])
 546 
 547                 self.w_review_treeview.set_model(treestore)
 548                 self.w_review_treeview.expand_all()
 549                 self.progress_stop_timer_thread = True
 550                 self.w_createplan_dialog.hide()
 551                 self.w_installupdate_dialog.show()
 552 
 553         def __get_pkgstr_from_pkginfo(self, pkginfo):
 554                 dt_str = self.get_datetime(pkginfo.packaging_date)
 555                 s_ver = pkginfo.version
 556                 s_bran = pkginfo.branch
 557                 pkg_name = pkginfo.pkg_stem
 558                 if not pkg_name in self.update_list:
 559                         self.update_list.append(pkg_name)
 560                 l_ver = 0
 561                 version_pref = ""
 562                 while l_ver < len(s_ver) -1:
 563                         version_pref += "%d%s" % (s_ver[l_ver],".")
 564                         l_ver += 1
 565                 version_pref += "%d%s" % (s_ver[l_ver],"-")
 566                 l_ver = 0
 567                 version_suf = ""
 568                 while l_ver < len(s_bran) -1:
 569                         version_suf += "%d%s" % (s_bran[l_ver],".")
 570                         l_ver += 1
 571                 version_suf += "%d" % s_bran[l_ver]
 572                 pkg_version = version_pref + version_suf + dt_str
 573                 return pkg_name + "@" + pkg_version  
 574 
 575         def ver_output(self): 
 576                 return
 577 
 578         def ver_output_error(self, actname, errors): 
 579                 return
 580 
 581         def dl_output(self):
 582                 gobject.idle_add(self.__update_download_progress, \
 583                     self.dl_cur_nbytes, self.dl_goal_nbytes)
 584                 if self.prev_pkg != self.dl_cur_pkg:
 585                         self.prev_pkg = self.dl_cur_pkg
 586                         text = self.parent._("Downloading: ") + self.dl_cur_pkg
 587                         gobject.idle_add(self.__add_info_to_downloadtext, text)
 588                 return
 589 
 590         def dl_output_done(self):
 591                 return
 592 
 593         def act_output(self):
 594                 gobject.idle_add(self.__update_install_progress, \
 595                     self.act_cur_nactions, self.act_goal_nactions)
 596                 return
 597 
 598         def act_output_done(self):
 599                 return
 600 
 601         def ind_output(self):
 602                 self.progress_stop_timer_thread = False
 603                 gobject.idle_add(self.__indexing_progress)
 604                 return
 605 
 606         def __indexing_progress(self):
 607                 if not self.progress_stop_timer_running:
 608                         self.w_installingdialog_label.set_text(\
 609                             self.parent._("Creating packages index..."))
 610                         Thread(target = self.__update_install_pulse).start()
 611                         
 612         def ind_output_done(self):
 613                 self.progress_stop_timer_thread = True
 614                 return
 615 
 616         @staticmethod
 617         def get_datetime(date_time):
 618                 '''Support function for getting date from the API.'''
 619                 date_tmp = time.strptime(date_time, "%a %b %d %H:%M:%S %Y")
 620                 date_tmp2 = datetime.datetime(*date_tmp[0:5])
 621                 return date_tmp2.strftime(":%m%d")