Permalink
Browse files

Start of Installation process of Daemon

  • Loading branch information...
1 parent 737f9f0 commit c311a9f2556877546ef47c9ff70a15f0a769df7f Marcus S. Zarra committed Jun 5, 2010
@@ -28,6 +28,9 @@
@interface AppDelegate : NSObject <NSApplicationDelegate>
{
+ NSStatusItem *statusItem;
}
+@property (nonatomic, retain) NSStatusItem *statusItem;
+
@end
@@ -34,6 +34,43 @@ - (void)applicationDidFinishLaunching:(NSNotification*)aNotification
{
[[ZSyncHandler shared] setDelegate:self];
[[ZSyncHandler shared] startBroadcasting];
+
+ NSMenu *menu = [[NSMenu alloc] initWithTitle:@"ZSync"];
+
+ NSMenuItem *aboutMenu = [[NSMenuItem alloc] initWithTitle:@"About" action:@selector(about:) keyEquivalent:@""];
+ [menu addItem:aboutMenu];
+ [aboutMenu release], aboutMenu = nil;
+
+ [menu addItem:[NSMenuItem separatorItem]];
+
+ NSMenuItem *quitMenu = [[NSMenuItem alloc] initWithTitle:@"Quit" action:@selector(quit:) keyEquivalent:@""];
+ [menu addItem:quitMenu];
+ [quitMenu release], quitMenu = nil;
+
+ NSImage *statusImage = [NSImage imageNamed:@"menubar.png"];
+
+ statusItem = [[[NSStatusBar systemStatusBar] statusItemWithLength:[statusImage size].width] retain];
+ [statusItem setMenu:menu];
+ [statusItem setToolTip:NSLocalizedString(@"ZSync Daemon", @"ZSync menu bar toolitp")];
+ [statusItem setImage:statusImage];
+ [statusItem setAction:@selector(statusItemSelected:)];
+
+ [menu release], menu = nil;
+
+ [[NSApplication sharedApplication] hide:self];
+}
+
+- (IBAction)about:(id)sender
+{
+ DLog(@"fired");
}
+- (IBAction)quit:(id)sender
+{
+ DLog(@"fired");
+ [[NSApplication sharedApplication] terminate:self];
+}
+
+@synthesize statusItem;
+
@end
@@ -0,0 +1,10 @@
+@interface ZSyncDaemon : NSObject
+{
+
+}
+
++ (BOOL)installPluginAtPath:(NSString*)path intoDaemonWithError:(NSError**)error;
++ (BOOL)isDaemonRunning;
++ (void)startDaemon;
+
+@end
@@ -0,0 +1,222 @@
+#import "ZSyncDaemon.h"
+
+@implementation ZSyncDaemon
+
++ (NSString*)basePath
+{
+ //Build our standard install path
+ NSArray *paths = NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES);
+ NSString *basePath = ([paths count] > 0) ? [paths objectAtIndex:0] : NSTemporaryDirectory();
+ basePath = [basePath stringByAppendingPathComponent:@"ZSyncDaemon"];
+ return basePath;
+}
+
++ (NSString*)applicationPath
+{
+ NSString *basePath = [self basePath];
+ return [basePath stringByAppendingPathComponent:@"ZSyncDaemon.app"];
+}
+
++ (BOOL)checkBasePath:(NSString*)basePath error:(NSError**)error;
+{
+ NSFileManager *fileManager = [NSFileManager defaultManager];
+ BOOL isDirectory = NO;
+ if (![fileManager fileExistsAtPath:basePath isDirectory:&isDirectory]) {
+ return NO;
+ }
+ if (!isDirectory) {
+ NSString *errorDesc = [NSString stringWithFormat:@"Unknown file at base installation path: %@", basePath];
+ NSDictionary *dictionary = [NSDictionary dictionaryWithObject:errorDesc forKey:NSLocalizedDescriptionKey];
+ *error = [NSError errorWithDomain:@"ZSync" code:1123 userInfo:dictionary];
+ return NO;
+ }
+ return YES;
+}
+
++ (BOOL)checkApplicationPath:(NSString*)applicationPath error:(NSError**)error;
+{
+ NSFileManager *fileManager = [NSFileManager defaultManager];
+ BOOL isDirectory = NO;
+ if (![fileManager fileExistsAtPath:applicationPath isDirectory:&isDirectory]) {
+ return NO;
+ }
+ if (!isDirectory) {
+ NSString *errorDesc = [NSString stringWithFormat:@"Unknown file at daemon application installation path: %@", applicationPath];
+ NSDictionary *dictionary = [NSDictionary dictionaryWithObject:errorDesc forKey:NSLocalizedDescriptionKey];
+ *error = [NSError errorWithDomain:@"ZSync" code:1124 userInfo:dictionary];
+ return NO;
+ }
+ return YES;
+}
+
++ (BOOL)isDaemonInstalled:(NSError**)error;
+{
+ NSString *basePath = [self basePath];
+ if (![self checkBasePath:basePath error:error]) {
+ if (error) {
+ return NO;
+ }
+ if (![[NSFileManager defaultManager] createDirectoryAtPath:basePath
+ withIntermediateDirectories:YES
+ attributes:nil
+ error:error]) {
+ return NO;
+ }
+ }
+ NSString *applicationPath = [self applicationPath];
+ return [self checkApplicationPath:applicationPath error:error];
+}
+
++ (BOOL)installDaemon:(NSError**)error;
+{
+ NSString *myBundlePath = [[NSBundle mainBundle] bundlePath];
+ NSString *applicationPath = [self applicationPath];
+ NSFileManager *fileManager = [NSFileManager defaultManager];
+ return [fileManager copyItemAtPath:myBundlePath toPath:applicationPath error:error];
+}
+
++ (BOOL)stopDaemon:(NSError**)error
+{
+ NSString *appName = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleExecutable"];
+ NSString *command = [NSString stringWithFormat:@"tell application \"%@\" to quit", appName];
+ NSAppleScript *quitScript;
+ quitScript = [[NSAppleScript alloc] initWithSource:command];
+ NSDictionary *errorDict = nil;
+ // TODO: This should be turned into an NSError response
+ if (![quitScript executeAndReturnError:&errorDict]) {
+ ALog(@"Failure. What does it look like: %@", errorDict);
+ [quitScript release], quitScript = nil;
+ return NO;
+ }
+ [quitScript release], quitScript = nil;
+ return YES;
+}
+
++ (BOOL)updateInstalledApplication:(NSError**)error;
+{
+ NSString *appName = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleExecutable"];
+
+ if ([self isDaemonRunning] && ![self stopDaemon:error]) return NO;
+
+ NSString *myBundlePath = [[NSBundle mainBundle] bundlePath];
+
+ NSString *applicationPath = [self applicationPath];
+ NSString *basePath = [self basePath];
+ NSWorkspace *workspace = [NSWorkspace sharedWorkspace];
+ if (![workspace performFileOperation:NSWorkspaceRecycleOperation
+ source:basePath
+ destination:@""
+ files:[NSArray arrayWithObject:appName]
+ tag:NULL]) {
+ NSString *errorDesc = [NSString stringWithFormat:@"Failed to move old app version to the trash"];
+ NSDictionary *dictionary = [NSDictionary dictionaryWithObject:errorDesc forKey:NSLocalizedDescriptionKey];
+ *error = [NSError errorWithDomain:@"ZSync" code:1126 userInfo:dictionary];
+ return NO;
+ }
+
+ NSFileManager *fileManager = [NSFileManager defaultManager];
+ return [fileManager copyItemAtPath:myBundlePath toPath:applicationPath error:error];
+}
+
++ (NSString*)pluginPath
+{
+ NSString *basePath = [self basePath];
+ return [basePath stringByAppendingPathComponent:@"Plugins"];
+}
+
++ (BOOL)isPluginInstalled:(NSString*)path error:(NSError**)error
+{
+ NSString *pluginPath = [self pluginPath];
+ NSFileManager *fileManager = [NSFileManager defaultManager];
+ BOOL isDirectory = NO;
+ if (![fileManager fileExistsAtPath:pluginPath isDirectory:&isDirectory]) {
+ return NO;
+ }
+ if (!isDirectory) {
+ NSString *errorDesc = [NSString stringWithFormat:@"Unknown file at plugin installation path: %@", pluginPath];
+ NSDictionary *dictionary = [NSDictionary dictionaryWithObject:errorDesc forKey:NSLocalizedDescriptionKey];
+ *error = [NSError errorWithDomain:@"ZSync" code:1123 userInfo:dictionary];
+ return NO;
+ }
+
+ NSString *finalPath = [pluginPath stringByAppendingPathComponent:[path lastPathComponent]];
+ if (![fileManager fileExistsAtPath:finalPath isDirectory:&isDirectory]) {
+ return NO;
+ }
+ return YES;
+}
+
++ (BOOL)installPluginAtPath:(NSString*)path intoDaemonWithError:(NSError**)error;
+{
+ if (![[path pathExtension] isEqualToString:@"zsyncPlugin"]) {
+ NSString *errorDesc = [NSString stringWithFormat:@"url is not a valid ZSync plugin: %@", path];
+ NSDictionary *dictionary = [NSDictionary dictionaryWithObject:errorDesc forKey:NSLocalizedDescriptionKey];
+ *error = [NSError errorWithDomain:@"ZSync" code:1125 userInfo:dictionary];
+ return NO;
+ }
+
+ BOOL isDaemonInstalled = [self isDaemonInstalled:error];
+
+ if (!isDaemonInstalled && *error) {
+ return NO;
+ }
+
+ if (!isDaemonInstalled) {
+ if (![self installDaemon:error]) return NO;
+ } else {
+ NSDictionary *infoDictionary = [[NSBundle mainBundle] infoDictionary];
+ NSInteger currentVersionNumber = [[infoDictionary objectForKey:ZSyncVersionNumber] integerValue];
+
+ NSBundle *installed = [NSBundle bundleWithPath:[self applicationPath]];
+ NSInteger installedVersionNumber = [[[installed infoDictionary] objectForKey:ZSyncVersionNumber] integerValue];
+
+ if (installedVersionNumber < currentVersionNumber && ![self updateInstalledApplication:error]) return NO;
+ }
+
+ //Is plugin already installed?
+ if ([self isPluginInstalled:path error:error]) {
+ return YES;
+ }
+
+ //Shutdown the daemon to install the plugin
+ if ([self isDaemonRunning] && ![self stopDaemon:error]) {
+ return NO;
+ }
+
+ //Install the plugin
+ NSString *pluginPath = [[self pluginPath] stringByAppendingPathComponent:[path lastPathComponent]];
+ NSFileManager *fileManager = [NSFileManager defaultManager];
+ if (![fileManager copyItemAtPath:path toPath:pluginPath error:error]) {
+ return NO;
+ }
+
+ //Start the daemon back up
+ [self startDaemon];
+
+ return YES;
+}
+
++ (BOOL)isDaemonRunning;
+{
+ NSDictionary *infoDictionary = [[NSBundle mainBundle] infoDictionary];
+ NSString *myBundleID = [infoDictionary objectForKey:@"CFBundleIdentifier"];
+
+ NSWorkspace *workspace = [NSWorkspace sharedWorkspace];
+ NSArray *apps = [workspace launchedApplications];
+ for (NSDictionary *appDict in apps) {
+ NSString *bundleID = [appDict objectForKey:@"NSApplicationBundleIdentifier"];
+ if ([bundleID isEqualToString:myBundleID]) return YES;
+ }
+ return NO;
+}
+
++ (void)startDaemon;
+{
+ NSDictionary *infoDictionary = [[NSBundle mainBundle] infoDictionary];
+ NSString *appName = [infoDictionary objectForKey:@"CFBundleExecutable"];
+
+ NSWorkspace *workspace = [NSWorkspace sharedWorkspace];
+ [workspace launchApplication:appName];
+}
+
+@end
View
@@ -30,5 +30,7 @@
<string>NSApplication</string>
<key>LSUIElement</key>
<true/>
+ <key>ZSyncVersionNumber</key>
+ <string>1</string>
</dict>
</plist>
View
@@ -3,3 +3,5 @@
#import <CoreData/CoreData.h>
#import "ZSync.h"
#endif
+
+#define ZSyncVersionNumber @"ZSyncVersionNumber"
@@ -8,6 +8,8 @@
/* Begin PBXBuildFile section */
8D11072F0486CEB800E47090 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */; };
+ B63F9C2211B2EA2800811EB1 /* menubar.png in Resources */ = {isa = PBXBuildFile; fileRef = B63F9C2111B2EA2800811EB1 /* menubar.png */; };
+ B63F9CAC11B2EF6700811EB1 /* ZSyncDaemon.m in Sources */ = {isa = PBXBuildFile; fileRef = B63F9CAB11B2EF6700811EB1 /* ZSyncDaemon.m */; };
B64FE70410EE728F00B15A8F /* clientDescription.plist in Resources */ = {isa = PBXBuildFile; fileRef = B64FE70310EE728F00B15A8F /* clientDescription.plist */; };
B64FE7C910EEA24500B15A8F /* DataModel.xcdatamodel in Sources */ = {isa = PBXBuildFile; fileRef = B64FE7C810EEA24500B15A8F /* DataModel.xcdatamodel */; };
B64FE94010EF35DF00B15A8F /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = B64FE93F10EF35DF00B15A8F /* libz.dylib */; };
@@ -31,6 +33,9 @@
29B97324FDCFA39411CA2CEA /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = /System/Library/Frameworks/AppKit.framework; sourceTree = "<absolute>"; };
29B97325FDCFA39411CA2CEA /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = /System/Library/Frameworks/Foundation.framework; sourceTree = "<absolute>"; };
8D1107320486CEB800E47090 /* ZSyncDaemon.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = ZSyncDaemon.app; sourceTree = BUILT_PRODUCTS_DIR; };
+ B63F9C2111B2EA2800811EB1 /* menubar.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = menubar.png; sourceTree = "<group>"; };
+ B63F9CAA11B2EF6700811EB1 /* ZSyncDaemon.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZSyncDaemon.h; sourceTree = "<group>"; };
+ B63F9CAB11B2EF6700811EB1 /* ZSyncDaemon.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZSyncDaemon.m; sourceTree = "<group>"; };
B64FE70310EE728F00B15A8F /* clientDescription.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = clientDescription.plist; sourceTree = "<group>"; };
B64FE7C810EEA24500B15A8F /* DataModel.xcdatamodel */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = wrapper.xcdatamodel; path = DataModel.xcdatamodel; sourceTree = "<group>"; };
B64FE93F10EF35DF00B15A8F /* libz.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libz.dylib; path = usr/lib/libz.dylib; sourceTree = SDKROOT; };
@@ -121,6 +126,7 @@
29B97314FDCFA39411CA2CEA /* Daemon */ = {
isa = PBXGroup;
children = (
+ B63F9C2011B2EA1300811EB1 /* Images */,
B6EC175910F5033E0051FD2E /* GoogleToolboxSubset */,
B691FB9810ED879D00207210 /* SharedCode */,
B691FB8210ED875800207210 /* DesktopCode */,
@@ -164,6 +170,15 @@
name = Frameworks;
sourceTree = "<group>";
};
+ B63F9C2011B2EA1300811EB1 /* Images */ = {
+ isa = PBXGroup;
+ children = (
+ B63F9C2111B2EA2800811EB1 /* menubar.png */,
+ );
+ name = Images;
+ path = ../Images;
+ sourceTree = "<group>";
+ };
B64FE7C710EEA24500B15A8F /* DataModel */ = {
isa = PBXGroup;
children = (
@@ -178,6 +193,8 @@
children = (
B691FB3A10ED855F00207210 /* AppDelegate.h */,
B691FB3B10ED855F00207210 /* AppDelegate.m */,
+ B63F9CAA11B2EF6700811EB1 /* ZSyncDaemon.h */,
+ B63F9CAB11B2EF6700811EB1 /* ZSyncDaemon.m */,
);
path = Classes;
sourceTree = "<group>";
@@ -290,6 +307,7 @@
B691FB4510ED855F00207210 /* MainMenu.xib in Resources */,
B691FB8C10ED875800207210 /* PairingWindow.xib in Resources */,
B64FE70410EE728F00B15A8F /* clientDescription.plist in Resources */,
+ B63F9C2211B2EA2800811EB1 /* menubar.png in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -308,6 +326,7 @@
B64FE7C910EEA24500B15A8F /* DataModel.xcdatamodel in Sources */,
B6EC175D10F5033E0051FD2E /* GTMNSData+zlib.m in Sources */,
B67ED12E1103765600314759 /* ZSyncConnectionDelegate.m in Sources */,
+ B63F9CAC11B2EF6700811EB1 /* ZSyncDaemon.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -49,7 +49,7 @@ - (void)windowDidLoad
- (void) dealloc
{
- DLog(@"%s window released cleanly", __PRETTY_FUNCTION__);
+ DLog(@"window released cleanly");
[codeString release], codeString = nil;
[super dealloc];
}
Oops, something went wrong.

0 comments on commit c311a9f

Please sign in to comment.