Skip to content

Commit

Permalink
The finish_installation tool will not relaunch the host app if it's u…
Browse files Browse the repository at this point in the history
…sing the "Install on Quit" functionality.
  • Loading branch information
andymatuschak committed Sep 29, 2011
1 parent e71915b commit c96aa2e
Show file tree
Hide file tree
Showing 5 changed files with 78 additions and 76 deletions.
8 changes: 4 additions & 4 deletions SUAutomaticUpdateDriver.m
Expand Up @@ -44,7 +44,7 @@ - (void)automaticUpdateAlert:(SUAutomaticUpdateAlert *)aua finishedWithChoice:(S
switch (choice)
{
case SUInstallNowChoice:
[self installUpdate];
[self installWithToolAndRelaunch:YES];
break;

case SUInstallLaterChoice:
Expand All @@ -61,15 +61,15 @@ - (void)automaticUpdateAlert:(SUAutomaticUpdateAlert *)aua finishedWithChoice:(S

- (BOOL)shouldInstallSynchronously { return postponingInstallation; }

- (void)installUpdate
- (void)installWithToolAndRelaunch:(BOOL)relaunch
{
showErrors = YES;
[super installUpdate];
[super installWithToolAndRelaunch:relaunch];
}

- (void)applicationWillTerminate:(NSNotification *)note
{
[self installUpdate];
[self installWithToolAndRelaunch:NO];
}

- (void)abortUpdateWithError:(NSError *)error
Expand Down
4 changes: 2 additions & 2 deletions SUBasicUpdateDriver.h
Expand Up @@ -46,10 +46,10 @@
- (void)unarchiverDidFail:(SUUnarchiver *)ua;
- (void)failedToApplyDeltaUpdate;

- (void)installUpdate;
- (void)installWithToolAndRelaunch:(BOOL)relaunch;
- (void)installerForHost:(SUHost *)host failedWithError:(NSError *)error;

- (void)installAndRelaunchWithTool;
- (void)installWithToolAndRelaunch:(BOOL)relaunch;
- (void)cleanUpDownload;

- (void)abortUpdate;
Expand Down
84 changes: 40 additions & 44 deletions SUBasicUpdateDriver.m
Expand Up @@ -237,7 +237,7 @@ - (void)failedToApplyDeltaUpdate
- (void)unarchiverDidFinish:(SUUnarchiver *)ua
{
if (ua) { CFRelease(ua); }
[self installUpdate];
[self installWithToolAndRelaunch:YES];
}

- (void)unarchiverDidFail:(SUUnarchiver *)ua
Expand All @@ -254,8 +254,28 @@ - (void)unarchiverDidFail:(SUUnarchiver *)ua

- (BOOL)shouldInstallSynchronously { return NO; }

- (void)installUpdate
- (void)installWithToolAndRelaunch:(BOOL)relaunch
{
if (![updater mayUpdateAndRestart])
{
[self abortUpdate];
return;
}

// Give the host app an opportunity to postpone the install and relaunch.
static BOOL postponedOnce = NO;
if (!postponedOnce && [[updater delegate] respondsToSelector:@selector(updater:shouldPostponeRelaunchForUpdate:untilInvoking:)])
{
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[[self class] instanceMethodSignatureForSelector:@selector(installWithToolAndRelaunch:)]];
[invocation setSelector:@selector(installWithToolAndRelaunch:)];
[invocation setArgument:&relaunch atIndex:0];
[invocation setTarget:self];
postponedOnce = YES;
if ([[updater delegate] updater:updater shouldPostponeRelaunchForUpdate:updateItem untilInvoking:invocation])
return;
}


if ([[updater delegate] respondsToSelector:@selector(updater:willInstallUpdate:)])
[[updater delegate] updater:updater willInstallUpdate:updateItem];

Expand All @@ -276,49 +296,25 @@ - (void)installUpdate
else
[self abortUpdateWithError:[NSError errorWithDomain:SUSparkleErrorDomain code:SURelaunchError userInfo:[NSDictionary dictionaryWithObjectsAndKeys:SULocalizedString(@"An error occurred while extracting the archive. Please try again later.", nil), NSLocalizedDescriptionKey, [NSString stringWithFormat:@"Couldn't copy relauncher (%@) to temporary path (%@)! %@", relaunchPathToCopy, targetPath, (error ? [error localizedDescription] : @"")], NSLocalizedFailureReasonErrorKey, nil]]];

[self installAndRelaunchWithTool];
}

- (void)installAndRelaunchWithTool
{
BOOL mayRelaunchAtAll = [updater mayUpdateAndRestart];
[[NSNotificationCenter defaultCenter] postNotificationName:SUUpdaterWillRestartNotification object:self];
if ([[updater delegate] respondsToSelector:@selector(updaterWillRelaunchApplication:)])
[[updater delegate] updaterWillRelaunchApplication:updater];

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];
NSString *relaunchToolPath = [relaunchPath stringByAppendingPathComponent: @"/Contents/MacOS/finish_installation"];
[NSTask launchedTaskWithLaunchPath: relaunchToolPath arguments:[NSArray arrayWithObjects:pathToRelaunch, [NSString stringWithFormat:@"%d", [[NSProcessInfo processInfo] processIdentifier]], tempDir, relaunch ? @"1" : @"0", nil]];

if( mayRelaunchAtAll )
{
// 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(installAndRelaunchWithTool)]];
[invocation setSelector:@selector(installAndRelaunchWithTool)];
[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];

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];
NSString *relaunchToolPath = [relaunchPath stringByAppendingPathComponent: @"/Contents/MacOS/finish_installation"];
[NSTask launchedTaskWithLaunchPath: relaunchToolPath arguments:[NSArray arrayWithObjects:pathToRelaunch, [NSString stringWithFormat:@"%d", [[NSProcessInfo processInfo] processIdentifier]], tempDir, nil]];

[NSApp terminate:self];
}
else
[self abortUpdate];
[NSApp terminate:self];
}

