Commit 861b8b86 authored by Tobias's avatar Tobias Committed by Felix Paul Kühne

move library migration code to category - remove old...

move library migration code to category - remove old GreatSharkHuntDatabaseFormat migration which is no longer needed - in debug mode clean new base path before doing the migration - remove all sqlite remaining from old database path
Signed-off-by: Felix Paul Kühne's avatarFelix Paul Kühne <fkuehne@videolan.org>
parent 63620abc
......@@ -27,19 +27,23 @@
@interface MLMediaLibrary : NSObject
@property (readonly) BOOL libraryNeedsUpgrade;
@property (nonatomic, strong) id delegate;
// base path for the database and thumbnails
// setting the library base path resets the path derived from it
@property (nonatomic, copy) NSString *libraryBasePath;
@property (nonatomic, strong) NSURL *persistentStoreURL;
@property (nonatomic, strong) NSPersistentStoreCoordinator *persistentStoreCoordinator;
@property (nonatomic, copy) NSDictionary *additionalPersitentStoreOptions;
@property (nonatomic, readonly) int deviceSpeedCategory;
// default is group.org.videolan.vlc-ios
@property (nonatomic, copy) NSString *applicationGroupIdentifier;
+ (id)sharedMediaLibrary;
- (BOOL)libraryMigrationNeeded;
- (void)migrateLibrary;
- (void)addFilePaths:(NSArray *)filepaths;
- (void)upgradeLibrary;
- (void)updateMediaDatabase;
// May be internal
......@@ -57,8 +61,6 @@
- (void)save;
- (void)libraryDidDisappear;
- (void)libraryDidAppear;
- (BOOL)migrateLibraryToBasePath:(NSString *)basePath error:(NSError **)migrationError;
@end
@protocol MLMediaLibrary <NSObject>
......
......@@ -47,6 +47,7 @@
A792468C170F09A30036AAF2 /* MLShow.h in Copy Files */ = {isa = PBXBuildFile; fileRef = 7D0EF514170885130003ED47 /* MLShow.h */; };
A792468D170F09A30036AAF2 /* MLShowEpisode.h in Copy Files */ = {isa = PBXBuildFile; fileRef = 7D0EF515170885130003ED47 /* MLShowEpisode.h */; };
A792468E170F09A30036AAF2 /* MLThumbnailerQueue.h in Copy Files */ = {isa = PBXBuildFile; fileRef = 7D0EF521170885130003ED47 /* MLThumbnailerQueue.h */; };
DDB959371AFB9B2B00BB8CFF /* MLMediaLibrary+Migration.m in Sources */ = {isa = PBXBuildFile; fileRef = DDB959361AFB9B2B00BB8CFF /* MLMediaLibrary+Migration.m */; };
/* End PBXBuildFile section */
/* Begin PBXCopyFilesBuildPhase section */
......@@ -138,6 +139,8 @@
7D9E238417AEEA13008485E5 /* MLAlbumTrack.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MLAlbumTrack.h; sourceTree = "<group>"; };
7D9E238517AEEA13008485E5 /* MLAlbumTrack.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MLAlbumTrack.m; sourceTree = "<group>"; };
7D9E238717AEEA71008485E5 /* MLAlbum.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MLAlbum.m; sourceTree = "<group>"; };
DDB959351AFB9B2B00BB8CFF /* MLMediaLibrary+Migration.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "MLMediaLibrary+Migration.h"; sourceTree = "<group>"; };
DDB959361AFB9B2B00BB8CFF /* MLMediaLibrary+Migration.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "MLMediaLibrary+Migration.m"; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
......@@ -239,6 +242,8 @@
7D0EF51B170885130003ED47 /* MLFileParserQueue.m */,
7D0EF51C170885130003ED47 /* MLLabel.m */,
7D0EF51D170885130003ED47 /* MLMediaLibrary.m */,
DDB959351AFB9B2B00BB8CFF /* MLMediaLibrary+Migration.h */,
DDB959361AFB9B2B00BB8CFF /* MLMediaLibrary+Migration.m */,
7D0EF51E170885130003ED47 /* MLMovieInfoGrabber.m */,
7D0EF51F170885130003ED47 /* MLShow.m */,
7D0EF520170885130003ED47 /* MLShowEpisode.m */,
......@@ -388,6 +393,7 @@
7D0EF556170885230003ED47 /* CXMLElement_CreationExtensions.m in Sources */,
7D4625851A560729001A80B4 /* MediaLibrary.xcdatamodeld in Sources */,
7D0EF557170885230003ED47 /* CXMLElement_ElementTreeExtensions.m in Sources */,
DDB959371AFB9B2B00BB8CFF /* MLMediaLibrary+Migration.m in Sources */,
7D0EF558170885230003ED47 /* CXMLNode.m in Sources */,
7D0EF559170885230003ED47 /* CXMLNode_PrivateExtensions.m in Sources */,
7D0EF55A170885230003ED47 /* CXMLNode_XPathExtensions.m in Sources */,
......
/*****************************************************************************
* MLMediaLibrary+Migration.h
* MobileMediaLibraryKit
*****************************************************************************
* Copyright (c) 2015 VideoLAN. All rights reserved.
* $Id$
*
* Authors: Tobias Conradi <videolan # tobias-conradi.de>
*
* Refer to the COPYING file of the official project for license.
*****************************************************************************/
#import "MLMediaLibrary.h"
@interface MLMediaLibrary (Migration)
- (void)_setupLibraryPathPriorToMigration;
- (BOOL)_libraryMigrationNeeded;
- (void)_migrateLibrary;
@end
/*****************************************************************************
* MLMediaLibrary+Migration.m
* MobileMediaLibraryKit
*****************************************************************************
* Copyright (c) 2015 VideoLAN. All rights reserved.
* $Id$
*
* Authors: Tobias Conradi <videolan # tobias-conradi.de>
*
* Refer to the COPYING file of the official project for license.
*****************************************************************************/
#import "MLMediaLibrary+Migration.h"
#import "MLTitleDecrapifier.h"
#import "MLMovieInfoGrabber.h"
#import "MLTVShowInfoGrabber.h"
#import "MLTVShowEpisodesInfoGrabber.h"
#import "MLFile.h"
#import "MLLabel.h"
#import "MLShowEpisode.h"
#import "MLShow.h"
#import "MLThumbnailerQueue.h"
#import "MLAlbumTrack.h"
#import "MLAlbum.h"
@implementation MLMediaLibrary (Migration)
- (void)_setupLibraryPathPriorToMigration
{
NSString *basePath = nil;
NSString *groupPath = [self _groupURL].path;
if ([self _migrationToGroupsNeeded] || groupPath == nil) {
basePath = [self _oldBasePath];
} else {
basePath = groupPath;
}
self.libraryBasePath = basePath;
}
- (BOOL)_libraryMigrationNeeded
{
BOOL migrationNeeded = [self _migrationToGroupsNeeded];
if (!migrationNeeded) {
NSError *error;
migrationNeeded = [self _migrationNeeded:&error];
if (error!=nil) {
NSLog(@"Failed to check if model migration is needed %@", error);
}
}
return migrationNeeded;
}
- (void)_migrateLibrary
{
// triggers automatic model migration
[self persistentStoreCoordinator];
if (![self _migrationToGroupsNeeded]) {
return;
}
NSError *error;
NSString *groupPath = [self _groupURL].path;
if ([self _migrateLibraryToBasePath:groupPath error:&error]) {
NSLog(@"Failed to migrate to group path with error: %@",error);
}
}
#pragma mark - model version migrations
- (BOOL)_migrationNeeded:(NSError **) migrationCheckError
{
BOOL migrationNeeded = NO;
if ([[NSFileManager defaultManager] fileExistsAtPath:((MLMediaLibrary *)[MLMediaLibrary sharedMediaLibrary]).persistentStoreURL.path]) {
NSDictionary *sourceMetadata = [NSPersistentStoreCoordinator metadataForPersistentStoreOfType:NSSQLiteStoreType
URL:((MLMediaLibrary *)[MLMediaLibrary sharedMediaLibrary]).persistentStoreURL
error:migrationCheckError];
if (*migrationCheckError) {
return NO;
}
NSManagedObjectModel *destinationModel = [[MLMediaLibrary sharedMediaLibrary] managedObjectModel];
migrationNeeded = ![destinationModel isConfiguration:nil compatibleWithStoreMetadata:sourceMetadata];
}
return migrationNeeded;
}
#pragma mark - group path migration
- (BOOL)_migrationToGroupsNeeded
{
/*
* We can't and don't need to migrate to groups on pre-iOS 7
*/
if (![[NSFileManager defaultManager] respondsToSelector:@selector(containerURLForSecurityApplicationGroupIdentifier:)]) {
return NO;
}
NSString *oldPersistentStorePath = [[self _oldBasePath] stringByAppendingPathComponent: @"MediaLibrary.sqlite"];
return [[NSFileManager defaultManager] fileExistsAtPath:oldPersistentStorePath];
}
- (NSString *)_oldBasePath
{
NSSearchPathDirectory directory = NSLibraryDirectory;
NSArray *paths = NSSearchPathForDirectoriesInDomains(directory, NSUserDomainMask, YES);
return paths.firstObject;
}
- (NSURL *)_groupURL {
if (![[NSFileManager defaultManager] respondsToSelector:@selector(containerURLForSecurityApplicationGroupIdentifier:)]) {
return nil;
}
NSURL *groupURL = [[NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier:self.applicationGroupIdentifier];
#if TARGET_IPHONE_SIMULATOR
// if something went wrong with the entitlements in the Simulator
if (!groupURL) {
NSArray *pathComponents = [[[NSBundle mainBundle] bundlePath] pathComponents];
pathComponents = [pathComponents subarrayWithRange:NSMakeRange(0, pathComponents.count-4)];
NSString *groupComponent = [@"Shared/AppGroup/fake-" stringByAppendingString:self.applicationGroupIdentifier];
NSString *groupPath = [[NSString pathWithComponents:pathComponents] stringByAppendingPathComponent:groupComponent];
groupURL = [NSURL fileURLWithPath:groupPath];
}
#endif
return groupURL;
}
- (BOOL)_migrateLibraryToBasePath:(NSString *)basePath error:(NSError *__autoreleasing *)migrationError
{
BOOL success = YES;
NSPersistentStoreCoordinator *coordinater = [self persistentStoreCoordinator];
if (!coordinater) {
APLog(@"no persistent store coordinator found, migration will fail");
return NO;
}
NSURL *oldStoreURL = self.persistentStoreURL;
NSPersistentStore *oldStore = [coordinater persistentStoreForURL:oldStoreURL];
NSString *oldThumbnailPath = self.thumbnailFolderPath;
self.libraryBasePath = basePath;
NSURL *newURL = self.persistentStoreURL;
NSError *error = nil;
#ifdef DEBUG
// when debugging we want to clean the new base path before doing the migration
NSError *deleteError;
NSDirectoryEnumerator *enumerator = [[NSFileManager defaultManager] enumeratorAtURL:[NSURL fileURLWithPath:basePath] includingPropertiesForKeys:nil options:NSDirectoryEnumerationSkipsSubdirectoryDescendants | NSDirectoryEnumerationSkipsHiddenFiles errorHandler:nil];
for (NSString *pathToDelete in enumerator) {
if (![[NSFileManager defaultManager] removeItemAtPath:pathToDelete error:&deleteError]) {
NSLog(@"Failed to clear object from new base path for migration debugging: %@",deleteError);
}
}
#endif
NSURL *directoryURL = [newURL URLByDeletingLastPathComponent];
if (![[NSFileManager defaultManager] createDirectoryAtURL:directoryURL withIntermediateDirectories:YES attributes:nil error:&error]) {
NSLog(@"Failed to created new directories for url: %@",directoryURL);
}
NSPersistentStore *newStore = [coordinater migratePersistentStore:oldStore
toURL:newURL
options:oldStore.options
withType:oldStore.type
error:&error];
if (!newStore) {
success = NO;
APLog(@"Failed to migrate library to new path with error: %@",error);
} else {
NSString *oldStorePath = [oldStoreURL path];
// remove all sqlite remainings
for (NSString *extension in @[@"",@"-wal",@"-shm"]) {
NSString *path = [oldStorePath stringByAppendingString:extension];
if ([[NSFileManager defaultManager] fileExistsAtPath:path] && ![[NSFileManager defaultManager] removeItemAtPath:path error:&error]) {
NSLog(@"Failed to remove old library with error: %@",error);
}
}
}
NSString *newThumbnailPath = self.thumbnailFolderPath;
if (![[NSFileManager defaultManager] moveItemAtPath:oldThumbnailPath toPath:newThumbnailPath error:&error]) {
success = NO;
APLog(@"Failed to move thumbnails to new path with error: %@",error);
}
if (migrationError != nil && error) {
*migrationError = error;
}
return success;
}
@end
......@@ -38,6 +38,7 @@
#import "MLAlbum.h"
#import "MLFileParserQueue.h"
#import "MLCrashPreventer.h"
#import "MLMediaLibrary+Migration.h"
#import <sys/sysctl.h> // for sysctlbyname
@interface MLMediaLibrary ()
......@@ -56,12 +57,9 @@
@end
#define DEBUG 1
// To debug
#define DELETE_LIBRARY_ON_EACH_LAUNCH 0
// Pref key
static NSString *kLastTVDBUpdateServerTime = @"MLLastTVDBUpdateServerTime";
static NSString *kUpdatedToTheGreatSharkHuntDatabaseFormat = @"upgradedToDatabaseFormat 2.3";
static NSString *kDecrapifyTitles = @"MLDecrapifyTitles";
#if HAVE_BLOCK
......@@ -77,7 +75,7 @@ static NSString *kDecrapifyTitles = @"MLDecrapifyTitles";
+ (void)initialize
{
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults registerDefaults:@{kUpdatedToTheGreatSharkHuntDatabaseFormat : @NO, kDecrapifyTitles : @YES}];
[defaults registerDefaults:@{kDecrapifyTitles : @YES}];
}
+ (id)sharedMediaLibrary
......@@ -85,7 +83,6 @@ static NSString *kDecrapifyTitles = @"MLDecrapifyTitles";
static id sharedMediaLibrary = nil;
if (!sharedMediaLibrary) {
sharedMediaLibrary = [[[self class] alloc] init];
APLog(@"Initializing db in %@", [sharedMediaLibrary databaseFolderPath]);
// Also force to init the crash preventer
// Because it will correctly set up the parser and thumbnail queue
......@@ -94,6 +91,17 @@ static NSString *kDecrapifyTitles = @"MLDecrapifyTitles";
return sharedMediaLibrary;
}
- (instancetype)init
{
self = [super init];
if (self) {
_applicationGroupIdentifier = @"group.org.videolan.vlc-ios";
[self _setupLibraryPathPriorToMigration];
APLog(@"Initializing db in %@", [self databaseFolderPath]);
}
return self;
}
- (void)dealloc
{
if (_managedObjectContext)
......@@ -175,20 +183,6 @@ static NSString *kDecrapifyTitles = @"MLDecrapifyTitles";
return _managedObjectModel;
}
- (NSString *)libraryBasePath
{
if (_libraryBasePath.length == 0) {
int directory = NSLibraryDirectory;
NSArray *paths = NSSearchPathForDirectoriesInDomains(directory, NSUserDomainMask, YES);
NSString *directoryPath = paths.firstObject;
#if DELETE_LIBRARY_ON_EACH_LAUNCH
[[NSFileManager defaultManager] removeItemAtPath:directoryPath error:nil];
#endif
_libraryBasePath = directoryPath;
}
return _libraryBasePath;
}
- (void)setLibraryBasePath:(NSString *)libraryBasePath
{
_libraryBasePath = [libraryBasePath copy];
......@@ -827,123 +821,7 @@ static NSString *kDecrapifyTitles = @"MLDecrapifyTitles";
}
#endif
- (BOOL)libraryNeedsUpgrade
{
if (![[[NSUserDefaults standardUserDefaults] objectForKey:kUpdatedToTheGreatSharkHuntDatabaseFormat] boolValue])
return YES;
return NO;
}
- (void)upgradeLibrary
{
if (![[[NSUserDefaults standardUserDefaults] objectForKey:kUpdatedToTheGreatSharkHuntDatabaseFormat] boolValue])
[self _upgradeLibraryToGreatSharkHuntDatabaseFormat];
}
- (void)_upgradeLibraryToGreatSharkHuntDatabaseFormat
{
[self libraryDidDisappear];
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSFileManager *fileManager = [NSFileManager defaultManager];
/* remove potential empty albums left over by previous releases */
NSArray *collection = [MLAlbum allAlbums];
NSUInteger count = collection.count;
MLAlbum *album;
MLAlbumTrack *track;
NSArray *secondaryCollection;
NSURL *fileURL;
NSUInteger secondaryCount = 0;
NSArray *tertiaryCollection;
NSUInteger tertiaryCount = 0;
NSUInteger emptyAlbumCounter = 0;
NSManagedObjectContext *moc = [self managedObjectContext];
if (!moc) {
[self libraryDidAppear];
if ([self.delegate respondsToSelector:@selector(libraryUpgradeComplete)])
[self.delegate libraryUpgradeComplete];
return;
}
for (NSUInteger x = 0; x < count; x++) {
album = collection[x];
if (album.tracks.count < 1)
[moc deleteObject:album];
else {
secondaryCollection = album.tracks.allObjects;
secondaryCount = secondaryCollection.count;
emptyAlbumCounter = 0;
for (NSUInteger y = 0; y < secondaryCount; y++) {
track = secondaryCollection[y];
tertiaryCollection = track.files.allObjects;
tertiaryCount = tertiaryCollection.count;
for (NSUInteger z = 0; z < tertiaryCount; z++) {
fileURL = [NSURL URLWithString:[(MLFile *)tertiaryCollection[z] url]];
BOOL exists = [fileManager fileExistsAtPath:[fileURL path]];
if (exists)
emptyAlbumCounter++;
else
[album removeTrack:track];
}
}
if (emptyAlbumCounter == 0)
[moc deleteObject:album];
}
}
album = nil;
/* remove potential empty shows left over by previous releases */
collection = [MLShow allShows];
MLShow *show;
MLShowEpisode *showEpisode;
count = collection.count;
for (NSUInteger x = 0; x < count; x++) {
show = collection[x];
if (show.episodes.count < 1)
[moc deleteObject:show];
else {
secondaryCollection = show.episodes.allObjects;
secondaryCount = secondaryCollection.count;
emptyAlbumCounter = 0;
for (NSUInteger y = 0; y < secondaryCount; y++) {
showEpisode = secondaryCollection[y];
tertiaryCollection = showEpisode.files.allObjects;
tertiaryCount = tertiaryCollection.count;
for (NSUInteger z = 0; z < tertiaryCount; z++) {
fileURL = [NSURL URLWithString:[(MLFile *)tertiaryCollection[z] url]];
BOOL exists = [fileManager fileExistsAtPath:[fileURL path]];
if (exists)
emptyAlbumCounter++;
else
[show removeEpisode:showEpisode];
}
}
if (emptyAlbumCounter == 0)
[moc deleteObject:show];
}
}
/* remove duplicates */
NSArray *allFiles = [MLFile allFiles];
NSUInteger allFilesCount = allFiles.count;
NSMutableArray *seenFiles = [[NSMutableArray alloc] initWithCapacity:allFilesCount];
MLFile *currentFile;
NSString *currentFilePath;
for (NSUInteger x = 0; x < allFilesCount; x++) {
currentFile = allFiles[x];
currentFilePath = [currentFile.url stringByReplacingOccurrencesOfString:@"/localhost/" withString:@"//"];
if ([seenFiles containsObject:currentFilePath])
[moc deleteObject:currentFile];
else
[seenFiles addObject:currentFilePath];
}
[defaults setBool:YES forKey:kUpdatedToTheGreatSharkHuntDatabaseFormat];
[defaults synchronize];
[self libraryDidAppear];
if ([self.delegate respondsToSelector:@selector(libraryUpgradeComplete)])
[self.delegate libraryUpgradeComplete];
}
- (void)updateMediaDatabase
{
......@@ -1089,51 +967,15 @@ static NSString *kDecrapifyTitles = @"MLDecrapifyTitles";
[[MLThumbnailerQueue sharedThumbnailerQueue] resume];
}
#pragma mark - path migrations
- (BOOL)migrateLibraryToBasePath:(NSString *)basePath error:(NSError *__autoreleasing *)migrationError
{
BOOL success = YES;
NSPersistentStoreCoordinator *coordinater = [self persistentStoreCoordinator];
if (!coordinater) {
APLog(@"no persistenz store coordinator found, migration will fail");
return NO;
}
NSURL *oldStoreURL = self.persistentStoreURL;
NSPersistentStore *oldStore = [coordinater persistentStoreForURL:oldStoreURL];
NSString *oldThumbnailPath = self.thumbnailFolderPath;
self.libraryBasePath = basePath;
_databaseFolderPath = nil;
_thumbnailFolderPath = nil;
self.persistentStoreURL = nil;
NSURL *newURL = self.persistentStoreURL;
NSError *error = nil;
[[NSFileManager defaultManager] createDirectoryAtPath:[[newURL URLByDeletingLastPathComponent] path] withIntermediateDirectories:YES attributes:nil error:nil];
NSPersistentStore *newStore = [coordinater migratePersistentStore:oldStore
toURL:newURL
options:oldStore.options
withType:oldStore.type
error:&error];
if (!newStore) {
success = NO;
APLog(@"Failed to migrate library to new path with error: %@",error);
} else {
if (![[NSFileManager defaultManager] removeItemAtURL:oldStoreURL error:&error]) {
APLog(@"Failed to remove old library with error: %@",error);
}
}
#pragma mark - migrations
NSString *newThumbnailPath = self.thumbnailFolderPath;
if (![[NSFileManager defaultManager] moveItemAtPath:oldThumbnailPath toPath:newThumbnailPath error:&error]) {
success = NO;
APLog(@"Failed to move thumbnails to new path with error: %@",error);
}
if (migrationError != nil && error) {
*migrationError = error;
}
return success;
- (BOOL)libraryMigrationNeeded
{
return [self _libraryMigrationNeeded];
}
- (void)migrateLibrary
{
[self _migrateLibrary];
}
@end
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment