OSDN Git Service

Initial version of updateCheck module. Basic framework is done, but checks don't...
authorJames Teh <jamie@jantrid.net>
Wed, 29 Feb 2012 02:15:04 +0000 (12:15 +1000)
committerJames Teh <jamie@jantrid.net>
Wed, 29 Feb 2012 02:15:04 +0000 (12:15 +1000)
source/updateCheck.py [new file with mode: 0644]

diff --git a/source/updateCheck.py b/source/updateCheck.py
new file mode 100644 (file)
index 0000000..19b415b
--- /dev/null
@@ -0,0 +1,160 @@
+#updateCheck.py\r
+#A part of NonVisual Desktop Access (NVDA)\r
+#This file is covered by the GNU General Public License.\r
+#See the file COPYING for more details.\r
+#Copyright (C) 2012 NV Access Limited\r
+\r
+"""Update checking functionality.\r
+"""\r
+\r
+import sys\r
+import os\r
+import threading\r
+import urllib\r
+import wx\r
+import versionInfo\r
+import languageHandler\r
+import gui\r
+from logHandler import log\r
+import config\r
+\r
+CHECK_URL = "http://www.nvda-project.org/updateCheck"\r
+\r
+# FIXME\r
+state = {\r
+       "lastCheck": 0,\r
+       "dontRemindVersion": None,\r
+}\r
+\r
+def checkForUpdate(auto=False):\r
+       """Check for an updated version of NVDA.\r
+       This will block, so it generally shouldn't be called from the main thread.\r
+       @param auto: Whether this is an automatic check for updates.\r
+       @type auto: bool\r
+       @return: Information about the update or C{None} if there is no update.\r
+       @rtype: dict\r
+       @raise RuntimeError: If there is an error checking for an update.\r
+       """\r
+       winVer = sys.getwindowsversion()\r
+       params = {\r
+               "autoCheck": auto,\r
+               "version": versionInfo.version,\r
+               "versionType": "stable",\r
+               "osVersion": "{v.major}.{v.minor}.{v.build} {v.service_pack}".format(v=winVer),\r
+               "x64": os.environ.get("PROCESSOR_ARCHITEW6432") == "AMD64",\r
+               "language": languageHandler.getLanguage(),\r
+       }\r
+       res = urllib.urlopen("%s?%s" % (CHECK_URL, urllib.urlencode(params)))\r
+       if res.code != 200:\r
+               raise RuntimeError("Checking for update failed with code %d" % res.code)\r
+       info = {}\r
+       for line in res:\r
+               line = line.rstrip()\r
+               try:\r
+                       key, val = line.split(": ", 1)\r
+               except ValueError:\r
+                       raise RuntimeError("Error in update check output")\r
+               info[key] = val\r
+       if not info:\r
+               return None\r
+       return info\r
+\r
+class CheckForUpdateUi(object):\r
+       """Check for an updated version of NVDA, presenting appropriate user interface.\r
+       Checks are performed in the background.\r
+       """\r
+\r
+       def __init__(self, auto=False):\r
+               """Constructor.\r
+               @param auto: Whether this is an automatic check for updates.\r
+               @type auto: bool\r
+               """\r
+               self.auto = auto\r
+               t = threading.Thread(target=self._bg)\r
+               t.daemon = True\r
+               t.start()\r
+\r
+       def _bg(self):\r
+               try:\r
+                       info = checkForUpdate(self.auto)\r
+               except:\r
+                       if self.auto:\r
+                               log.debugWarning("Error checking for update", exc_info=True)\r
+                       else:\r
+                               log.error("Error checking for update", exc_info=True)\r
+                               wx.CallAfter(self._error)\r
+                       return\r
+               if not info:\r
+                       # No update.\r
+                       if  not self.auto:\r
+                               wx.CallAfter(self._result, None)\r
+                       return\r
+               version = info["version"]\r
+               if self.auto and state["dontRemindVersion"] == version:\r
+                       # The user has already been automatically notified about this version.\r
+                       return\r
+               state["dontRemindVersion"] = version\r
+               wx.CallAfter(self._result, info)\r
+\r
+       def _error(self):\r
+               gui.messageBox(\r
+                       # Translators: A message indicating that an error occurred while checking for an update to NVDA.\r
+                       _("Error checking for update."),\r
+                       # Translators: The title of an error message dialog.\r
+                       _("Error"),\r
+                       wx.OK | wx.ICON_ERROR)\r
+\r
+       def _result(self, info):\r
+               UpdateResultDialog(gui.mainFrame, info, self.auto)\r
+\r
+class UpdateResultDialog(wx.Dialog):\r
+\r
+       def __init__(self, parent, updateInfo, auto):\r
+               # Translators: The title of the dialog informing the user about an NVDA update.\r
+               super(UpdateResultDialog, self).__init__(parent, title=_("NVDA Update"))\r
+               self.updateInfo = updateInfo\r
+               mainSizer = wx.BoxSizer(wx.VERTICAL)\r
+\r
+               if updateInfo:\r
+                       # Translators: A message indicating that an updated version of NVDA is available.\r
+                       # {version} will be replaced with the version; e.g. 2011.3.\r
+                       message = _("NVDA version {version} is available.").format(**updateInfo)\r
+               else:\r
+                       # Translators: A message indicating that no update to NVDA is available.\r
+                       message = _("No update available.")\r
+               mainSizer.Add(wx.StaticText(self, label=message))\r
+\r
+               if updateInfo:\r
+                       # Translators: The label of a button to download an NVDA update.\r
+                       item = wx.Button(self, label=_("&Download update"))\r
+                       item.Bind(wx.EVT_BUTTON, self.onDownloadButton)\r
+                       mainSizer.Add(item)\r
+\r
+                       if auto:\r
+                               # Translators: The label of a button to remind the user later about performing some action.\r
+                               item = wx.Button(self, label=_("Remind me &later"))\r
+                               item.Bind(wx.EVT_BUTTON, self.onLaterButton)\r
+                               mainSizer.Add(item)\r
+\r
+               # Translators: The label of a button to close a dialog.\r
+               item = wx.Button(self, wx.ID_CLOSE, label=_("&Close"))\r
+               item.Bind(wx.EVT_BUTTON, lambda evt: self.Close())\r
+               mainSizer.Add(item)\r
+               self.Bind(wx.EVT_CLOSE, lambda evt: self.Destroy())\r
+               self.EscapeId = wx.ID_CLOSE\r
+\r
+               self.Sizer = mainSizer\r
+               mainSizer.Fit(self)\r
+               self.Show()\r
+\r
+       def onDownloadButton(self, evt):\r
+               if config.isInstalledCopy():\r
+                       url = self.updateInfo["installerUrl"]\r
+               else:\r
+                       url = self.updateInfo["portableUrl"]\r
+               os.startfile(url)\r
+               self.Close()\r
+\r
+       def onLaterButton(self, evt):\r
+               state["dontRemindVersion"] = None\r
+               self.Close()\r