home *** CD-ROM | disk | FTP | other *** search
/ Maximum CD 2011 October / maximum-cd-2011-10.iso / DiscContents / digsby_setup.exe / lib / plugins / digsby_updater / updater.pyo (.txt) < prev    next >
Encoding:
Python Compiled Bytecode  |  2011-06-22  |  22.9 KB  |  630 lines

  1. # Source Generated with Decompyle++
  2. # File: in.pyo (Python 2.6)
  3.  
  4. import logging
  5. log = logging.getLogger('d_updater')
  6. import sys
  7. import traceback
  8. import io
  9. import time
  10. import wx
  11. import gui
  12. import hashlib
  13. import path
  14. import syck
  15. import config
  16. import stdpaths
  17. import hooks
  18. import peak.util.addons as addons
  19. import lxml.objectify as objectify
  20. import util
  21. import util.net as net
  22. import util.callbacks as callbacks
  23. import common
  24. import common.asynchttp as asynchttp
  25. import file_integrity
  26. import downloader
  27. if config.platform == 'win':
  28.     import winhelpers as helpers
  29. elif config.platform == 'mac':
  30.     import machelpers as helpers
  31.  
  32.  
  33. def rm_emptydirs(dir):
  34.     for d in dir.dirs():
  35.         rm_emptydirs(d)
  36.     
  37.     if not dir.files() or dir.dirs():
  38.         
  39.         try:
  40.             dir.rmdir()
  41.         except Exception:
  42.             pass
  43.         except:
  44.             None<EXCEPTION MATCH>Exception
  45.         
  46.  
  47.     None<EXCEPTION MATCH>Exception
  48.  
  49.  
  50. class UpdateChecker(object):
  51.     
  52.     def __init__(self, release_type = None):
  53.         self.remote_manifest_path = None
  54.         if not release_type:
  55.             pass
  56.         self.release_type = self.get_release_type()
  57.         self.callback = None
  58.  
  59.     
  60.     def update(self, callback = None):
  61.         self.callback = callback
  62.         self.get_manifest_path()
  63.  
  64.     update = callbacks.callsback(update)
  65.     
  66.     def manifest_path_error(self, e):
  67.         log.info('Error getting manifest path: %r', e)
  68.         self._error(e)
  69.  
  70.     
  71.     def manifest_request_error(self, e):
  72.         log.error('Error retrieving manifest file: %r', e)
  73.         self._error(e)
  74.  
  75.     
  76.     def manifest_check_error(self, e):
  77.         log.error('Error checking manifest integrity: %r', e)
  78.         self._error(e)
  79.  
  80.     
  81.     def update_check_complete(self, needs_update, manifest_data):
  82.         log.info('Update check complete. Need update? %r', needs_update)
  83.         self._success(needs_update, self.remote_manifest_path, manifest_data)
  84.  
  85.     
  86.     def _error(self, e):
  87.         cb = self.callback
  88.         self.callback = None
  89.         if cb is not None:
  90.             cb.error(e)
  91.         
  92.  
  93.     
  94.     def _success(self, *a):
  95.         cb = self.callback
  96.         self.callback = None
  97.         if cb is not None:
  98.             cb.success(*a)
  99.         
  100.  
  101.     
  102.     def check_manifest_integrity(self, req, resp):
  103.         headers = resp.headers
  104.         rmtime = headers.get('x-amz-meta-mtime', None)
  105.         if rmtime is None:
  106.             rmtime = headers.get('last-modified', None)
  107.             if rmtime is not None:
  108.                 rmtime = net.http_date_to_timestamp(rmtime)
  109.             
  110.         
  111.         if rmtime is not None:
  112.             
  113.             try:
  114.                 rmtime = int(rmtime)
  115.             except (TypeError, ValueError):
  116.                 rmtime = None
  117.             except:
  118.                 None<EXCEPTION MATCH>(TypeError, ValueError)
  119.             
  120.  
  121.         None<EXCEPTION MATCH>(TypeError, ValueError)
  122.         prog_dir = util.program_dir()
  123.         self.local_manifest_path = path.path(prog_dir) / path.path(self.remote_manifest_path).splitpath()[-1]
  124.         needs_update = True
  125.         if self.local_manifest_path.isfile():
  126.             lmtime = int(self.local_manifest_path.mtime)
  127.         else:
  128.             lmtime = 0
  129.         if sys.opts.force_update or lmtime != rmtime:
  130.             log.info('MTime mismatch or sys.opts.force_update is True. Downloading manifest. (local=%r, remote=%r)', lmtime, rmtime)
  131.             downloader.httpopen(self.remote_manifest_path, success = self.got_manifest_response, error = self.manifest_request_error)
  132.         else:
  133.             log.info('Local MTime matches remote. Not downloading manifest. (local=%r, remote=%r)', lmtime, rmtime)
  134.             self.update_check_complete(False, None)
  135.  
  136.     
  137.     def got_manifest_response(self, req, resp):
  138.         if self.local_manifest_path.isfile():
  139.             local_manifest_digest = self.local_manifest_path.read_md5()
  140.         else:
  141.             local_manifest_digest = None
  142.         log.info('Got manifest response. Comparing hashes.')
  143.         manifest_data = resp.read()
  144.         remote_manifest_digest = hashlib.md5(manifest_data).digest()
  145.         needs_update = local_manifest_digest != remote_manifest_digest
  146.         if sys.opts.force_update:
  147.             needs_update = True
  148.         
  149.         if not needs_update:
  150.             manifest_data = None
  151.         
  152.         self.update_check_complete(needs_update, manifest_data)
  153.  
  154.     
  155.     def get_release_type(self):
  156.         return get_client_tag()
  157.  
  158.     
  159.     def get_manifest_path(self):
  160.         program_dir = util.program_dir()
  161.         local_info_file = program_dir / 'update.yaml'
  162.         if local_info_file.isfile():
  163.             
  164.             try:
  165.                 local_info = open(local_info_file, 'rb')
  166.             except Exception:
  167.                 pass
  168.  
  169.             self.got_updateyaml(fobj = local_info)
  170.             return None
  171.         local_info_file.isfile()
  172.         log.info('Manifest path not found in %r. checking web for update.yaml', local_info_file)
  173.         asynchttp.httpopen('http://s3.amazonaws.com/update.digsby.com/update.yaml?%s' % int(time.time()), success = self.got_updateyaml, error = self.manifest_path_error)
  174.  
  175.     
  176.     def got_updateyaml(self, req = None, fobj = None):
  177.         
  178.         try:
  179.             data = fobj.read()
  180.         except Exception:
  181.             e = None
  182.             return self.manifest_path_error(e)
  183.  
  184.         
  185.         try:
  186.             ui = syck.load(data)
  187.         except Exception:
  188.             e = None
  189.             return self.manifest_path_error(e)
  190.  
  191.         all = ui.get('all', { })
  192.         if not ui.get(config.platform, None):
  193.             pass
  194.         mine = { }
  195.         merged = all.copy()
  196.         merged.update(mine)
  197.         manifest_path = merged.get(self.release_type, merged.get('release', None))
  198.         if manifest_path is None:
  199.             self.update_check_error(Exception('No manifest URL for %r in %r' % (self.release_type, all)))
  200.         else:
  201.             log.info('Got manifest path: %r', manifest_path)
  202.             self.remote_manifest_path = manifest_path
  203.             downloader.httpopen(self.remote_manifest_path, method = 'HEAD', success = self.check_manifest_integrity, error = self.manifest_check_error)
  204.  
  205.  
  206.  
  207. def help_menu_items(*a):
  208.     if not common.pref('digsby.updater.help_menu', type = bool, default = True):
  209.         return []
  210.     if sys.TAG and sys.TAG != 'release':
  211.         txt = _('Check for %s updates') % sys.TAG
  212.     else:
  213.         txt = _('Check for Updates')
  214.     return [
  215.         (txt, update_check)]
  216.  
  217.  
  218. def update_check(*a):
  219.     p = common.profile()
  220.     if p is not None:
  221.         UpdateManager(p).update()
  222.     
  223.  
  224.  
  225. def update_check_later(*a):
  226.     util.Timer(common.pref('digsby.updater.initial_delay', type = int, default = 300), update_check).start()
  227.  
  228.  
  229. def on_update_complete(*a):
  230.     for handler in logging.root.handlers:
  231.         handler.flush()
  232.     
  233.     src_file = path.path(sys.LOGFILE_NAME)
  234.     dst_file = src_file.parent / 'digsby_update_download.log.csv'
  235.     
  236.     try:
  237.         data = src_file.bytes()
  238.     except Exception:
  239.         e = None
  240.         f = io.BytesIO()
  241.         traceback.print_exc(file = f)
  242.         data = f.getvalue()
  243.         del f
  244.  
  245.     
  246.     try:
  247.         f = _[1]
  248.         f.write(data)
  249.     finally:
  250.         pass
  251.  
  252.  
  253.  
  254. def update_cancel(*a):
  255.     p = common.profile()
  256.     if p is not None:
  257.         UpdateManager(p).cancel()
  258.     
  259.  
  260.  
  261. def start_fastmode(*a):
  262.     p = common.profile()
  263.     if p is not None:
  264.         UpdateManager(p).set_fastmode(True)
  265.     
  266.  
  267.  
  268. def stop_fastmode(*a):
  269.     p = common.profile()
  270.     if p is not None:
  271.         UpdateManager(p).set_fastmode(False)
  272.     
  273.  
  274.  
  275. def load_tag_and_install_update(*a):
  276.     get_client_tag()
  277.     return install_update()
  278.  
  279.  
  280. def was_updated():
  281.     if sys.opts.updated:
  282.         p = common.profile()
  283.         buddy = util.Storage(name = 'digsby.org', service = 'digsby', protocol = p.connection, increase_log_size = (lambda : pass), icon = None)
  284.         msg = common.message.Message(buddy = buddy, message = _get_release_notes(), content_type = 'text/html', conversation = util.Storage(protocol = p.connection, buddy = buddy, ischat = False))
  285.         p.on_message(msg)
  286.     
  287.  
  288.  
  289. def _get_release_notes():
  290.     
  291.     try:
  292.         
  293.         try:
  294.             f = _[1]
  295.             data = f.read()
  296.         finally:
  297.             pass
  298.  
  299.         return data
  300.     except Exception:
  301.         e = None
  302.         log.error('Release notes not found. %r', e)
  303.         return ''
  304.  
  305.  
  306.  
  307. def install_update(*a):
  308.     temp_dir = file_integrity.GetUserTempDir()
  309.     manifest = temp_dir / 'manifest'
  310.     updateme = temp_dir / 'updateme.txt'
  311.     deleteme = temp_dir / 'deleteme.txt'
  312.     if UpdateManager(Null()).should_check_for_updates() and not (sys.opts.update_failed):
  313.         if updateme.isfile() and deleteme.isfile() and manifest.isfile():
  314.             print >>sys.stderr, 'Installing update'
  315.             log.info('Installing update')
  316.             helpers.restart_and_update(temp_dir)
  317.             return False
  318.     else:
  319.         _delete_updater_files()
  320.         print >>sys.stderr, 'Not installing update'
  321.         log.info('Not installing update')
  322.  
  323.  
  324. def _delete_updater_files():
  325.     temp_dir = file_integrity.GetUserTempDir()
  326.     manifest = temp_dir / 'manifest'
  327.     updateme = temp_dir / 'updateme.txt'
  328.     deleteme = temp_dir / 'deleteme.txt'
  329.     if updateme.isfile():
  330.         updateme.remove()
  331.     
  332.     if deleteme.isfile():
  333.         deleteme.remove()
  334.     
  335.     if manifest.isfile():
  336.         manifest.remove()
  337.     
  338.     sys.opts.update_failed = False
  339.  
  340.  
  341. def update_status():
  342.     p = common.profile()
  343.     if p is None:
  344.         return False
  345.     um = UpdateManager(p)
  346.     if um.updating:
  347.         if um.downloader:
  348.             return 'downloading'
  349.         if um.updater:
  350.             return 'filechecking'
  351.         return 'checking'
  352.     return 'idle'
  353.  
  354.  
  355. def get_client_tag():
  356.     if getattr(sys, 'DEV', False):
  357.         tag = ''
  358.     else:
  359.         tag = 'release'
  360.     tag_fname = 'tag.yaml'
  361.     for fpath in (stdpaths.userlocaldata / tag_fname, util.program_dir() / tag_fname):
  362.         
  363.         try:
  364.             
  365.             try:
  366.                 f = _[1]
  367.                 yaml = syck.load(f)
  368.                 tag = yaml['tag']
  369.             finally:
  370.                 pass
  371.  
  372.         except Exception:
  373.             e = None
  374.             log.debug("Didn't get a release tag from %r: %r", fpath, e)
  375.             continue
  376.  
  377.         log.info('Got release tag %r from %r', tag, fpath)
  378.     
  379.     sys.TAG = tag
  380.     return tag
  381.  
  382.  
  383. class UpdateManager(addons.AddOn):
  384.     updating = False
  385.     
  386.     def setup(self):
  387.         log.info('UpdateManager setup')
  388.         self.updating = False
  389.         self.cancelling = False
  390.         self.updater = None
  391.         self.downloader = None
  392.         self.update_checker = UpdateChecker()
  393.         self._timer = util.RepeatTimer(common.pref('digsby.updater.update_interval', type = int, default = 21600), self.update)
  394.         self._timer.start()
  395.         self.fast_mode = False
  396.  
  397.     
  398.     def set_fastmode(self, v):
  399.         self.fast_mode = v
  400.         if self.updater is not None:
  401.             self.updater.fast_mode = v
  402.         
  403.  
  404.     
  405.     def cancel(self):
  406.         if not self.updating:
  407.             return None
  408.         self.updating = False
  409.         self.cancelling = True
  410.         if self.updater is not None:
  411.             self.updater.cancel()
  412.             self.updater = None
  413.         
  414.         if self.downloader is not None:
  415.             self.downloader.cancel()
  416.             self.downloader = None
  417.         
  418.         hooks.notify('digsby.updater.cancelled')
  419.  
  420.     
  421.     def should_check_for_updates(self):
  422.         retval = True
  423.         reason = None
  424.         if not sys.opts.allow_update:
  425.             retval = False
  426.             reason = 'sys.opts.allow_updates == False'
  427.         
  428.         if sys.DEV and not (sys.opts.force_update):
  429.             retval = False
  430.             reason = 'sys.DEV and not sys.opts.force_update'
  431.         
  432.         if self.updating:
  433.             retval = False
  434.             reason = 'already checking for updates, or currently updating'
  435.         
  436.         if not retval:
  437.             log.info('Not checking for updates because: %r', reason)
  438.         
  439.         return retval
  440.  
  441.     
  442.     def update(self):
  443.         if not self.should_check_for_updates():
  444.             if not self.updating:
  445.                 hooks.notify('digsby.updater.update_check_results', False, None, None)
  446.             
  447.             return None
  448.         self.delete_file_changes()
  449.         self.cancelling = False
  450.         self.updating = True
  451.         hooks.notify('digsby.updater.update_start')
  452.         self.update_checker.release_type = get_client_tag()
  453.         self.update_checker.update(success = self.update_check_success, error = self.update_check_error)
  454.  
  455.     
  456.     def update_check_success(self, update_required, manifest_path, manifest_data):
  457.         log.info('Got result for update check. update_required = %r, manifest_path = %r', update_required, manifest_path)
  458.         hooks.notify('digsby.updater.update_check_results', update_required, manifest_path, manifest_data)
  459.         if not update_required:
  460.             self.cancel()
  461.             return None
  462.         if self.cancelling:
  463.             return None
  464.         log.info('Starting updater.')
  465.         self.updater = file_integrity.ProgramIntegrityChecker(manifest_path = manifest_path, manifest_data = manifest_data)
  466.         self.updater.start(success = self.file_check_complete)
  467.  
  468.     
  469.     def update_check_error(self, *a):
  470.         self.cancel()
  471.         hooks.notify('digsby.updater.update_check_error', *a)
  472.  
  473.     
  474.     def file_check_complete(self, updater):
  475.         if not updater.update_files or updater.delete_files:
  476.             self.cancel()
  477.             return None
  478.         self.downloader = downloader.Downloader(updater)
  479.         auto_download = common.pref('digsby.updater.auto_download', type = bool, default = True)
  480.         res = []
  481.         
  482.         def after_popup():
  483.             if auto_download:
  484.                 self.start_downloader()
  485.             elif not res or res[0] is None:
  486.                 
  487.                 def dialog_cb(ok):
  488.                     if ok:
  489.                         self.start_downloader()
  490.                     else:
  491.                         self.stop_timer()
  492.  
  493.                 diag = gui.toolbox.SimpleMessageDialog(None, title = _('Update Available'), message = _('A Digsby update is available to download.\nWould you like to begin downloading it now?'), icon = gui.skin.get('serviceicons.digsby').Resized(32), ok_caption = _('Yes'), cancel_caption = _('No'), wrap = 450)
  494.                 diag.OnTop = True
  495.                 diag.ShowWithCallback(dialog_cb)
  496.             
  497.  
  498.         
  499.         def do_popup():
  500.             res.append(gui.toast.popup(icon = gui.skin.get('serviceicons.digsby'), header = _('Update Available'), minor = _('A Digsby update is available to download.\nWould you like to begin downloading it now?'), sticky = True, buttons = [
  501.                 ((_('Yes'),), (lambda : self.start_downloader())),
  502.                 (_('No'), self.stop_timer)], size = util.nicebytecount(updater.expected_download_size), onclose = self._download_popup_closed))
  503.             wx.CallAfter(after_popup)
  504.  
  505.         if not auto_download:
  506.             wx.CallAfter(do_popup)
  507.         else:
  508.             wx.CallAfter(after_popup)
  509.  
  510.     
  511.     def write_file_changes(self, temp, to_update, to_delete):
  512.         if not temp.isdir():
  513.             temp.makedirs()
  514.         
  515.         
  516.         try:
  517.             out = _[1]
  518.             if to_delete:
  519.                 
  520.                 write = lambda s: out.write(unicode(s).encode('filesys', 'replace') + '\n')
  521.                 for f in sorted(to_delete, reverse = True):
  522.                     rel_path = self.updater.local_dir.relpathto(f)
  523.                     write(rel_path)
  524.                 
  525.         finally:
  526.             pass
  527.  
  528.         
  529.         try:
  530.             out = _[2]
  531.             
  532.             write = lambda s: out.write(unicode(s).encode('filesys', 'replace') + '\n')
  533.             write('manifest')
  534.             for f in sorted(to_update, reverse = True):
  535.                 if f.path.lower() != helpers.get_exe_name().lower():
  536.                     write(f.path)
  537.                     continue
  538.                 (open(temp / 'updateme.txt', 'wb').__exit__,)
  539.         finally:
  540.             pass
  541.  
  542.  
  543.     
  544.     def delete_file_changes(self):
  545.         _delete_updater_files()
  546.  
  547.     
  548.     def start_downloader(self):
  549.         if self.cancelling:
  550.             return None
  551.         self.downloader.start(success = self.download_success, error = self.download_error)
  552.  
  553.     
  554.     def stop_timer(self, *a):
  555.         log.info('Stopping update checker timer.')
  556.         self._timer.stop()
  557.         self.cancel()
  558.  
  559.     
  560.     def _download_popup_closed(self, *a, **k):
  561.         if k.get('userClose', False):
  562.             self.stop_timer()
  563.         
  564.  
  565.     
  566.     def download_error(self, error_files, success_files):
  567.         log.error('Update incomplete. %d successful files, %d errored files', len(success_files), len(error_files))
  568.         for f in error_files:
  569.             log.error('\t%r', f.path)
  570.         
  571.         self.cancel()
  572.         hooks.notify('digsby.updater.update_failed')
  573.         auto_download = common.pref('digsby.updater.auto_download', type = bool, default = True)
  574.         if not auto_download:
  575.             popup = gui.toast.popup(icon = gui.skin.get('serviceicons.digsby'), header = _('Update Failed'), minor = _('Digsby was unable to complete the download. This update will be attempted again later.'), sticky = True, buttons = [
  576.                 (_('Manual Update'), (lambda : wx.LaunchDefaultBrowser('http://install.digsby.com'))),
  577.                 ((_('Close'),), (lambda : popup.cancel()))])
  578.         
  579.  
  580.     
  581.     def download_success(self, success_files):
  582.         log.info('Downloaded files. %d files downloaded', len(success_files))
  583.         updater = self.updater
  584.         if updater is None:
  585.             self.cancel()
  586.             return None
  587.         self.write_file_changes(updater.temp_dir, updater.update_files, updater.delete_files)
  588.         hooks.notify('digsby.updater.update_complete')
  589.         if not common.pref('digsby.updater.install_prompt', type = bool, default = False):
  590.             log.debug('Update install prompt disabled. Scheduling install')
  591.             self.schedule_install()
  592.         else:
  593.             res = []
  594.             
  595.             def after_popup():
  596.                 if not res or res[0] is None:
  597.                     log.debug('Popup was not shown. Scheduling install')
  598.                     self.schedule_install()
  599.                 
  600.  
  601.             
  602.             def do_popup():
  603.                 res.append(gui.toast.popup(icon = gui.skin.get('serviceicons.digsby'), header = _('Update Ready'), minor = _('A new version of Digsby is ready to install. Restart Digsby to apply the update.'), sticky = True, buttons = [
  604.                     (_('Restart Now'), self.do_install),
  605.                     (_('Restart Later'), self.schedule_install)], onclose = self._install_popup_closed))
  606.                 wx.CallAfter(after_popup)
  607.  
  608.             do_popup = (None, (None, None), wx.CallAfter)(do_popup)
  609.  
  610.     
  611.     def do_install(self):
  612.         log.info('Doing install!')
  613.         if self.cancelling:
  614.             log.info("\tNevermind, we're cancelling. Install not happening now.")
  615.             return None
  616.         install_update()
  617.  
  618.     
  619.     def _install_popup_closed(self, *a, **k):
  620.         if k.get('userClose', False):
  621.             self.schedule_install()
  622.         
  623.  
  624.     
  625.     def schedule_install(self):
  626.         log.info('Schedule install somehow!')
  627.         self.stop_timer()
  628.  
  629.  
  630.