- (void)cleanUpDownload
Expand Down
7 changes: 3 additions & 4 deletions SUUIBasedUpdateDriver.m
Expand Up @@ -162,15 +162,14 @@ - (void)unarchiverDidFinish:(SUUnarchiver *)ua

- (void)installAndRestart: (id)sender
{
if( [updater mayUpdateAndRestart] )
[self installUpdate];
[self installWithToolAndRelaunch:YES];
}

- (void)installUpdate
- (void)installWithToolAndRelaunch:(BOOL)relaunch
{
[statusController beginActionWithTitle:SULocalizedString(@"Installing update...", @"Take care not to overflow the status window.") maxProgressValue:0.0 statusText:nil];
[statusController setButtonEnabled:NO];
[super installUpdate];
[super installWithToolAndRelaunch:relaunch];


// if a user chooses to NOT relaunch the app (as is the case with WebKit
Expand Down
51 changes: 29 additions & 22 deletions finish_installation.m
Expand Up @@ -21,6 +21,7 @@ @interface TerminationListener : NSObject
NSTimer *watchdogTimer;
NSTimer *longInstallationTimer;
SUHost *host;
BOOL shouldRelaunch;
}

- (void) parentHasQuit;
Expand All @@ -35,7 +36,7 @@ - (void) watchdog:(NSTimer *)aTimer;

@implementation TerminationListener

- (id) initWithExecutablePath:(const char *)execpath parentProcessId:(pid_t)ppid folderPath: (const char*)infolderpath
- (id) initWithExecutablePath:(const char *)execpath parentProcessId:(pid_t)ppid folderPath: (const char*)infolderpath shouldRelaunch:(BOOL)relaunch
selfPath: (NSString*)inSelfPath
{
if( !(self = [super init]) )
Expand All @@ -45,6 +46,7 @@ - (id) initWithExecutablePath:(const char *)execpath parentProcessId:(pid_t)ppid
parentprocessid = ppid;
folderpath = infolderpath;
selfPath = [inSelfPath retain];
shouldRelaunch = relaunch;

BOOL alreadyTerminated = (getppid() == 1); // ppid is launchd (1) => parent terminated already

Expand Down Expand Up @@ -105,23 +107,27 @@ - (void)showAppIconInDock:(NSTimer *)aTimer;

- (void) relaunch
{
NSString *appPath = nil;
if( !folderpath )
appPath = [[NSFileManager defaultManager] stringWithFileSystemRepresentation:executablepath length:strlen(executablepath)];
else
appPath = [host installationPath];
[[NSWorkspace sharedWorkspace] openFile: appPath];
if( folderpath )
{
NSError* theError = nil;
if( ![SUPlainInstaller _removeFileAtPath: [SUInstaller updateFolder] error: &theError] )
SULog( @"Couldn't remove update folder: %@.", theError );
}
#if MAC_OS_X_VERSION_MIN_REQUIRED <= MAC_OS_X_VERSION_10_4
[[NSFileManager defaultManager] removeFileAtPath: selfPath handler: nil];
#else
[[NSFileManager defaultManager] removeItemAtPath: selfPath error: NULL];
#endif
if (shouldRelaunch)
{
NSString *appPath = nil;
if( !folderpath )
appPath = [[NSFileManager defaultManager] stringWithFileSystemRepresentation:executablepath length:strlen(executablepath)];
else
appPath = [host installationPath];
[[NSWorkspace sharedWorkspace] openFile: appPath];
if( folderpath )
{
NSError* theError = nil;
if( ![SUPlainInstaller _removeFileAtPath: [SUInstaller updateFolder] error: &theError] )
SULog( @"Couldn't remove update folder: %@.", theError );
}
#if MAC_OS_X_VERSION_MIN_REQUIRED <= MAC_OS_X_VERSION_10_4
[[NSFileManager defaultManager] removeFileAtPath: selfPath handler: nil];
#else
[[NSFileManager defaultManager] removeItemAtPath: selfPath error: NULL];
#endif
}

exit(EXIT_SUCCESS);
}

Expand Down Expand Up @@ -158,7 +164,7 @@ - (void) installerForHost:(SUHost *)host failedWithError:(NSError *)error

int main (int argc, const char * argv[])
{
if( argc < 3 || argc > 4 )
if( argc < 4 || argc > 5 )
return EXIT_FAILURE;

NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
Expand All @@ -182,9 +188,10 @@ int main (int argc, const char * argv[])

[NSApplication sharedApplication];
[[[TerminationListener alloc] initWithExecutablePath: (argc > 1) ? argv[1] : NULL
parentProcessId: (argc > 2) ? atoi(argv[2]) : 0
folderPath: (argc > 3) ? argv[3] : NULL
selfPath: selfPath] autorelease];
parentProcessId: (argc > 2) ? atoi(argv[2]) : 0
folderPath: (argc > 3) ? argv[3] : NULL
shouldRelaunch: (argc > 4) ? atoi(argv[4]) : 1
selfPath: selfPath] autorelease];
[[NSApplication sharedApplication] run];

[pool drain];
Expand Down

0 comments on commit c96aa2e

Please sign in to comment.