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")