Permalink
Browse files

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.
  • Loading branch information...
uliwitness committed Dec 4, 2009
1 parent bbcfe7e commit 43a0a7db4f806985df073c899da783eacab75e73
Showing with 1,985 additions and 397 deletions.
  1. +15 −0 Elgato/ThreadSafePreferences.h
  2. +1 −1 NTSynchronousTask.h
  3. +18 −8 NTSynchronousTask.m
  4. +19 −1 SUAppcast.m
  5. +4 −0 SUAppcastItem.h
  6. +29 −3 SUAppcastItem.m
  7. +1 −1 SUAutomaticUpdateAlert.m
  8. +1 −0 SUAutomaticUpdateDriver.m
  9. +49 −31 SUBasicUpdateDriver.m
  10. +20 −0 SUConstants.h
  11. +7 −1 SUConstants.m
  12. +2 −0 SUDSAVerifier.h
  13. +6 −0 SUDSAVerifier.m
  14. +17 −3 SUDiskImageUnarchiver.m
  15. +5 −1 SUHost.h
  16. +20 −8 SUHost.m
  17. +2 −0 SUInstaller.h
  18. +37 −9 SUInstaller.m
  19. +31 −0 SULog.h
  20. +80 −0 SULog.m
  21. +5 −1 SUPackageInstaller.h
  22. +1 −0 SUPackageInstaller.m
  23. +15 −1 SUPipedUnarchiver.m
  24. +6 −1 SUPlainInstaller.h
  25. +6 −0 SUPlainInstaller.m
  26. +99 −37 SUPlainInstallerInternals.m
  27. +5 −1 SUScheduledUpdateDriver.m
  28. +12 −4 SUStandardVersionComparator.m
  29. +56 −0 SUStatus.nib/classes.nib
  30. +20 −0 SUStatus.nib/info.nib
  31. +12 −3 SUStatusController.m
  32. +2 −0 SUSystemProfiler.h
  33. +3 −1 SUUIBasedUpdateDriver.h
  34. +16 −2 SUUIBasedUpdateDriver.m
  35. +5 −1 SUUnarchiver.m
  36. +4 −1 SUUpdateAlert.h
  37. +79 −9 SUUpdateAlert.m
  38. +2 −1 SUUpdateDriver.m
  39. +1 −0 SUUpdatePermissionPrompt.m
  40. +21 −5 SUUpdater.h
  41. +94 −14 SUUpdater.m
  42. +3 −1 SUVersionComparisonProtocol.h
  43. +0 −245 Sparkle.xcodeproj/default.pbxuser
  44. +19 −0 Sparkle.xcodeproj/project.pbxproj
  45. +43 −0 Test Application/English.lproj/MainMenu.nib/classes.nib
  46. +21 −0 Test Application/English.lproj/MainMenu.nib/info.nib
  47. +29 −0 da.lproj/SUAutomaticUpdateAlert.nib/classes.nib
  48. +18 −0 da.lproj/SUAutomaticUpdateAlert.nib/info.nib
  49. BIN da.lproj/SUAutomaticUpdateAlert.strings
  50. +40 −0 da.lproj/SUUpdateAlert.nib/classes.nib
  51. +22 −0 da.lproj/SUUpdateAlert.nib/info.nib
  52. BIN da.lproj/SUUpdateAlert.nib/keyedobjects.nib
  53. BIN da.lproj/SUUpdateAlert.strings
  54. +34 −0 da.lproj/SUUpdatePermissionPrompt.nib/classes.nib
  55. +10 −0 da.lproj/SUUpdatePermissionPrompt.nib/data.dependency
  56. +16 −0 da.lproj/SUUpdatePermissionPrompt.nib/info.nib
  57. BIN da.lproj/SUUpdatePermissionPrompt.nib/keyedobjects.nib
  58. BIN da.lproj/Sparkle.strings
  59. BIN de.lproj/SUAutomaticUpdateAlert.strings
  60. BIN de.lproj/SUUpdateAlert.strings
  61. +59 −0 de.lproj/SUUpdatePermissionPrompt.nib/classes.nib
  62. +18 −0 de.lproj/SUUpdatePermissionPrompt.nib/info.nib
  63. BIN de.lproj/SUUpdatePermissionPrompt.strings
  64. BIN de.lproj/Sparkle.strings
  65. BIN en.lproj/SUUpdatePermissionPrompt.strings
  66. BIN es.lproj/SUAutomaticUpdateAlert.strings
  67. BIN es.lproj/SUUpdateAlert.strings
  68. +59 −0 es.lproj/SUUpdatePermissionPrompt.nib/classes.nib
  69. +18 −0 es.lproj/SUUpdatePermissionPrompt.nib/info.nib
  70. BIN es.lproj/SUUpdatePermissionPrompt.strings
  71. +24 −2 finish_installation.m
  72. +59 −0 fr.lproj/SUUpdatePermissionPrompt.nib/classes.nib
  73. +18 −0 fr.lproj/SUUpdatePermissionPrompt.nib/info.nib
  74. BIN fr.lproj/SUUpdatePermissionPrompt.strings
  75. BIN it.lproj/SUAutomaticUpdateAlert.strings
  76. BIN it.lproj/SUUpdateAlert.strings
  77. +59 −0 it.lproj/SUUpdatePermissionPrompt.nib/classes.nib
  78. +18 −0 it.lproj/SUUpdatePermissionPrompt.nib/info.nib
  79. BIN it.lproj/SUUpdatePermissionPrompt.strings
  80. BIN ja.lproj/SUUpdatePermissionPrompt.strings
  81. +59 −0 nl.lproj/SUUpdatePermissionPrompt.nib/classes.nib
  82. +16 −0 nl.lproj/SUUpdatePermissionPrompt.nib/info.nib
  83. +50 −0 pt.lproj/SUAutomaticUpdateAlert.nib/classes.nib
  84. +18 −0 pt.lproj/SUAutomaticUpdateAlert.nib/info.nib
  85. BIN pt.lproj/SUAutomaticUpdateAlert.nib/keyedobjects.nib
  86. +12 −0 pt.lproj/SUAutomaticUpdateAlert.strings
  87. +69 −0 pt.lproj/SUUpdateAlert.nib/classes.nib
  88. +18 −0 pt.lproj/SUUpdateAlert.nib/info.nib
  89. BIN pt.lproj/SUUpdateAlert.nib/keyedobjects.nib
  90. BIN pt.lproj/SUUpdateAlert.strings
  91. +59 −0 pt.lproj/SUUpdatePermissionPrompt.nib/classes.nib
  92. +18 −0 pt.lproj/SUUpdatePermissionPrompt.nib/info.nib
  93. BIN pt.lproj/SUUpdatePermissionPrompt.nib/keyedobjects.nib
  94. BIN pt.lproj/SUUpdatePermissionPrompt.strings
  95. +95 −0 pt.lproj/Sparkle.strings
  96. +59 −0 ru.lproj/SUUpdatePermissionPrompt.nib/classes.nib
  97. +18 −0 ru.lproj/SUUpdatePermissionPrompt.nib/info.nib
  98. +59 −0 sv.lproj/SUUpdatePermissionPrompt.nib/classes.nib
  99. +20 −0 sv.lproj/SUUpdatePermissionPrompt.nib/info.nib
  100. BIN zh_CN.lproj/SUUpdatePermissionPrompt.strings
