一、esky介紹
Esky is an auto-update framework for frozen Python applications. It provides a simple API through which apps can find, fetch and install updates, and a bootstrapping mechanism that keeps the app safe in the face of failed or partial updates. Updates can also be sent as differential patches.
Esky is currently capable of freezing apps with py2exe, py2app, cxfreeze and bbfreeze. Adding support for other freezer programs should be easy; patches will be gratefully accepted.
We are tested and running on Python 2.7 Py2app will work on python3 fine, the other freezers not so much.
Esky是一個python編譯程序的自動升級框架,提供簡單的api實現應用的自動更新(包括比較版本、更新版本),esky支持py2exe,py2app,cxfreeze以及bbfreeze等多種python打包框架。
二、esky安裝及說明
1、pip安裝
pip install esky
2、esky說明
https://github.com/cloudmatrix/esky/
3、esky教學視頻
http://pyvideo.org/pycon-au-2010/pyconau-2010--esky--keep-your-frozen-apps-fresh.html
三、esky用法示例
esky用起來比較簡單,我們這里以常用的基於wx的windows應用舉例。
wxpython下有個wx.lib.softwareupdate 類,對wxpython應用的esky升級進行了二次封裝。
網上有個現成的示范例子,具體網址:http://www.blog.pythonlibrary.org/2013/07/12/wxpython-updating-your-application-with-esky/
代碼很簡單,對其中的關鍵部分進行注釋說明(紅色字體部分):
# ---------------------------------------- # image_viewer2.py # # Created 03-20-2010 # # Author: Mike Driscoll # ---------------------------------------- import glob import os import wx from wx.lib.pubsub import setuparg1 from wx.lib.pubsub import pub as Publisher
#申明語句
from wx.lib.softwareupdate import SoftwareUpdate
import version ######################################################################## class ViewerPanel(wx.Panel): """""" #---------------------------------------------------------------------- def __init__(self, parent): """Constructor""" wx.Panel.__init__(self, parent) ... ######################################################################## class ViewerFrame(wx.Frame): """""" #---------------------------------------------------------------------- def __init__(self): """Constructor""" title = 'Image Viewer %s' %(version.VERSION) wx.Frame.__init__(self, None, title=title) panel = ViewerPanel(self) ……
########################################################################
#注意基類是兩個 class ImageApp(wx.App, SoftwareUpdate): """""" #---------------------------------------------------------------------- def OnInit(self): """Constructor""" BASEURL = "http://127.0.0.1:8000"
#升級初始化,參數1:檢查升級包的網頁地址,參數2:升級說明文件,升級網頁地址與升級說明文件可以不在一個目錄。 self.InitUpdates(BASEURL,BASEURL + 'ChangeLog.txt')
#啟動升級檢查,參數:是否顯示升級提示,默認顯示提示。顯然該語句可以放到按鈕或者菜單中觸發。 self.CheckForUpdate(silentUnlessUpdate=False) frame = ViewerFrame() self.SetTopWindow(frame) self.SetAppDisplayName('Image Viewer') #ViewerPanel..SetValue('Image Viewer %s' %(version.VERSION)) return True #---------------------------------------------------------------------- if __name__ == "__main__": app = wx.PySimpleApp() frame = ViewerFrame() app.MainLoop()
總結:
1、先聲明類
from wx.lib.softwareupdate import SoftwareUpdate
2、在app中調用聲明的類,做為基類之一
class UpApp(wx.App, SoftwareUpdate):
3、在app的中初始化softwareupate,一般放在OnInit()中
wx.GetApp().InitUpdates('http://127.0.0.1/update.html', 'http://127.0.0.1/ChangeLog.txt')
4、在窗口事件中調用升級檢查,可以放到菜單或者按鈕中
wx.GetApp().CheckForUpdate()
四、esky編譯腳本編寫
esky本身不支持編譯,所以必須調用cx_freeze或者py2exe之類進行python編譯,由於本人比較熟悉cx_freeze,所以……以下例子均是基於cx_freeze。
其編譯腳本跟cx_freeze的setup.py有點類似,先來一個簡單例子:
#coding=utf-8 #--------------------------------------------------------------------------- # This setup file serves as a model for how to structure your # distutils setup files for making self-updating applications using # Esky. When you run this script use # # python setup.py bdist_esky # # Esky will then use py2app or py2exe as appropriate to create the # bundled application and also its own shell that will help manage # doing the updates. See wx.lib.softwareupdate for the class you can # use to add self-updates to your applications, and you can see how # that code is used here in the superdoodle.py module. #--------------------------------------------------------------------------- from esky import bdist_esky from setuptools import setup # Common settings exeICON = 'mondrian.ico' NAME = "wxImageViewer"
#明確調用cx_freeze進行編譯 FREEZER ='cx_freeze' #cx_freeze的編譯options FREEZER_OPTIONS = { "excludes": ["tkinter","collections.sys",'collections._weakref']#, #剔除wx里tkinter包 }; APP = [bdist_esky.Executable("image_viewer.py", gui_only=True, icon=exeICON, )] DATA_FILES = [ 'mondrian.ico' ] ESKY_OPTIONS = dict( freezer_module = FREEZER, freezer_options = FREEZER_OPTIONS, enable_appdata_dir = True, bundle_msvcrt = False, ) # Build the app and the esky bundle setup( name = NAME, version = '1.0', scripts = APP, data_files = DATA_FILES, options = dict(bdist_esky=ESKY_OPTIONS), )
這個是編譯腳本,具體的編譯命令,如下。
五、編譯命令
注意setup.py中的version=1.0就是版本定義,若是要發布升級版,只要把version修改成1.1或者2.0,程序就會判斷為升級包,進行更新。
編譯分兩種方式,一種是編譯完整包,一種是編譯增量補丁包。
特別說明一下補丁包的生成機制:先編譯完整包,再比較老版本完整包、新版本完整包,生成差異補丁包。
1、編譯完整包
python setup.py bdist_esky
編譯之后會在dist目錄生成名為wxImageViewer-1.0.win-amd64.zip的打包文件,注意這個文件名本身就包含了版本信息:
1)、wxImageViewer是應用名,對應setup.py中的name定義
2)、1.0是版本號,對應setup.py中version定義
3)、amd64代表64位編譯版本,跟python的版本一致。
2、編譯增量補丁包
python setup.py bdist_esky_path
注意每次重新編譯,需要修改version,會自動生成會自動增量包。
譬如第二次編譯,修改version=2.0,則增量包為:wxImageViewer-1.0.win-amd64.from-2.0.patch
1)增量包文件基本很小
2)升級時會自動判斷是下載全新包,還是下載增量包。
譬如本地程序是1.0版本,服務器端發了2.0版本的升級文件:wxImageViewer-2.0.win-amd64.zip、wxImageViewer-1.0.win-amd64.from-2.0.patch,esky會自動只下載patch文件。
六、復雜的esky編譯腳本
1、實現目錄打包
2、實現應用程序版本信息設置
#coding=utf-8 #--------------------------------------------------------------------------- ''' Create by: joshua zou 2016.10.08 Purpose: 調用esky打包成執行文件,支持自動升級。 Example: python setup.py bdist_esky / python setup.py bdist_esky_patch ''' #--------------------------------------------------------------------------- from esky import bdist_esky from setuptools import setupimport distutils # Dependencies are automatically detected, but it might need fine tuning. VER = '1.16.1102.1'# Common settings exeICON = 'et.ico' NAME = "eTaxMain.exe" FREEZER ='cx_freeze' ESKY_VERSION ={ "version": VER, "company": u"****公司", "description": u"****程序", "product": u"****系統", 'copyright':u"***@版權所有 2016-2020" } #版本申明部分 metadata= distutils.dist.DistributionMetadata() metadata.version = ESKY_VERSION['version'] metadata.description = ESKY_VERSION['description'] metadata.copyright = ESKY_VERSION['copyright'] metadata.name = ESKY_VERSION['product'] #版本申明結束 FREEZER_OPTIONS = { "packages": ["os","wx","requests","lxml","lxml.etree"], #包含package "includes": ["PIL","traceback",'HTMLParser'], #這里可以包含一些自定義包。 "excludes": ['MSVCP90.dll', 'mswsock.dll', 'powrprof.dll', 'USP10.dll', '_gtkagg', '_tkagg', 'bsddb', 'curses', 'pywin.debugger','pywin.debugger.dbgcon', 'pywin.dialogs','tcl', 'Tkconstants', 'Tkinter', 'wx.tools.*','wx.py.*', "collections.sys",'collections._weakref'], #剔除wx里tkinter包 "metadata":metadata }; APP = [bdist_esky.Executable("eT.py", gui_only=True, icon=exeICON, )] #打包et.ico,helpinfo.txt放到應用目錄下
#打包.\lang\zh_CN\LC_MESSAGES\eT.mo到lang\zh_CN下。 DATA_FILES=[('', ['et.ico','helpinfo.txt']), ('lang\zh_CN', ['.\lang\zh_CN\LC_MESSAGES\eT.mo','.\lang\zh_CN\LC_MESSAGES\eT.po']) ] ESKY_OPTIONS = dict( freezer_module = FREEZER, freezer_options = FREEZER_OPTIONS, enable_appdata_dir = True, bundle_msvcrt = False, ) # Build the app and the esky bundle setup( name = NAME, version = VER, scripts = APP, data_files = DATA_FILES, options = dict(bdist_esky=ESKY_OPTIONS), )
前前后后,為了這個esky,折騰了快2個禮拜,總算圓滿成功,寫的比較簡單,感興趣的留言交流。
