Now would be a good time to pull our changes :-) #18

wants to merge 85 commits into from

7 participants


Here's what this branch does:

  • Removed dangling pointer with NSTimer
  • appcast entries with a "new version" but without a download (paid updates, update notification for users of dropped HW)
  • MacBook Air & Mac pro machine names
  • auto-size update alert & buttons
  • Borderless, fixed-size web view if desired.
  • Cope with screwed-up Application Support permissions
  • XIBs instead of NIBs
  • delegate method before/after alerts
  • localizations (XIBs only) - when in doubt I chose our localizations, since we pay professional localizers.
  • symbolic constants for machine types
  • Version number parsing that can cope with build numbers in brackets at the end
  • No more framework-style includes for people who want to compile in app instead of using the framework (easier debugging, no surprises if some other app installs Sparkle in /Library)
  • download on desktop/in trash on failure
  • installation now happens in the finish_installation tool (formerly relaunch) so we don't perform surgery on the app's open heart
  • More use of fileSystemRepresentation when dealing with C-string paths
  • misc fixes to authorized copying code.
  • mdimport no longer runs async
  • download's version, not host version in update alert
  • SULog for an easier post-mortem if an installation fails.
  • Reset the application package to the real name when installing. So users don't have an icon labeled MyApp 1.0 that is actually 3.0 (ifdef-controlled).
  • Don't have update notification float on top unless we are a faceless app (so users can set aside the window and get back to it).
  • More performSelectorOnMainThread: where needed to avoid threading-related crashes.
  • Permit automated downgrades (ifdef-controlled - we have a URL scheme that offers to downgrade, good for support to hand out)
  • Customization of how version numbers are displayed to the user.
  • Fix a possible crasher where a button wasn't disabled in some circumstances and could be clicked a second time.
  • ifdef to allow installing non-signed updates.

You can probably ignore all the ThreadSafePreferences stuff. Also, we do not use the stuff for transmitting system information in EyeTV, nor the RSA and delta stuff, so I recommend you have an eye on anything that may affect those, and run whatever test cases you have for these. We also localize using a database-based tool, so we don't use the .strings files. So when in doubt, choose our localized XIBs over the strings files.

This code (before the merge) has been in use for years with lots of users on our end, so is rock-solid. However, I may have caused the odd regression by merging. Feel free to ask if you have questions, here, on Twitter, or via e-mail.

