14

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.

Luper Rouch
  • 9,304
  • 7
  • 42
  • 56
  • Out of interest how do you plan to deal with updates that span multiple versions/updates. e.g. a user has 1.0, then by the time they next try running it there have been (say) 10 updates? Would you generate the patches on demand? With caching I guess it wouldn't be too bad, but assumes you have some server-side code available... – John Montgomery Apr 29 '09 at 14:48
  • 1
    If the user missed 10 updates the updater will download the 10 patches needed to get to the latest version and apply them one by one. There is no server side code, just a simple apache server showing directories content. – Luper Rouch Apr 29 '09 at 18:08

5 Answers5

5

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.

Jason Coon
  • 17,601
  • 10
  • 42
  • 50
  • 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 Apr 17 '09 at 14:25
3

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
  • 8,868
  • 4
  • 33
  • 43
  • 1
    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 Apr 17 '09 at 14:24
2

This is 4 years old now, but what about Esky?

Chelonian
  • 549
  • 2
  • 5
  • 21
1

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
  • 40,356
  • 16
  • 72
  • 88
  • 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 Apr 17 '09 at 16:04
0

An old post, but I thought I'd mention pyupdater with pyinstaller.

It supports Amazon and scp.

In the future, according to recent github posts, they plan to support free alternatives.