@@ -0,0 +1,15 @@
+// Header that shouldn't be included in anything but the Sparkle finish_installation tool
+// because it includes files also used in EyeTV, but doesn't need to be thread safe
+// as it's a single-threaded process anyway.
+
+#if !EYETV && !__TOAST__ && !TURBO
+
+#define ThreadSafePreferences_CopyAppValue CFPreferencesCopyAppValue
+#define ThreadSafePreferences_SetValue CFPreferencesSetValue
+#define ThreadSafePreferences_Synchronize CFPreferencesSynchronize
+
+#else
+
+#error This header shouldn't be included here!
+
+#endif
View
@@ -22,7 +22,7 @@
// pass nil for directory if not needed
// returns the result
-+ (NSData*)task:(NSString*)toolPath directory:(NSString*)currentDirectory withArgs:(NSArray*)args input:(NSData*)input;
++(int) task:(NSString*)toolPath directory:(NSString*)currentDirectory withArgs:(NSArray*)args input:(NSData*)input output: (NSData**)outData;
@end
View
@@ -6,7 +6,11 @@
// Copyright 2005 Steve Gehrman. All rights reserved.
//
-#import "Sparkle.h"
+#import "SUUpdater.h"
+
+#import "SUAppcast.h"
+#import "SUAppcastItem.h"
+#import "SUVersionComparisonProtocol.h"
#import "NTSynchronousTask.h"
@interface NTSynchronousTask (Private)
@@ -44,6 +48,7 @@ - (id)init;
[[self task] setStandardInput:[self inputPipe]];
[[self task] setStandardOutput:[self outputPipe]];
+ [[self task] setStandardError:[self outputPipe]];
}
return self;
@@ -64,32 +69,37 @@ - (void)dealloc
[super dealloc];
}
-+ (NSData*)task:(NSString*)toolPath directory:(NSString*)currentDirectory withArgs:(NSArray*)args input:(NSData*)input;
++(int) task:(NSString*)toolPath directory:(NSString*)currentDirectory withArgs:(NSArray*)args input:(NSData*)input output: (NSData**)outData
{
// we need this wacky pool here, otherwise we run out of pipes, the pipes are internally autoreleased
- NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
- NSData* result=nil;
+ NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
+ int taskResult = 0;
+ if( outData )
+ *outData = nil;
NS_DURING
{
NTSynchronousTask* task = [[NTSynchronousTask alloc] init];
[task run:toolPath directory:currentDirectory withArgs:args input:input];
- if ([task result] == 0)
- result = [[task output] retain];
+ taskResult = [task result];
+ if( outData )
+ *outData = [[task output] retain];
[task release];
}
NS_HANDLER;
+ taskResult = errCppGeneral;
NS_ENDHANDLER;
[pool drain];
// retained above
- [result autorelease];
+ if( outData )
+ [*outData autorelease];
- return result;
+ return taskResult;
}
@end
View
@@ -6,8 +6,15 @@
// Copyright 2006 Andy Matuschak. All rights reserved.
//
-#import "Sparkle.h"
+#import "SUUpdater.h"
+
+#import "SUAppcast.h"
+#import "SUAppcastItem.h"
+#import "SUVersionComparisonProtocol.h"
#import "SUAppcast.h"
+#import "SUConstants.h"
+#import "SULog.h"
+
@interface SUAppcast (Private)
- (void)reportError:(NSError *)error;
@@ -19,7 +26,12 @@ @implementation SUAppcast
- (void)dealloc
{
[items release];
+ items = nil;
[userAgentString release];
+ userAgentString = nil;
+ [downloadFilename release];
+ downloadFilename = nil;
+
[super dealloc];
}
@@ -59,6 +71,12 @@ - (void)downloadDidFinish:(NSURLDownload *)download
BOOL failed = NO;
NSArray *xmlItems = nil;
NSMutableArray *appcastItems = [NSMutableArray array];
+
+ #if DEBUG
+ NSString* debugXML = [NSString stringWithContentsOfFile: downloadFilename encoding: NSUTF8StringEncoding error: nil];
+ SULog(@"<<<< XML >>>>\n%@\n>>>> XML <<<<", debugXML);
+ #endif
+
#if MAC_OS_X_VERSION_MIN_REQUIRED <= MAC_OS_X_VERSION_10_4
[[NSFileManager defaultManager] removeFileAtPath:downloadFilename handler:nil];
#else
View
@@ -24,6 +24,8 @@
NSString *displayVersionString;
NSDictionary *propertiesDictionary;
+
+ NSURL *infoURL; // UK 2007-08-31
}
// Initializes with data from a dictionary provided by the RSS class.
@@ -43,6 +45,8 @@
// Returns the dictionary provided in initWithDictionary; this might be useful later for extensions.
- (NSDictionary *)propertiesDictionary;
+- (NSURL *)infoURL; // UK 2007-08-31
+
@end
#endif
View
@@ -6,7 +6,11 @@
// Copyright 2006 Andy Matuschak. All rights reserved.
//
-#import "Sparkle.h"
+#import "SUUpdater.h"
+
+#import "SUAppcast.h"
+#import "SUAppcastItem.h"
+#import "SUVersionComparisonProtocol.h"
#import "SUAppcastItem.h"
@implementation SUAppcastItem
@@ -101,6 +105,16 @@ - (void)setMinimumSystemVersion:(NSString *)systemVersionString
minimumSystemVersion = [systemVersionString copy];
}
+
+- (NSURL *)infoURL { return [[infoURL retain] autorelease]; } // UK 2007-08-31 (whole method)
+
+- (void)setInfoURL:(NSURL *)aFileURL // UK 2007-08-31 (whole method)
+{
+ if( aFileURL == infoURL ) return;
+ [infoURL release];
+ infoURL = [aFileURL copy];
+}
+
- initWithDictionary:(NSDictionary *)dict
{
return [self initWithDictionary:dict failureReason:nil];
@@ -130,7 +144,9 @@ - (void)setMinimumSystemVersion:(NSString *)systemVersionString
// The big caveat with this is that you can't have underscores in your version strings, as that'll confuse Sparkle.
// Feel free to change the separator string to a hyphen or something more suited to your needs if you like.
NSString *newVersion = [enclosure objectForKey:@"sparkle:version"];
- if (newVersion == nil) // no sparkle:version attribute
+ if( newVersion == nil )
+ newVersion = [dict objectForKey:@"sparkle:version"]; // UK 2007-08-31 Get version from the item, in case it's a download-less item (i.e. paid upgrade).
+ if (newVersion == nil) // no sparkle:version attribute anywhere?
{
// Separate the url by underscores and take the last component, as that'll be closest to the end,
// then we remove the extension. Hopefully, this will be the version.
@@ -160,7 +176,16 @@ - (void)setMinimumSystemVersion:(NSString *)systemVersionString
[self setDate:[dict objectForKey:@"pubDate"]];
[self setItemDescription:[dict objectForKey:@"description"]];
- [self setFileURL:[NSURL URLWithString:[[enclosure objectForKey:@"url"] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]]];
+ NSString* theInfoURL = [dict objectForKey:@"link"];
+ if( theInfoURL )
+ {
+ if( ![theInfoURL isKindOfClass: [NSString class]] )
+ NSLog(@"SUAppcastItem -initWithDictionary: Info URL is not of valid type.");
+ else
+ [self setInfoURL:[NSURL URLWithString:theInfoURL]];
+ }
+
+ [self setFileURL:[NSURL URLWithString:[[enclosure objectForKey:@"url"] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]]];
[self setDSASignature:[enclosure objectForKey:@"sparkle:dsaSignature"]];
[self setVersionString:newVersion];
@@ -193,6 +218,7 @@ - (void)dealloc
[self setFileURL:nil];
[self setVersionString:nil];
[self setDisplayVersionString:nil];
+ [self setInfoURL:nil];
[propertiesDictionary release];
[super dealloc];
}
View
@@ -33,7 +33,7 @@ - (void)dealloc
[super dealloc];
}
-- (NSString *)description { return [NSString stringWithFormat:@"%@ <%@>", [self class], [host bundlePath]]; }
+- (NSString *)description { return [NSString stringWithFormat:@"%@ <%@, %@>", [self class], [host bundlePath], [host installationPath]]; }
- (IBAction)installNow:sender
{
@@ -10,6 +10,7 @@
#import "SUAutomaticUpdateAlert.h"
#import "SUHost.h"
+#import "SUConstants.h"
@implementation SUAutomaticUpdateDriver
View
@@ -13,6 +13,9 @@
#import "SUInstaller.h"
#import "SUStandardVersionComparator.h"
#import "SUUnarchiver.h"
+#import "SUConstants.h"
+#import "SULog.h"
+
@implementation SUBasicUpdateDriver
@@ -165,6 +168,7 @@ - (void)download:(NSURLDownload *)d decideDestinationWithSuggestedFilename:(NSSt
- (void)downloadDidFinish:(NSURLDownload *)d
{
+ #if 0 // +++
// New in Sparkle 1.5: we're now checking signatures on all non-secure downloads, where "secure" is defined as both the appcast and the download being transmitted over SSL.
NSURL *downloadURL = [[d request] URL];
if (!(([[downloadURL scheme] isEqualToString:@"https"] && [[appcastURL scheme] isEqualToString:@"https"]) ||
@@ -176,6 +180,7 @@ - (void)downloadDidFinish:(NSURLDownload *)d
return;
}
}
+ #endif
[self extractUpdate];
}
@@ -200,7 +205,7 @@ - (void)extractUpdate
SUUnarchiver *unarchiver = [SUUnarchiver unarchiverForPath:downloadPath];
if (!unarchiver)
{
- NSLog(@"Sparkle Error: No valid unarchiver for %@!", downloadPath);
+ SULog(@"Sparkle Error: No valid unarchiver for %@!", downloadPath);
[self unarchiverDidFail:nil];
return;
}
@@ -231,7 +236,11 @@ - (void)installUpdate
NSString *relaunchPathToCopy = [[NSBundle bundleForClass:[self class]] pathForResource:@"finish_installation" ofType:@""];
NSString *appSupportFolder = [[@"~/Library/Application Support/" stringByExpandingTildeInPath] stringByAppendingPathComponent: [host name]];
NSString *targetPath = [appSupportFolder stringByAppendingPathComponent:[relaunchPathToCopy lastPathComponent]];
- [[NSFileManager defaultManager] createDirectoryAtPath: targetPath withIntermediateDirectories: YES attributes: [NSDictionary dictionary] error: NULL];
+#if MAC_OS_X_VERSION_MIN_REQUIRED <= MAC_OS_X_VERSION_10_4
+ [[NSFileManager defaultManager] createDirectoryAtPath: [targetPath stringByDeletingLastPathComponent] attributes: [NSDictionary dictionary]];
+#else
+ [[NSFileManager defaultManager] createDirectoryAtPath: [targetPath stringByDeletingLastPathComponent] withIntermediateDirectories: YES attributes: [NSDictionary dictionary] error: NULL];
+#endif
// Only the paranoid survive: if there's already a stray copy of relaunch there, we would have problems.
NSError *error = nil;
@@ -251,36 +260,43 @@ - (void)installUpdate
- (void)installAndRelaunchWithTool
{
- // Give the host app an opportunity to postpone the relaunch.
- static BOOL postponedOnce = NO;
- if (!postponedOnce && [[updater delegate] respondsToSelector:@selector(updater:shouldPostponeRelaunchForUpdate:untilInvoking:)])
+ BOOL mayRelaunchAtAll = [updater mayUpdateAndRestart];
+
+ if( mayRelaunchAtAll )
{
- NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[[self class] instanceMethodSignatureForSelector:@selector(relaunchHostApp)]];
- [invocation setSelector:@selector(relaunchHostApp)];
- [invocation setTarget:self];
- postponedOnce = YES;
- if ([[updater delegate] updater:updater shouldPostponeRelaunchForUpdate:updateItem untilInvoking:invocation])
- return;
- }
-
- [[NSNotificationCenter defaultCenter] postNotificationName:SUUpdaterWillRestartNotification object:self];
- if ([[updater delegate] respondsToSelector:@selector(updaterWillRelaunchApplication:)])
- [[updater delegate] updaterWillRelaunchApplication:updater];
+ // Give the host app an opportunity to postpone the relaunch.
+ static BOOL postponedOnce = NO;
+ if (!postponedOnce && [[updater delegate] respondsToSelector:@selector(updater:shouldPostponeRelaunchForUpdate:untilInvoking:)])
+ {
+ NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[[self class] instanceMethodSignatureForSelector:@selector(relaunchHostApp)]];
+ [invocation setSelector:@selector(relaunchHostApp)];
+ [invocation setTarget:self];
+ postponedOnce = YES;
+ if ([[updater delegate] updater:updater shouldPostponeRelaunchForUpdate:updateItem untilInvoking:invocation])
+ return;
+ }
- if(!relaunchPath || ![[NSFileManager defaultManager] fileExistsAtPath:relaunchPath])
- {
- // Note that we explicitly use the host app's name here, since updating plugin for Mail relaunches Mail, not just the plugin.
- [self abortUpdateWithError:[NSError errorWithDomain:SUSparkleErrorDomain code:SURelaunchError userInfo:[NSDictionary dictionaryWithObjectsAndKeys:[NSString stringWithFormat:SULocalizedString(@"An error occurred while relaunching %1$@, but the new version will be available next time you run %1$@.", nil), [host name]], NSLocalizedDescriptionKey, [NSString stringWithFormat:@"Couldn't find the relauncher (expected to find it at %@)", relaunchPath], NSLocalizedFailureReasonErrorKey, nil]]];
- // We intentionally don't abandon the update here so that the host won't initiate another.
- return;
- }
+ [[NSNotificationCenter defaultCenter] postNotificationName:SUUpdaterWillRestartNotification object:self];
+ if ([[updater delegate] respondsToSelector:@selector(updaterWillRelaunchApplication:)])
+ [[updater delegate] updaterWillRelaunchApplication:updater];
- NSString *pathToRelaunch = [host bundlePath];
- if ([[updater delegate] respondsToSelector:@selector(pathToRelaunchForUpdater:)])
- pathToRelaunch = [[updater delegate] pathToRelaunchForUpdater:updater];
- [NSTask launchedTaskWithLaunchPath:relaunchPath arguments:[NSArray arrayWithObjects:pathToRelaunch, [NSString stringWithFormat:@"%d", [[NSProcessInfo processInfo] processIdentifier]], [downloadPath stringByDeletingLastPathComponent], nil]];
-
- [NSApp terminate:self];
+ if(!relaunchPath || ![[NSFileManager defaultManager] fileExistsAtPath:relaunchPath])
+ {
+ // Note that we explicitly use the host app's name here, since updating plugin for Mail relaunches Mail, not just the plugin.
+ [self abortUpdateWithError:[NSError errorWithDomain:SUSparkleErrorDomain code:SURelaunchError userInfo:[NSDictionary dictionaryWithObjectsAndKeys:[NSString stringWithFormat:SULocalizedString(@"An error occurred while relaunching %1$@, but the new version will be available next time you run %1$@.", nil), [host name]], NSLocalizedDescriptionKey, [NSString stringWithFormat:@"Couldn't find the relauncher (expected to find it at %@)", relaunchPath], NSLocalizedFailureReasonErrorKey, nil]]];
+ // We intentionally don't abandon the update here so that the host won't initiate another.
+ return;
+ }
+
+ NSString *pathToRelaunch = [host bundlePath];
+ if ([[updater delegate] respondsToSelector:@selector(pathToRelaunchForUpdater:)])
+ pathToRelaunch = [[updater delegate] pathToRelaunchForUpdater:updater];
+ [NSTask launchedTaskWithLaunchPath:relaunchPath arguments:[NSArray arrayWithObjects:pathToRelaunch, [NSString stringWithFormat:@"%d", [[NSProcessInfo processInfo] processIdentifier]], [downloadPath stringByDeletingLastPathComponent], nil]];
+
+ [NSApp terminate:self];
+ }
+ else
+ [self abortUpdate];
}
- (void)cleanUp
@@ -295,21 +311,23 @@ - (void)cleanUp
- (void)installerForHost:(SUHost *)aHost failedWithError:(NSError *)error
{
if (aHost != host) { return; }
+ [[NSFileManager defaultManager] removeFileAtPath:relaunchPath handler:NULL]; // Clean up the copied relauncher.
[self abortUpdateWithError:[NSError errorWithDomain:SUSparkleErrorDomain code:SUInstallationError userInfo:[NSDictionary dictionaryWithObjectsAndKeys:SULocalizedString(@"An error occurred while installing the update. Please try again later.", nil), NSLocalizedDescriptionKey, [error localizedDescription], NSLocalizedFailureReasonErrorKey, nil]]];
}
- (void)abortUpdate
{
+ [[self retain] autorelease]; // In case the notification center was the last one holding on to us.
[[NSNotificationCenter defaultCenter] removeObserver:self];
[super abortUpdate];
}
- (void)abortUpdateWithError:(NSError *)error
{
if ([error code] != SUNoUpdateError) // Let's not bother logging this.
- NSLog(@"Sparkle Error: %@", [error localizedDescription]);
+ SULog(@"Sparkle Error: %@", [error localizedDescription]);
if ([error localizedFailureReason])
- NSLog(@"Sparkle Error (continued): %@", [error localizedFailureReason]);
+ SULog(@"Sparkle Error (continued): %@", [error localizedFailureReason]);
if (download)
[download cancel];
[self abortUpdate];
Oops, something went wrong.

0 comments on commit 43a0a7d

Please sign in to comment.