uliwitness and others added some commits Dec 4, 2009
@uliwitness uliwitness WIP turning the relaunch tool into a finish_installation tool. a11578a
@uliwitness uliwitness - More WIP creating finish_installation that waits
for quit, updates and relaunches the app, so
updates don't happen while app is still running.
NSBundle gets royally confused and points to the
old path (loading new NIBs into the old app in the
worst case) when you move a running app.
- Temp folder is now user's desktop, as
NSTemporaryDirectory() doesn't stay the same
between two separate apps, and may be emptied on quit.
- Relaunch gets created in App Support now, for
same reasons as above.
- Less dependency on prefix headers, that only leads
to lazy, un-reusable code.
@uliwitness uliwitness Merge of changes from SVN repository:
- Changed NTSynchronousTask to also give the status return value and direct stderror output to the outputData.
- Changed includes so this builds as part of an app, too, not just as a framework
- Made sure SUAppcast's dealloc releases some leaked ivars.
- Added infoURL, extracted from link, that can point to a "more Info" page for download-less URLs
- Added support for version attribute on item so we can support update notifications that don't include an enclosure (e.g. paid upgrades, or upgrades that would require a system update)
- Added/improved a few description methods to ease debugging.
- Added SULog so one can ask for a special log with additional information when there are update issues.
- Added mayUpdateAndRestart for apps that absolutely, positively can't restart right now (e.g. cuz they're burning a CD and would produce a coaster).
- Added updaterWillRelaunchApplication delegate method, analogous to the notification. Useful to have app delegate quit helper apps during installation.
- Made SUBasicUpdateDriver's abortUpdate implicitly retain/autorelease the update driver, because the notification center otherwise releases it and it goes away, causing crashes in superclass's abortUpdate.
- Merge of SUKeepDownloadOnFailedInstallKey and SUFixedHTMLDisplaySizeKey.
- Avoid a few warnings about missing prototypes
- Be paranoid, hdiutil can verify the download again, so let it. Better for internal apps where we turn off DSA checks, too.
- SUHost has an -installationPath now, independent from the bundlePath, so one can normalize the app name from "MyApp 1.1b4" back to "MyApp" Users assume the file name contains the correct version number when there is one in it. Saves support a few round-trips each time.
- Be better at threading: Try calling non-thread-safe methods on main thread only, and don't assume delegates know when they need to be thread-safe, call them on main thread where possible.
- Added a method to put the old copy of the app in the trash. 1.5git changed in this spot, so I didn't actually merge the code that uses it back in yet.
- Fix version comparison so it doesn't get confused by bracketed build numbers in version strings
- Make sure cancel button is disabled during extraction, otherwise user would crash.
- Don't put auto-update window at floating window level. It's huge and can't be switched to background! If you're an NSBGOnly where you need that, turn it on only in that case, but don't generally do such nonsense.
- Hide release notes view if there aren't any.
- Test whether we are on dial-up before checking for updates in background. It's not nice to cause (possibly expensive) dial-up periodically.
- Temporarily comment out DSA complaints for easier testing.
- Don't store (possibly already invalidated) one-shot NSTimers in an ivar. It's bad style. Retain it instead.
- Decompress some monster expressions with nested method calls in ternary operators and nested in method calls again.
- Don't use implicit "id" for params or return types.
- finish_installation now puts up a progress window, so user knows update is still not finished.
- Use ThreadSafePreferences (included dummy version that uses regular prefs for projects that don't use ThreadSafePreferences).

- Todo later: Change finish_installation to be prettier.
@uliwitness uliwitness Shut up undeclared selector warning. c51bf73
@uliwitness uliwitness Bring window to front when progress panel changes to "Install and res…
…tart", it's essentially a new alert coming up.
@uliwitness uliwitness Use installPath, not bundlePath here. 8c67631
@uliwitness uliwitness Added preprocessor defines to SUConstants.h for turning on/off DSA an…
…d downgrades. We let users downgrade using our URL scheme, and we warn them beforehand, so the downgrade possible attack paranoia gets in the way.
@uliwitness uliwitness target is an ObjC object, so nil, not NULL. 27e8714
@uliwitness uliwitness Maybe that makes the progress bar animate? No, it doesn't. 983ad61
@uliwitness uliwitness Partial Elgato string merges. 2ad144c
@uliwitness uliwitness - finish_installation is now a real bundled app, so it can be localized.
- It contains its own copy of Sparkle.strings and SUUpdateStatus.nib so it can show its progress prettier
- We call TransformProcessType() before our first call to [NSApplication sharedApplication], so we can be launched as a command line tool and get a proper window server connection, and so our progress bars animate.
- We still support the old "relaunch"-style mode of operation, just by not passing the folder to install. This is useful for other relaunch occasions, like setting one's own dock icon flag.

- To do: Make sample app use the new finish_installation.
@uliwitness uliwitness Commented preprocessor switches. Added a named switch for normalizing…
… an app name (it was just a #if 1 before).
@uliwitness uliwitness Build for more than just current architecture. We only build 32-bit b…
…ecause otherwise we'll get errors against 10.4 SDK (where 64-bit AppKit is not yet supported).
@uliwitness uliwitness Updated localizations. e4eccce
@uliwitness uliwitness Don't insist on having a file to replace. When we normalize the name,…
… we may not have one.
@uliwitness uliwitness We should now correctly replace renamed apps, trashing the custom-nam…
…ed one, installing a new one with a default name, and also moving out of the way any existing copy with the default name.
@uliwitness uliwitness Changed a few NSLogs() to SULogs(). 4f8d745
@uliwitness uliwitness We now really put the old app in the trash (and any file we have to m…
…ove out of the way to install a new app when we reset an edited name), even on non-admin user accounts. +++ TODO: Work around double authorization.
@uliwitness uliwitness Adjust the width of the status window so all localizations fit. 7686c86
@uliwitness uliwitness One more SULog() replacing an NSLog(). 2e0c1b0
Uli Kusterer Shutting up warnings due to missing includes and fix indentation on o…
…ne line.
Uli Kusterer Delegate can now control how version numbers are formatted/displayed …
…to the user, so we can e.g. exclude build numbers or whatever makes sense for a particular application.
Uli Kusterer Set floating window level on the update alert again, but only for bg-…
…only apps. Don't want to annoy users by having an always-visible panel.
Uli Kusterer Danish localization updates. d2f843f
@jollyjinx jollyjinx added Prefix header to finish_installation_tool
added SystemConfiguration.framework to Sparkle
added SUWindowController.m to finish_installation_tool
added SUStatusController.m to finish_installation_tool

now compiles Sparkle. Now going to fix the testbuild
@jollyjinx jollyjinx commented unused boxView code. c634f61
@jollyjinx jollyjinx fixed Version Comparision , added more testcases 65e836c
@jollyjinx jollyjinx removed cmdline installation tool and copied installation app to Spar…
…kle framework.
Uli Kusterer Merge remote branch 'andymatuschak/master' 590122f
@jollyjinx jollyjinx Intermediate Update directory name contains the version number of the…
… downloaded version
Uli Kusterer Tests for version numbers with build numbers. 64ec0c3
@jollyjinx jollyjinx Updating an application now longer shows the installation application…
… n the Dock (LSUIElement) , Removed TransformProcessType call as it will force the installer application to show in the Dock.
@jollyjinx jollyjinx Merge remote branch 'uliwitness/master' d3fac14
@uliwitness uliwitness Remove 10.4 SDK setting. Causes more problems than it helps. bc3fd45
@jollyjinx jollyjinx Merge remote branch 'uliwitness/master' f555e11
@uliwitness uliwitness Make sure we delete the temporary folder when the user cancels the do…
…wnload. Also make sure we delete it on 10.4, which seems to have a bug in removeFileAtPath: that won't delete nested empty folders. As a quick fix, I just trash the folder in that case. We already put the old version in the trash anyway, and this saves me from having to write, test and debug a recursive removal function.
@uliwitness uliwitness Be paranoid and wait for the mdimport to finish before we launch the …
…app. Might make spurious "no executable" errors a bit less likely.
@jollyjinx jollyjinx changed back 10.4 settings cause it broke the updater on 10.4 ad4e9c7
@jollyjinx jollyjinx updated the installer program to show an icon when the installation t…
…akes more than 1.2 seconds,

long installations have a program in the Dock
short installations just look like the program is restarting
some variable renaming to no longer have camelCasePath for char *
@uliwitness uliwitness Move 10.4 SDK setting into xcconfig file. 27f2b9c
@uliwitness uliwitness Fix authorized file moving code:
- We now correctly handle the case where the containing directory doesn't allow us adding files without authorization (e.g. /Applications).
- We do the quarantine release *before* the copy.
@uliwitness uliwitness Make sure mdimport is run synchronously, not asynchronously. 4d70069
@uliwitness uliwitness Fix typo in LONG_INSTALLATION_TIME constant. 5ec4c74
@uliwitness uliwitness Make sure we delete the temp directory. 0e609cc
@uliwitness uliwitness Make sure we delete the temp directory. 1b02ab5
@uliwitness uliwitness Make sure we also delete the temp dir when the user clicks "cancel" d…
…uring the download.
@uliwitness uliwitness More correct way of turning a C-string path into an NSString. 4c765d8
@uliwitness uliwitness Method for removing a file with optional authorization. cd93eb9
@uliwitness uliwitness More more correct way of creating an NSString from a C-string path. 2e8fa61
@uliwitness uliwitness Slightly more user-suitable error message. 9b11692
@uliwitness uliwitness Make sure that, even on 10.4, we delete our temp folder. Also, we no …
…longer use the stop-gap measure of trashing the temp folder, we really delete it after successful installation.
@uliwitness uliwitness Merge branch 'master' of a17f974
@uliwitness uliwitness Fix configuration for target:
Otherwise it won't build correctly on 10.4 and gives us "unsupported required load command" errors instead of starting up.
@uliwitness uliwitness If we install under a normalized name, make sure we take owner/group …
…from the target directory, not from a nonexistent destination application we haven't installed yet.
@uliwitness uliwitness Add missing include. 50b76d5
@uliwitness uliwitness More detailed error handling and logging.
- Take failure of stat into account
- Use correct format for printing uids
- SULog actual failure points.
- Cope with nonexistent destinations
@uliwitness uliwitness Revert Patrick's version number change.
- It made bracketed build numbers look like components of the version, which gave wrong results
- Added a test for one such broken build-numbered version number

TODO: Tests currently fail for Patrick's version numbers. Will have to write a smarter parser, or split this into two version comparator classes.
@uliwitness uliwitness Actually use the build configurations. 65f8d26
@uliwitness uliwitness Strings changes from Elgato. 8f0d7d0
@uliwitness uliwitness More strings changes from Elgato. 874572f
@uliwitness uliwitness Merge branch 'master' of 3d352c6
@uliwitness uliwitness Use symbolic constants, that's what they're for ;-) b4210d8
@uliwitness uliwitness That checkbox was way too narrow. 2903519
@uliwitness uliwitness Restore support for enclosure-less appcast items. If they have a spar…
…ke:version tag at the same level as the enclosure would be (as opposed to as an attribute on the enclosure), and no enclosure, but a "link" tag, the link tag's contents will be used as the URL for a "More Info" button to replace the "install" button.

Use this for paid updates, where you want to redirect users to your store page instead of installing an update they don't have a license key for.
@uliwitness uliwitness SUUpdateAlert.nib: Made sure all installButton outlets are hooked up.…
… Converted from NIB to XIB.
@uliwitness uliwitness SUUpdateAlert.xib: Shut up warnings about offscreen windows and clipp…
…ed content.
@uliwitness uliwitness Move ThreadSafePreferences.h dummy compatibility header to a differen…
…t spot in Groups & Files.
@uliwitness uliwitness Added two MacBook Air models. 7bfec0f
@uliwitness uliwitness Newest Elgato localizations. 990dee6
@uliwitness uliwitness Sparkle now warns the delegate before and after it brings up a modal …
…panel. One can e.g. use this to unfloat floating windows that would otherwise cover the alerts.
@uliwitness uliwitness All XIBs, all the time. 3db00fa
@uliwitness uliwitness The buttons in the update alert now auto-resize. Since we change the …
…button width when we show "Learn More..." for no-download updates (e.g. paid updates or updates that may no longer run on the user's Mac), this simplifies localization a lot.

The requisite NIB changes have been checked in previously with the newest localizations.
@uliwitness uliwitness Make Sparkle more robust when the permissions of ~/Library/Applicatio…
…n Support/EyeTV are screwed up. We now authenticate if needed, when we copy the finish_installation tool.
@uliwitness uliwitness Make sure the update alert is *really* not resizable. 5b90432
@uliwitness uliwitness Add a dummy line to make sure that the binary is linked against WebKi…
…t when Sparkle is used. The SUUpdateAlert.xib file contains a WebView and if we don't link against WebKit, we will get a runtime crash when decoding the NIB. It is better to get a link error.
@uliwitness uliwitness Merge andymatuschak/Sparkle. 9937e5a
@uliwitness uliwitness Manually merge project file (recreating the finish_installation appli…
…cation target) and make things build and run again.
@uliwitness uliwitness Added two new Mac Pro models. fdaf26e
@uliwitness uliwitness Add strings file to the finish_installation tool. Apparently also rem…
…ove a leftover NIB, though I don't remember actually doing that.

Thanks so much for doing this, Uli.

I'll try to get this handled tomorrow night.


I really don't want to put these downloads on the desktop. Let's put them in the application support folder instead.

We should be finding these paths with NSSearchPathForDirectoriesInDomains.

Hm. But then even in the common case (update success), a user with an empty desktop sees something appear there for a while.

How about ~/Downloads (creating it if necessary for 10.4 folks)?


We should be finding these paths with NSSearchPathForDirectoriesInDomains.


I'd like to inline these #defines with #ifndefs, so the Elgato branch can still override them, but I don't think we should have references to EYETV and TOAST in the master Sparkle branch.


!!! I'm assuming this is removed in a later patch.

Yep, fixed in d0b802e.

Ah. You're right, it has the define.


Ah, this is addressed in 5a5b171.


Need to handle the case of LSUIElement sorts of apps.

Handled in e9c6967.


This doesn't seem to be used anywhere.


To be removed.


To be removed.


To be removed.


Will need to review the localization changes; as I recall the buttons are all made the size of the greatest button size.


… "the standard version displayer" …

Ooops. Good catch. :-)


I love the dynamic presentation here: short is invisible; long shows status. We do this all over the place in UIKit, and I think it's a great behavior.

It was a fight between Patrick and me whether we should show it or not. I think this was his idea.


I've reviewed most of this tonight. Didn't quite meet my goal of finishing the merge tonight, but not too much left to do. Only a couple small changes required, and only a small portion left the review. Localizations may need a fair amount of work to merge gracefully.

Uli, if you're coming to WWDC, you aren't allowed to pay for drinks as long as I'm nearby.


Ah, this should make the "lolz hueg boottun" localization issues go away. Excellent.


Unfortunately, this means that the user could potentially get several authentication dialogs. But that would take a great deal of work to correct, and this case should be rare.


Hah! I did not realize that. Fantastic.


Thank you so much for doing this legwork, Uli.


I've reviewed these changes. Now, a few small modifications and testing. I won't have time tonight, but I'll do my best to land this ASAP.


Merged with a number of modifications at

I'm asking for some community QA before I pull from there into master.



So... is this stuff pretty stable? Any idea?


I don't know if anyone's living on it. I have a suite of tests (not automated, sadly) I want to perform on it, but I'm too busy trying to get iOS 5 out the door now. :/


I've made a few more changes in my branch here:

I fixed some build issues and deprecation warnings I ran into. The last commit changes the base SDK to 10.6 since I target Intel only, but isn't necessary.


I have been testing this branch. A couple issues discovered so far I'll need to address:
– is displaying its UI unconditionally (i.e. without the hysteresis that makes it only display if the installation takes more than 1.2s)
– restarts the host app, even if it is performing an "Install on Quit" (i.e. install only, no restart)


time to accept the pull request, andy.


Why the resource removal?


I have landed this at last in 05861e5. Thank you for your patience and contributions, all.


Uli, can you take a look at line 364 and 365 above and let me know if my reasoning for why this should be changed rings true for you? It looks like the case this is handling is where the target file does not yet exist, so for example if we are trying to copy into /Applications/

The test then for write access is confirming write access for both:




It strikes me that in the case where there is no file already there, it should ONLY need to test for write access to the container folder for the file to be created. I suspect the redundant check on the second-level parent is a vestige of copying/modeling on the code that handles the case where the file exists and thus permission for both the file and the containing folder needs to be tested.

The downside to the code as it stands in this commit is if the user DOES have access to the container folder, but DOES NOT have access to the second-level container, Sparkle will erroneously prompt for admin privileges to complete the installation.


@alexrinass alexrinass pushed a commit to fournova/Sparkle that referenced this pull request Jun 12, 2014
@pornel pornel Removed unused notifications
Fixes #18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment