Created
July 26, 2013 11:04
-
-
Save curthard89/6088064 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// UpgradeController.m | |
// Caffeinated | |
// | |
// Created by Curtis Hard on 25/07/2013. | |
// | |
// | |
#import "UpgradeController.h" | |
@implementation UpgradeController | |
#define UPGRADE_CLASS_PREFIX @"UpgradeVersion" | |
- (void)dealloc | |
{ | |
[window release], window = nil; | |
[context release], context = nil; | |
[super dealloc]; | |
} | |
- (id)initWithManagedObjectContext:(NSManagedObjectContext *)aContext | |
isNew:(BOOL)flag | |
{ | |
if( ( self = [super init] ) != nil ) | |
{ | |
context = [aContext retain]; | |
isNew = flag; | |
} | |
return self; | |
} | |
- (void)step | |
{ | |
[progressIndicator incrementBy:1]; | |
[NSThread sleepForTimeInterval:0.001]; | |
} | |
- (void)upgrade | |
{ | |
// we need to check the current DB version | |
NSEntityDescription * configEntity = [NSEntityDescription entityForName:@"Config" | |
inManagedObjectContext:context]; | |
// find the version | |
NSFetchRequest * request = [[[NSFetchRequest alloc] init] autorelease]; | |
[request setEntity:configEntity]; | |
[request setFetchLimit:1]; | |
NSError * error = nil; | |
NSArray * results = [context executeFetchRequest:request | |
error:&error]; | |
NSInteger currentVersion = 0; | |
Config * config = nil; | |
if( [results count] != 0 ) | |
{ | |
config = [results objectAtIndex:0]; | |
currentVersion = [[config version] integerValue]; | |
} else | |
config = [NSEntityDescription insertNewObjectForEntityForName:[configEntity name] | |
inManagedObjectContext:context]; | |
// find the classes | |
NSInteger start = currentVersion; | |
NSInteger counter = start; | |
NSInteger latestFoundVersion = 0; | |
NSMutableArray * objs = [[[NSMutableArray alloc] init] autorelease]; | |
while( TRUE ) | |
{ | |
counter++; | |
// see if there is a class available from the start version upwards... | |
Class upgradeClass = NSClassFromString( [NSString stringWithFormat:@"%@%ld",UPGRADE_CLASS_PREFIX,counter] ); | |
if( upgradeClass == nil ) | |
break; | |
// add the upgrade | |
Upgrade * upgrade = [[[upgradeClass alloc] initWithManagedObjectContext:context | |
controller:self] autorelease]; | |
[objs addObject:upgrade]; | |
// store the latest version | |
if( [upgrade versionNumber] > latestFoundVersion ) | |
latestFoundVersion = [upgrade versionNumber]; | |
} | |
// nothing to do | |
if( [objs count] == 0 ) | |
return; | |
// are we new? | |
if( isNew ) | |
{ | |
[config setVersion:[NSNumber numberWithInteger:latestFoundVersion]]; | |
[context save:&error]; | |
return; | |
} | |
// there is an upgrade to perform... | |
// load the nib and run the modal window | |
[NSBundle loadNibNamed:@"Upgrade" | |
owner:self]; | |
[label setStringValue:@"Preparing database upgrade..."]; | |
// set up the indicator | |
[progressIndicator setUsesThreadedAnimation:YES]; | |
[progressIndicator startAnimation:nil]; | |
[progressIndicator setIndeterminate:YES]; | |
NSPersistentStoreCoordinator * coordinator = [context persistentStoreCoordinator]; | |
// start the async... | |
dispatch_block_t upgradeBlock = ^{ | |
NSInteger itemsToUpgrade = 0; | |
for( Upgrade * up in objs ) | |
{ | |
// create the context per request | |
NSManagedObjectContext * mContext = [[[NSManagedObjectContext alloc] init] autorelease]; | |
[mContext setUndoManager:nil]; | |
[mContext setPersistentStoreCoordinator:coordinator]; | |
// set the context | |
[up setManagedObjectContext:mContext]; | |
[up prefetch]; | |
itemsToUpgrade += [up numberOfUpgradingObjects]; | |
} | |
// set the min and max on the progress indicator | |
[progressIndicator setMinValue:0]; | |
[progressIndicator setMaxValue:itemsToUpgrade]; | |
[progressIndicator setIndeterminate:NO]; | |
// label | |
dispatch_sync( dispatch_get_main_queue(), ^{ | |
[label setStringValue:@"Upgrading database..."]; | |
}); | |
// run the main | |
for( Upgrade * up in objs ) | |
{ | |
NSLog(@"Upgrading DB to version %ld",[up versionNumber]); | |
[up main]; | |
[up save]; | |
[up clean]; | |
[config setVersion:[NSNumber numberWithInteger:[up versionNumber]]]; | |
NSLog(@"Upgraded DB to version %ld",[up versionNumber]); | |
} | |
// stop the modal | |
dispatch_sync( dispatch_get_main_queue(), ^{ | |
[label setStringValue:@"Cleaning up..."]; | |
// clean up... | |
[progressIndicator setIndeterminate:YES]; | |
[progressIndicator startAnimation:nil]; | |
double delayInSeconds = 2.0; | |
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC)); | |
dispatch_after(popTime, dispatch_get_main_queue(), ^(void) | |
{ | |
// set the label back | |
[label setStringValue:@"Database upgrade complete."]; | |
[progressIndicator setIndeterminate:NO]; | |
[progressIndicator startAnimation:nil]; | |
// kill the modal | |
double delayInSeconds = 2.0; | |
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC)); | |
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){ | |
// abort the modal | |
[NSApp abortModal]; | |
}); | |
}); | |
}); | |
}; | |
// dispatch the async block after a delay | |
double delayInSeconds = 1.0; | |
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC)); | |
dispatch_after(popTime, dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_HIGH, 0 ), ^(void) | |
{ | |
dispatch_async( dispatch_get_main_queue(), ^{ | |
// set the label to backup | |
[label setStringValue:@"Creating database backup..."]; | |
dispatch_async( dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_HIGH, 0 ), ^{ | |
// create backup here... | |
NSURL * storeURL = [[[[context persistentStoreCoordinator] persistentStores] objectAtIndex:0] URL]; | |
if( [[NSFileManager defaultManager] fileExistsAtPath:[storeURL path]] ) | |
{ | |
NSDateFormatter * dateFormatter = [[[NSDateFormatter alloc] init] autorelease]; | |
[dateFormatter setDateFormat:@"yyyy-MM-dd HH-mm-ss"]; | |
NSError * error = nil; | |
NSString * location = [NSString stringWithFormat:@"%@/%@.cafdb",NSUserLibraryPathWithDirectory( @"Backup/Databases" ),[dateFormatter stringFromDate:[NSDate date]]]; | |
[[NSFileManager defaultManager] copyItemAtPath:[storeURL path] | |
toPath:location | |
error:&error]; | |
} | |
double delayInSeconds = 2.0; | |
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC)); | |
dispatch_after(popTime, dispatch_get_current_queue(), upgradeBlock ); | |
}); | |
}); | |
}); | |
// stop the run loop and make it modal...basically just block the window | |
while( [NSApp runModalForWindow:window] == NSRunContinuesResponse ) | |
continue; | |
// save the objects | |
[context save:&error]; | |
// now its done we need to store the new version number | |
[window close], window = nil; | |
} | |
@end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment