views:

862

answers:

3

I maintain a cross platform application, based on PyQt that runs on linux mac and windows.

The windows and mac versions are distributed using py2exe and py2app, which produces quite large bundles (~40 MB).

I would like to add an "auto update" functionality, based on patches to limit downloads size:

  • check for new versions on an http server
  • download the patches needed to update to the last version
  • apply the patches list and restart the application

I have some questions:

  • what is the preferred way to update a windows application since open files are locked and can't be overwritten ?
  • how do I prepare and apply the patches ? perhaps using bsdiff/pspatch ?

[update]

I made a simple class to make patches with bsdiff, which is very efficient as advertised on their site : a diff on two py2exe versions of my app (~75 MB uncompressed) produces a 44 kB patch ! Small enough for me, I will stick to this format.

The code is available in the 'update' package of pyflu, a small library of Python code.

+3  A: 

I don't know about patches, but on OS X the "standard" for this with cocoa apps is Sparkle. Basically it does "appcasting". It downloads the full app each time. It might be worth looking at it for inspiration.

I imagine on OS X you can probably just download the actual part of your app bundle that contains your specific code (not the libs etc that get packaged in) and that'd be fairly small and easy to replace in the bundle.

On Windows, you'd probably be able to do a similar trick by not bundling your app into one exe - thus letting you change the one file that has actually changed.

I'd imagine your actual Python code would be much less than 40Mb, so that's probably the way to go.

As for replacing the running app, well first you need to find it's location, so you could use sys.executable to get you a starting point, then you could probably fork a child process to, kill the parent process and have the child doing the actual replacement?

I'm currently playing around with a small wxPython app and wondering about exactly this problem. I'd love to hear about what you come up with.

Also how big is you app when compressed? If it compresses well then maybe you can still afford to send the whole thing.

John Montgomery
The app is 40 MB *compressed* :) It's all the DLLs and python runtime that takes the most part of it, my code is only 500 KB.
Luper Rouch
+2  A: 

I don't believe py2exe supports patched updates. However, if you do not bundle the entire package into a single EXE (py2exe website example - bottom of page), you can get away with smaller updates by just replacing certain files, like the EXE file, for example. This can reduce the size of your updates significantly.

You can write a separate updater app, which can be downloaded/ran from inside your application. This app may be different for every update, as the files that need to be updated may change.

Once the application launches the updater, it will need to close itself so the files can be overwritten. Once the updater is complete, you can have it reopen the application before closing itself.

jcoon
Out of pure curiosity, why would a python executable, or any other executable for that matter, not support binary patching? Isn't a binary patch just NewVersion.exe minus OldVersion.exe, with the patch changing the bytes necessary to make it NewVersion.exe?
ryeguy
+1  A: 

Since py2exe puts all of the compiled modules of your app into a ZIP file, you could try to update this file by creating a script that updates it from a given set of files. Then replace the remaining files that have changed (which should be few, if any).

Ber
Sometimes you also want to update the DLLs (e.g. when changing Qt version, adding new extension modules dependencies, etc...), I don't want to check manually if everything works each time I make a release.
Luper Rouch