mirror of
https://github.com/EDCD/EDMarketConnector.git
synced 2025-04-14 08:17:13 +03:00
Sparkle & WinSparkle integration for automatic updates.
This commit is contained in:
parent
0ad39ac41f
commit
b635fbb048
4
.gitignore
vendored
4
.gitignore
vendored
@ -2,8 +2,12 @@
|
|||||||
build
|
build
|
||||||
dist.*
|
dist.*
|
||||||
*.bak
|
*.bak
|
||||||
|
*.json
|
||||||
*.pyc
|
*.pyc
|
||||||
*.pyo
|
*.pyo
|
||||||
|
*.dll
|
||||||
|
*.pdb
|
||||||
*.msi
|
*.msi
|
||||||
*.wixobj
|
*.wixobj
|
||||||
|
*.xml
|
||||||
*.zip
|
*.zip
|
||||||
|
31
EDMarketConnector.manifest
Normal file
31
EDMarketConnector.manifest
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
<?xml version='1.0' encoding='UTF-8' standalone='yes'?>
|
||||||
|
<assembly xmlns='urn:schemas-microsoft-com:asm.v1' manifestVersion='1.0'>
|
||||||
|
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
|
||||||
|
<security>
|
||||||
|
<requestedPrivileges>
|
||||||
|
<requestedExecutionLevel level='asInvoker' uiAccess='false' />
|
||||||
|
</requestedPrivileges>
|
||||||
|
</security>
|
||||||
|
</trustInfo>
|
||||||
|
<dependency>
|
||||||
|
<dependentAssembly>
|
||||||
|
<assemblyIdentity
|
||||||
|
type='win32'
|
||||||
|
name='Microsoft.VC90.CRT'
|
||||||
|
version='9.0.21022.8'
|
||||||
|
processorArchitecture='*'
|
||||||
|
publicKeyToken='1fc8b3b9a1e18e3b' />
|
||||||
|
</dependentAssembly>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<dependentAssembly>
|
||||||
|
<assemblyIdentity
|
||||||
|
type="win32"
|
||||||
|
name="Microsoft.Windows.Common-Controls"
|
||||||
|
version="6.0.0.0"
|
||||||
|
processorArchitecture="*"
|
||||||
|
publicKeyToken="6595b64144ccf1df"
|
||||||
|
language="*" />
|
||||||
|
</dependentAssembly>
|
||||||
|
</dependency>
|
||||||
|
</assembly>
|
@ -66,8 +66,15 @@ class AppWindow:
|
|||||||
child.grid_configure(padx=5, pady=(platform=='darwin' and 3 or 2))
|
child.grid_configure(padx=5, pady=(platform=='darwin' and 3 or 2))
|
||||||
|
|
||||||
menubar = tk.Menu()
|
menubar = tk.Menu()
|
||||||
self.w['menu'] = menubar
|
|
||||||
if platform=='darwin':
|
if platform=='darwin':
|
||||||
|
from Foundation import NSBundle
|
||||||
|
# https://www.tcl.tk/man/tcl/TkCmd/menu.htm
|
||||||
|
apple_menu = tk.Menu(menubar, name='apple')
|
||||||
|
apple_menu.add_command(label="About %s" % applongname, command=lambda:root.call('tk::mac::standardAboutPanel'))
|
||||||
|
apple_menu.add_command(label="Check for Update", command=lambda:self.updater.checkForUpdates())
|
||||||
|
menubar.add_cascade(menu=apple_menu)
|
||||||
|
window_menu = tk.Menu(menubar, name='window')
|
||||||
|
menubar.add_cascade(menu=window_menu)
|
||||||
# https://www.tcl.tk/man/tcl/TkCmd/tk_mac.htm
|
# https://www.tcl.tk/man/tcl/TkCmd/tk_mac.htm
|
||||||
root.createcommand('tkAboutDialog', lambda:root.call('tk::mac::standardAboutPanel'))
|
root.createcommand('tkAboutDialog', lambda:root.call('tk::mac::standardAboutPanel'))
|
||||||
root.createcommand("::tk::mac::Quit", self.onexit)
|
root.createcommand("::tk::mac::Quit", self.onexit)
|
||||||
@ -76,10 +83,12 @@ class AppWindow:
|
|||||||
root.protocol("WM_DELETE_WINDOW", self.w.withdraw) # close button shouldn't quit app
|
root.protocol("WM_DELETE_WINDOW", self.w.withdraw) # close button shouldn't quit app
|
||||||
else:
|
else:
|
||||||
file_menu = tk.Menu(menubar, tearoff=tk.FALSE)
|
file_menu = tk.Menu(menubar, tearoff=tk.FALSE)
|
||||||
|
file_menu.add_command(label="Check for Update", command=lambda:self.updater.checkForUpdates())
|
||||||
file_menu.add_command(label="Settings", command=lambda:prefs.PreferencesDialog(self.w, self.login))
|
file_menu.add_command(label="Settings", command=lambda:prefs.PreferencesDialog(self.w, self.login))
|
||||||
file_menu.add_command(label="Exit", command=self.onexit)
|
file_menu.add_command(label="Exit", command=self.onexit)
|
||||||
menubar.add_cascade(label="File", menu=file_menu)
|
menubar.add_cascade(label="File", menu=file_menu)
|
||||||
root.protocol("WM_DELETE_WINDOW", self.onexit)
|
root.protocol("WM_DELETE_WINDOW", self.onexit)
|
||||||
|
self.w['menu'] = menubar
|
||||||
|
|
||||||
# update geometry
|
# update geometry
|
||||||
if config.get('geometry'):
|
if config.get('geometry'):
|
||||||
@ -97,6 +106,12 @@ class AppWindow:
|
|||||||
else:
|
else:
|
||||||
self.login()
|
self.login()
|
||||||
|
|
||||||
|
# Load updater after UI creation (for WinSparkle)
|
||||||
|
import update
|
||||||
|
self.updater = update.Updater(master)
|
||||||
|
master.bind_all('<<Quit>>', self.onexit) # user-generated
|
||||||
|
|
||||||
|
|
||||||
# call after credentials have changed
|
# call after credentials have changed
|
||||||
def login(self):
|
def login(self):
|
||||||
self.status['text'] = 'Logging in...'
|
self.status['text'] = 'Logging in...'
|
||||||
@ -190,7 +205,7 @@ class AppWindow:
|
|||||||
self.status['text'] = status
|
self.status['text'] = status
|
||||||
self.w.update_idletasks()
|
self.w.update_idletasks()
|
||||||
|
|
||||||
def onexit(self):
|
def onexit(self, event=None):
|
||||||
config.set('geometry', '+{1}+{2}'.format(*self.w.geometry().split('+')))
|
config.set('geometry', '+{1}+{2}'.format(*self.w.geometry().split('+')))
|
||||||
config.close()
|
config.close()
|
||||||
self.session.close()
|
self.session.close()
|
||||||
|
@ -17,6 +17,9 @@
|
|||||||
Description="$(var.PRODUCTLONGNAME) installer"
|
Description="$(var.PRODUCTLONGNAME) installer"
|
||||||
InstallerVersion="300" Compressed="yes" />
|
InstallerVersion="300" Compressed="yes" />
|
||||||
|
|
||||||
|
<!-- Always reinstall since patching is problematic -->
|
||||||
|
<MajorUpgrade AllowSameVersionUpgrades="yes" DowngradeErrorMessage="A newer version of [ProductName] is already installed." />
|
||||||
|
|
||||||
<Media Id="1" Cabinet="product.cab" EmbedCab="yes" />
|
<Media Id="1" Cabinet="product.cab" EmbedCab="yes" />
|
||||||
|
|
||||||
<Icon Id="EDMarketConnector.exe" SourceFile="EDMarketConnector.ico"/>
|
<Icon Id="EDMarketConnector.exe" SourceFile="EDMarketConnector.ico"/>
|
||||||
@ -87,6 +90,9 @@
|
|||||||
<Component Id="cmpF53EFD7F16A85DF32B289806E475CEC1" Guid="{E8E3701A-8AA1-4D46-A56D-7AF08D6AFCD4}">
|
<Component Id="cmpF53EFD7F16A85DF32B289806E475CEC1" Guid="{E8E3701A-8AA1-4D46-A56D-7AF08D6AFCD4}">
|
||||||
<File Id="filEB07038D0C43A2635802F5F0874B19F4" KeyPath="yes" Source="SourceDir\unicodedata.pyd" />
|
<File Id="filEB07038D0C43A2635802F5F0874B19F4" KeyPath="yes" Source="SourceDir\unicodedata.pyd" />
|
||||||
</Component>
|
</Component>
|
||||||
|
<Component Id="cmp775D0CC23474B987B407951838E0DCC3" Guid="{3117D2CF-1D87-4B99-BE44-7BDDFE8C8E60}">
|
||||||
|
<File Id="fil293C8E7AF8C6F689C7E50983C257DD68" KeyPath="yes" Source="SourceDir\WinSparkle.dll" />
|
||||||
|
</Component>
|
||||||
<Directory Id="dirBEE0D5863824B80A537E14FE56402A0C" Name="tcl">
|
<Directory Id="dirBEE0D5863824B80A537E14FE56402A0C" Name="tcl">
|
||||||
<Directory Id="dir9FADF4954D330D96E48B9D59CBE9A964" Name="tcl8.5">
|
<Directory Id="dir9FADF4954D330D96E48B9D59CBE9A964" Name="tcl8.5">
|
||||||
<Component Id="cmpE60B2042B4B6A6FC78D8B97E5C31EFE2" Guid="{C085794D-6644-4915-B1C3-3060BE9E3F3B}">
|
<Component Id="cmpE60B2042B4B6A6FC78D8B97E5C31EFE2" Guid="{C085794D-6644-4915-B1C3-3060BE9E3F3B}">
|
||||||
@ -314,6 +320,7 @@
|
|||||||
<ComponentRef Id="cmp47BC2E37E918091103765A3E7BD81D06" />
|
<ComponentRef Id="cmp47BC2E37E918091103765A3E7BD81D06" />
|
||||||
<ComponentRef Id="cmp4854ADD13616F64F327353F410CEDC44" />
|
<ComponentRef Id="cmp4854ADD13616F64F327353F410CEDC44" />
|
||||||
<ComponentRef Id="cmpF53EFD7F16A85DF32B289806E475CEC1" />
|
<ComponentRef Id="cmpF53EFD7F16A85DF32B289806E475CEC1" />
|
||||||
|
<ComponentRef Id="cmp775D0CC23474B987B407951838E0DCC3" />
|
||||||
<ComponentRef Id="cmpE60B2042B4B6A6FC78D8B97E5C31EFE2" />
|
<ComponentRef Id="cmpE60B2042B4B6A6FC78D8B97E5C31EFE2" />
|
||||||
<ComponentRef Id="cmp89797FC50D96847B20F83F5F004B305D" />
|
<ComponentRef Id="cmp89797FC50D96847B20F83F5F004B305D" />
|
||||||
<ComponentRef Id="cmp46F96A08F279F9A56AA11B7A48864E3B" />
|
<ComponentRef Id="cmp46F96A08F279F9A56AA11B7A48864E3B" />
|
||||||
|
15
README.md
15
README.md
@ -59,7 +59,20 @@ Running from source & packaging
|
|||||||
--------
|
--------
|
||||||
The application requires Python 2.7, plus the "requests" module. Run with `python EDMarketConnector.py`.
|
The application requires Python 2.7, plus the "requests" module. Run with `python EDMarketConnector.py`.
|
||||||
|
|
||||||
To package up for distribution requires py2app 0.9.x on Mac, and py2exe 0.6.x plus the [WiX Toolset](http://wixtoolset.org/) on Windows. Run `setup.py py2app` or `setup.py py2exe`.
|
To package up for distribution:
|
||||||
|
|
||||||
|
Mac:
|
||||||
|
|
||||||
|
* requires py2app 0.9.x
|
||||||
|
* [Sparkle.framework](https://github.com/sparkle-project/Sparkle) installed in /Library/Frameworks
|
||||||
|
* Run `setup.py py2app`
|
||||||
|
|
||||||
|
Windows:
|
||||||
|
|
||||||
|
* requires py2exe 0.6.x
|
||||||
|
* winsparkle.dll & .pdb from [WinSparkle](https://github.com/vslavik/winsparkle) copied to the current directory
|
||||||
|
* [WiX Toolset](http://wixtoolset.org/)
|
||||||
|
* Run `setup.py py2exe`
|
||||||
|
|
||||||
|
|
||||||
Acknowledgements
|
Acknowledgements
|
||||||
|
10
config.py
10
config.py
@ -131,6 +131,16 @@ class Config:
|
|||||||
SHDeleteKey(oldkey, '')
|
SHDeleteKey(oldkey, '')
|
||||||
RegCloseKey(oldkey)
|
RegCloseKey(oldkey)
|
||||||
|
|
||||||
|
# set WinSparkle defaults - https://github.com/vslavik/winsparkle/wiki/Registry-Settings
|
||||||
|
sparklekey = HKEY()
|
||||||
|
if not RegCreateKeyEx(self.hkey, 'WinSparkle', 0, None, 0, KEY_ALL_ACCESS, None, ctypes.byref(sparklekey), ctypes.byref(disposition)):
|
||||||
|
if disposition.value == REG_CREATED_NEW_KEY:
|
||||||
|
buf = ctypes.create_unicode_buffer('1')
|
||||||
|
RegSetValueEx(sparklekey, 'CheckForUpdates', 0, 1, buf, len(buf)*2)
|
||||||
|
buf = ctypes.create_unicode_buffer(unicode(47*60*60))
|
||||||
|
RegSetValueEx(sparklekey, 'UpdateInterval', 0, 1, buf, len(buf)*2)
|
||||||
|
RegCloseKey(sparklekey)
|
||||||
|
|
||||||
if not self.get('outdir') or not isdir(self.get('outdir')):
|
if not self.get('outdir') or not isdir(self.get('outdir')):
|
||||||
ctypes.windll.shell32.SHGetSpecialFolderPathW(0, buf, CSIDL_PERSONAL, 0)
|
ctypes.windll.shell32.SHGetSpecialFolderPathW(0, buf, CSIDL_PERSONAL, 0)
|
||||||
self.set('outdir', buf.value)
|
self.set('outdir', buf.value)
|
||||||
|
55
setup.py
55
setup.py
@ -54,17 +54,23 @@ SHORTVERSION = ''.join(VERSION.split('.')[:3])
|
|||||||
PY2APP_OPTIONS = {'dist_dir': dist_dir,
|
PY2APP_OPTIONS = {'dist_dir': dist_dir,
|
||||||
'optimize': 2,
|
'optimize': 2,
|
||||||
'packages': [ 'requests' ],
|
'packages': [ 'requests' ],
|
||||||
|
'frameworks': [ 'Sparkle.framework' ],
|
||||||
'excludes': [ 'PIL' ],
|
'excludes': [ 'PIL' ],
|
||||||
'iconfile': '%s.icns' % APPNAME,
|
'iconfile': '%s.icns' % APPNAME,
|
||||||
'semi_standalone': True,
|
'semi_standalone': True,
|
||||||
'site_packages': False,
|
'site_packages': False,
|
||||||
'plist': {
|
'plist': {
|
||||||
'CFBundleName': APPNAME,
|
'CFBundleName': APPLONGNAME,
|
||||||
'CFBundleIdentifier': 'uk.org.marginal.%s' % APPNAME.lower(),
|
'CFBundleIdentifier': 'uk.org.marginal.%s' % APPNAME.lower(),
|
||||||
'CFBundleShortVersionString': VERSION,
|
'CFBundleShortVersionString': VERSION,
|
||||||
'CFBundleVersion': VERSION,
|
'CFBundleVersion': VERSION,
|
||||||
'LSMinimumSystemVersion': '.'.join(platform.mac_ver()[0].split('.')[:2]), # minimum version = build version
|
'LSMinimumSystemVersion': '.'.join(platform.mac_ver()[0].split('.')[:2]), # minimum version = build version
|
||||||
'NSHumanReadableCopyright': u'© 2015 Jonathan Harris',
|
'NSHumanReadableCopyright': u'© 2015 Jonathan Harris',
|
||||||
|
'SUEnableAutomaticChecks': True,
|
||||||
|
'SUShowReleaseNotes': True,
|
||||||
|
'SUAllowsAutomaticUpdates': False,
|
||||||
|
'SUFeedURL': 'http://marginal.org.uk/edmarketconnector.xml',
|
||||||
|
'SUScheduledCheckInterval': 47*60*60,
|
||||||
},
|
},
|
||||||
'graph': True, # output dependency graph in dist
|
'graph': True, # output dependency graph in dist
|
||||||
}
|
}
|
||||||
@ -78,6 +84,7 @@ PY2EXE_OPTIONS = {'dist_dir': dist_dir,
|
|||||||
if sys.platform=='win32':
|
if sys.platform=='win32':
|
||||||
import requests
|
import requests
|
||||||
DATA_FILES = [ ('', [requests.certs.where(),
|
DATA_FILES = [ ('', [requests.certs.where(),
|
||||||
|
'WinSparkle.dll',
|
||||||
'%s.ico' % APPNAME ] ) ]
|
'%s.ico' % APPNAME ] ) ]
|
||||||
else:
|
else:
|
||||||
DATA_FILES = [ ]
|
DATA_FILES = [ ]
|
||||||
@ -89,6 +96,9 @@ setup(
|
|||||||
windows = [ {'script': APP,
|
windows = [ {'script': APP,
|
||||||
'icon_resources': [(0, '%s.ico' % APPNAME)],
|
'icon_resources': [(0, '%s.ico' % APPNAME)],
|
||||||
'copyright': u'© 2015 Jonathan Harris',
|
'copyright': u'© 2015 Jonathan Harris',
|
||||||
|
'name': APPNAME, # WinSparkle
|
||||||
|
'company_name': 'Marginal', # WinSparkle
|
||||||
|
'other_resources': [(24, 1, open(APPNAME+'.manifest').read())],
|
||||||
} ],
|
} ],
|
||||||
data_files = DATA_FILES,
|
data_files = DATA_FILES,
|
||||||
options = { 'py2app': PY2APP_OPTIONS,
|
options = { 'py2app': PY2APP_OPTIONS,
|
||||||
@ -98,22 +108,39 @@ setup(
|
|||||||
|
|
||||||
|
|
||||||
if sys.platform == 'darwin':
|
if sys.platform == 'darwin':
|
||||||
if isdir('%s/%s.app' % (dist_dir, APPNAME)):
|
if isdir('%s/%s.app' % (dist_dir, APPLONGNAME)): # from CFBundleName
|
||||||
|
os.rename('%s/%s.app' % (dist_dir, APPLONGNAME), '%s/%s.app' % (dist_dir, APPNAME))
|
||||||
if macdeveloperid:
|
if macdeveloperid:
|
||||||
os.system('codesign --deep -v -s "Developer ID Application: %s" %s/%s.app' % (macdeveloperid, dist_dir, APPNAME))
|
os.system('codesign --deep -v -s "Developer ID Application: %s" %s/%s.app' % (macdeveloperid, dist_dir, APPNAME))
|
||||||
# Make zip for distribution, preserving signature
|
# Make zip for distribution, preserving signature
|
||||||
os.system('cd %s; ditto -ck --keepParent --sequesterRsrc %s.app ../%s_mac_%s.zip; cd ..' % (dist_dir, APPNAME, APPNAME, SHORTVERSION))
|
PKG = '%s_mac_%s.zip' % (APPNAME, SHORTVERSION)
|
||||||
|
os.system('cd %s; ditto -ck --keepParent --sequesterRsrc %s.app ../%s; cd ..' % (dist_dir, APPNAME, PKG))
|
||||||
else:
|
else:
|
||||||
# Manually trim the tcl/tk folders
|
shutil.copy('WinSparkle.pdb', dist_dir) # For debugging - not included in package
|
||||||
os.unlink(join(dist_dir, 'w9xpopen.exe'))
|
|
||||||
for d in [ r'tcl\tcl8.5\encoding',
|
|
||||||
r'tcl\tcl8.5\http1.0',
|
|
||||||
r'tcl\tcl8.5\msgs',
|
|
||||||
r'tcl\tcl8.5\tzdata',
|
|
||||||
r'tcl\tk8.5\demos',
|
|
||||||
r'tcl\tk8.5\images',
|
|
||||||
r'tcl\tk8.5\msgs', ]:
|
|
||||||
shutil.rmtree(join(dist_dir, d))
|
|
||||||
os.system(r'"C:\Program Files (x86)\WiX Toolset v3.9\bin\candle.exe" -out %s\ %s.wxs' % (dist_dir, APPNAME))
|
os.system(r'"C:\Program Files (x86)\WiX Toolset v3.9\bin\candle.exe" -out %s\ %s.wxs' % (dist_dir, APPNAME))
|
||||||
if exists('%s/%s.wixobj' % (dist_dir, APPNAME)):
|
if exists('%s/%s.wixobj' % (dist_dir, APPNAME)):
|
||||||
os.system(r'"C:\Program Files (x86)\WiX Toolset v3.9\bin\light.exe" -sacl -spdb -sw1076 %s\%s.wixobj -out %s_win_%s.msi' % (dist_dir, APPNAME, APPNAME, SHORTVERSION))
|
PKG = '%s_win_%s.msi' % (APPNAME, SHORTVERSION)
|
||||||
|
os.system(r'"C:\Program Files (x86)\WiX Toolset v3.9\bin\light.exe" -sacl -spdb -sw1076 %s\%s.wixobj -out %s' % (dist_dir, APPNAME, PKG))
|
||||||
|
|
||||||
|
# Make appcast entry
|
||||||
|
appcast = open('appcast_%s_%s.xml' % (sys.platform=='darwin' and 'mac' or 'win', SHORTVERSION), 'w')
|
||||||
|
appcast.write('''
|
||||||
|
\t\t<item>
|
||||||
|
\t\t\t<title>Release {0}</title>
|
||||||
|
\t\t\t<description>
|
||||||
|
\t\t\t\t<![CDATA[
|
||||||
|
<h2>Release {0}</h2>
|
||||||
|
<ul>
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
\t\t\t\t]]>
|
||||||
|
\t\t\t</description>
|
||||||
|
\t\t\t<enclosure
|
||||||
|
\t\t\t\turl="https://github.com/Marginal/EDMarketConnector/releases/download/rel-{1}/{2}"
|
||||||
|
\t\t\t\tsparkle:os="{3}"
|
||||||
|
\t\t\t\tsparkle:version="{4}"
|
||||||
|
\t\t\t\tlength="{5}"
|
||||||
|
\t\t\t\ttype="application/octet-stream"
|
||||||
|
\t\t\t/>
|
||||||
|
\t\t</item>
|
||||||
|
'''.format(float(SHORTVERSION)/100, SHORTVERSION, PKG, sys.platform=='darwin' and 'osx' or 'windows"\n\t\t\t\tsparkle:installerArguments="/passive', VERSION, os.stat(PKG).st_size))
|
||||||
|
97
update.py
Normal file
97
update.py
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
import os
|
||||||
|
from os.path import dirname, join
|
||||||
|
import sys
|
||||||
|
|
||||||
|
|
||||||
|
# ensure registry is set up on Windows before we start
|
||||||
|
import config
|
||||||
|
|
||||||
|
class NullUpdater:
|
||||||
|
|
||||||
|
def __init__(self, master):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def checkForUpdates(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def close(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
if not getattr(sys, 'frozen', False):
|
||||||
|
|
||||||
|
class Updater(NullUpdater):
|
||||||
|
pass
|
||||||
|
|
||||||
|
elif sys.platform=='darwin':
|
||||||
|
|
||||||
|
import objc
|
||||||
|
|
||||||
|
class Updater(NullUpdater):
|
||||||
|
|
||||||
|
# https://github.com/sparkle-project/Sparkle/wiki/Customization
|
||||||
|
|
||||||
|
def __init__(self, master):
|
||||||
|
try:
|
||||||
|
objc.loadBundle('Sparkle', globals(), join(dirname(sys.executable), os.pardir, 'Frameworks', 'Sparkle.framework'))
|
||||||
|
self.updater = SUUpdater.sharedUpdater()
|
||||||
|
except:
|
||||||
|
# can't load framework - not frozen or not included in app bundle?
|
||||||
|
self.updater = None
|
||||||
|
|
||||||
|
def checkForUpdates(self):
|
||||||
|
if self.updater:
|
||||||
|
self.updater.checkForUpdates_(None)
|
||||||
|
|
||||||
|
def close():
|
||||||
|
self.updater = None
|
||||||
|
|
||||||
|
|
||||||
|
elif sys.platform=='win32':
|
||||||
|
|
||||||
|
import ctypes
|
||||||
|
|
||||||
|
# https://github.com/vslavik/winsparkle/blob/master/include/winsparkle.h#L272
|
||||||
|
root = None
|
||||||
|
|
||||||
|
def shutdown_request():
|
||||||
|
root.event_generate('<<Quit>>', when="tail")
|
||||||
|
|
||||||
|
class Updater(NullUpdater):
|
||||||
|
|
||||||
|
# https://github.com/vslavik/winsparkle/wiki/Basic-Setup
|
||||||
|
|
||||||
|
def __init__(self, master):
|
||||||
|
try:
|
||||||
|
sys.frozen # don't want to try updating python.exe
|
||||||
|
self.updater = ctypes.cdll.WinSparkle
|
||||||
|
self.updater.win_sparkle_set_appcast_url('http://marginal.org.uk/edmarketconnector.xml') # py2exe won't let us embed this in resources
|
||||||
|
|
||||||
|
# set up shutdown callback
|
||||||
|
global root
|
||||||
|
root = master
|
||||||
|
self.callback_t = ctypes.CFUNCTYPE(None) # keep reference
|
||||||
|
self.callback_fn = self.callback_t(shutdown_request)
|
||||||
|
self.updater.win_sparkle_set_shutdown_request_callback(self.callback_fn)
|
||||||
|
|
||||||
|
self.updater.win_sparkle_init()
|
||||||
|
|
||||||
|
except:
|
||||||
|
from traceback import print_exc
|
||||||
|
print_exc()
|
||||||
|
self.updater = None
|
||||||
|
|
||||||
|
def checkForUpdates(self):
|
||||||
|
if self.updater:
|
||||||
|
self.updater.win_sparkle_check_update_with_ui()
|
||||||
|
|
||||||
|
def close(self):
|
||||||
|
if self.updater:
|
||||||
|
updater.win_sparkle_cleanup()
|
||||||
|
self.updater = None
|
||||||
|
|
||||||
|
else:
|
||||||
|
|
||||||
|
class Updater(NullUpdater):
|
||||||
|
pass
|
||||||
|
|
Loading…
x
Reference in New Issue
Block a user