Brion VIBBER has uploaded a new change for review.

  https://gerrit.wikimedia.org/r/129307

Change subject: Work in progress: data migration from old app
......................................................................

Work in progress: data migration from old app

Extracts the list of saved pages from the old app at app startup,
but doesn't yet do anything but dump them to console log.

Change-Id: I1dc4e230c2dc8320528045081fc834e4c992e992
---
M Wikipedia.xcodeproj/project.pbxproj
M wikipedia/AppDelegate.m
A wikipedia/DataMigrator.h
A wikipedia/DataMigrator.m
A wikipedia/SQLiteHelper.h
A wikipedia/SQLiteHelper.m
6 files changed, 332 insertions(+), 0 deletions(-)


  git pull ssh://gerrit.wikimedia.org:29418/apps/ios/wikipedia 
refs/changes/07/129307/1

diff --git a/Wikipedia.xcodeproj/project.pbxproj 
b/Wikipedia.xcodeproj/project.pbxproj
index 708eaee..df58833 100644
--- a/Wikipedia.xcodeproj/project.pbxproj
+++ b/Wikipedia.xcodeproj/project.pbxproj
@@ -192,6 +192,9 @@
                D499144C181D51DE00E6073C /* Main_iPhone.storyboard in Resources 
*/ = {isa = PBXBuildFile; fileRef = D499144A181D51DE00E6073C /* 
Main_iPhone.storyboard */; };
                D4991454181D51DE00E6073C /* Images.xcassets in Resources */ = 
{isa = PBXBuildFile; fileRef = D4991453181D51DE00E6073C /* Images.xcassets */; 
};
                D4BC22B4181E9E6300CAC673 /* empty.png in Resources */ = {isa = 
PBXBuildFile; fileRef = D4BC22B3181E9E6300CAC673 /* empty.png */; };
+               D4E8A8A4190835C100DA4765 /* DataMigrator.m in Sources */ = {isa 
= PBXBuildFile; fileRef = D4E8A8A3190835C100DA4765 /* DataMigrator.m */; };
+               D4E8A8A719084F1300DA4765 /* SQLiteHelper.m in Sources */ = {isa 
= PBXBuildFile; fileRef = D4E8A8A619084F1300DA4765 /* SQLiteHelper.m */; };
+               D4E8A8A919085CEA00DA4765 /* libsqlite3.dylib in Frameworks */ = 
{isa = PBXBuildFile; fileRef = D4E8A8A819085CEA00DA4765 /* libsqlite3.dylib */; 
};
                D4EE00B9182443FC0090790F /* MWPageTitle.m in Sources */ = {isa 
= PBXBuildFile; fileRef = D4EE00B8182443FC0090790F /* MWPageTitle.m */; };
 /* End PBXBuildFile section */
 
@@ -638,6 +641,11 @@
                D4991466181D51DF00E6073C /* Wikipedia_Tests.m */ = {isa = 
PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = 
Wikipedia_Tests.m; sourceTree = "<group>"; };
                D4BC22B3181E9E6300CAC673 /* empty.png */ = {isa = 
PBXFileReference; lastKnownFileType = image.png; path = empty.png; sourceTree = 
"<group>"; };
                D4DE203018283FF200148CA2 /* CommunicationBridgeTests.m */ = 
{isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = 
sourcecode.c.objc; path = CommunicationBridgeTests.m; sourceTree = "<group>"; };
+               D4E8A8A2190835C100DA4765 /* DataMigrator.h */ = {isa = 
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = 
DataMigrator.h; sourceTree = "<group>"; };
+               D4E8A8A3190835C100DA4765 /* DataMigrator.m */ = {isa = 
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path 
= DataMigrator.m; sourceTree = "<group>"; };
+               D4E8A8A519084F1300DA4765 /* SQLiteHelper.h */ = {isa = 
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = 
SQLiteHelper.h; sourceTree = "<group>"; };
+               D4E8A8A619084F1300DA4765 /* SQLiteHelper.m */ = {isa = 
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path 
= SQLiteHelper.m; sourceTree = "<group>"; };
+               D4E8A8A819085CEA00DA4765 /* libsqlite3.dylib */ = {isa = 
PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = 
libsqlite3.dylib; path = usr/lib/libsqlite3.dylib; sourceTree = SDKROOT; };
                D4EE00B7182443FC0090790F /* MWPageTitle.h */ = {isa = 
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = 
MWPageTitle.h; path = "mw-support/MWPageTitle.h"; sourceTree = "<group>"; };
                D4EE00B8182443FC0090790F /* MWPageTitle.m */ = {isa = 
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name 
= MWPageTitle.m; path = "mw-support/MWPageTitle.m"; sourceTree = "<group>"; };
                D4EE00BC1824459D0090790F /* PageTitleTests.m */ = {isa = 
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name 
= PageTitleTests.m; path = "mw-support/PageTitleTests.m"; sourceTree = 
"<group>"; };
@@ -648,6 +656,7 @@
                        isa = PBXFrameworksBuildPhase;
                        buildActionMask = 2147483647;
                        files = (
+                               D4E8A8A919085CEA00DA4765 /* libsqlite3.dylib in 
Frameworks */,
                                04D34DB21863D39000610A87 /* libxml2.dylib in 
Frameworks */,
                                D499143B181D51DE00E6073C /* 
CoreGraphics.framework in Frameworks */,
                                D499143D181D51DE00E6073C /* UIKit.framework in 
Frameworks */,
@@ -1253,6 +1262,7 @@
                D4991437181D51DE00E6073C /* Frameworks */ = {
                        isa = PBXGroup;
                        children = (
+                               D4E8A8A819085CEA00DA4765 /* libsqlite3.dylib */,
                                04D34DB11863D39000610A87 /* libxml2.dylib */,
                                040E5C4E184566F4007AFE6F /* CoreData.framework 
*/,
                                D4991438181D51DE00E6073C /* 
Foundation.framework */,
@@ -1276,6 +1286,7 @@
                                045A9F0C18F6090E0057EA85 /* assets */,
                                04C43AB7183442FC006C643B /* Categories */,
                                040E5C50184673F2007AFE6F /* Data */,
+                               D4E8A8A11908357600DA4765 /* Data Migration */,
                                04292FFB185FC026002A13FC /* Defines */,
                                0442F57C1900718600F55DF9 /* Fonts */,
                                04D34DA31863D2D600610A87 /* HTML Parsing */,
@@ -1334,6 +1345,17 @@
                                D4991463181D51DF00E6073C /* InfoPlist.strings 
*/,
                        );
                        name = "Supporting Files";
+                       sourceTree = "<group>";
+               };
+               D4E8A8A11908357600DA4765 /* Data Migration */ = {
+                       isa = PBXGroup;
+                       children = (
+                               D4E8A8A2190835C100DA4765 /* DataMigrator.h */,
+                               D4E8A8A3190835C100DA4765 /* DataMigrator.m */,
+                               D4E8A8A519084F1300DA4765 /* SQLiteHelper.h */,
+                               D4E8A8A619084F1300DA4765 /* SQLiteHelper.m */,
+                       );
+                       name = "Data Migration";
                        sourceTree = "<group>";
                };
                D4EE00BB182445670090790F /* mw-support */ = {
@@ -1577,6 +1599,7 @@
                                04D34D97186216AF00610A87 /* 
MainMenuViewController.m in Sources */,
                                0433543718A1A7AE009305F0 /* NavController.m in 
Sources */,
                                0447866F1852B5010050563B /* SessionSingleton.m 
in Sources */,
+                               D4E8A8A4190835C100DA4765 /* DataMigrator.m in 
Sources */,
                                04D34DD11863F6E600610A87 /* SectionImage.m in 
Sources */,
                                0447867C1852BBFE0050563B /* 
NSManagedObjectContext+SimpleFetch.m in Sources */,
                                04AE1C741891BB32002D5487 /* Article.m in 
Sources */,
@@ -1630,6 +1653,7 @@
                                04F0E2EE186FB2D100468738 /* 
TOCSectionCellView.m in Sources */,
                                04D122321899B8AC006B9A30 /* AlertWebView.m in 
Sources */,
                                D4991449181D51DE00E6073C /* AppDelegate.m in 
Sources */,
+                               D4E8A8A719084F1300DA4765 /* SQLiteHelper.m in 
Sources */,
                                04F39590186CF80100B0D6FC /* TOCViewController.m 
in Sources */,
                                04D75824189248E900CE2040 /* 
DownloadLangLinksOp.m in Sources */,
                                04B91AB218E406FB00FFAA1C /* MainMenuRowView.m 
in Sources */,
diff --git a/wikipedia/AppDelegate.m b/wikipedia/AppDelegate.m
index c2aacdf..e6f4598 100644
--- a/wikipedia/AppDelegate.m
+++ b/wikipedia/AppDelegate.m
@@ -3,6 +3,7 @@
 
 #import "AppDelegate.h"
 #import "URLCache.h"
+#import "DataMigrator.h"
 
 @implementation AppDelegate
 
@@ -25,6 +26,19 @@
     //[[NSUserDefaults standardUserDefaults] synchronize];
 
     // Override point for customization after application launch.
+    
+    // This probably belongs elsewhere... maybe tie it into one of the main 
pages on the nav stack.
+    DataMigrator *dataMigrator = [[DataMigrator alloc] init];
+    if ([dataMigrator hasData]) {
+        NSLog(@"Old data to migrate found!");
+        NSArray *titles = [dataMigrator extractSavedPages];
+        for (NSDictionary *item in titles) {
+            NSLog(@"Need to import saved page: %@ %@", item[@"lang"], 
item[@"title"]);
+        }
+    } else {
+        NSLog(@"No pld data to migrate.");
+    }
+
     return YES;
 }
 
diff --git a/wikipedia/DataMigrator.h b/wikipedia/DataMigrator.h
new file mode 100644
index 0000000..786fd16
--- /dev/null
+++ b/wikipedia/DataMigrator.h
@@ -0,0 +1,34 @@
+//
+//  DataMigrator.h
+//  Wikipedia
+//
+//  Created by Brion on 4/23/14.
+//  Copyright (c) 2014 Wikimedia Foundation. Some rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+
+@interface DataMigrator : NSObject
+
+- (id)init;
+
+/**
+ * Is there anything that needs to be migrated?
+ */
+- (BOOL)hasData;
+
+/**
+ * Return the extracted JSON blobs from the savedPagesDB database table.
+ * Each contains 'lang', 'title', and 'key' strings.
+ *
+ * @return (NSArray *) of (NSDictionary *)s.
+ */
+- (NSArray *)extractSavedPages;
+
+/**
+ * Delete the old files.
+ * @todo implement this
+ */
+- (void)removeOldData;
+
+@end
diff --git a/wikipedia/DataMigrator.m b/wikipedia/DataMigrator.m
new file mode 100644
index 0000000..98fdb5b
--- /dev/null
+++ b/wikipedia/DataMigrator.m
@@ -0,0 +1,105 @@
+//
+//  DataMigrator.m
+//  Wikipedia
+//
+//  Created by Brion on 4/23/14.
+//  Copyright (c) 2014 Wikimedia Foundation. Some rights reserved.
+//
+
+#import "DataMigrator.h"
+#import "SQLiteHelper.h"
+
+@implementation DataMigrator
+{
+    SQLiteHelper *masterDB;
+    SQLiteHelper *savedPagesDB;
+}
+
+#pragma mark - Public methods
+
+- (id)init
+{
+    self = [super init];
+    if (self) {
+        NSString *dbPath = [self localLibraryPath:@"Caches/Databases.db"];
+        if ([[NSFileManager defaultManager] fileExistsAtPath:dbPath]) {
+            NSLog(@"Opening sqlite database from %@", dbPath);
+            masterDB = [[SQLiteHelper alloc] initWithPath:dbPath];
+        }
+    }
+    return self;
+}
+
+- (BOOL)hasData
+{
+    return (masterDB != NULL);
+}
+
+- (NSArray *)extractSavedPages
+{
+    NSMutableArray *arr = [[NSMutableArray alloc] init];
+    for (NSDictionary *row in [self fetchRawSavedPages]) {
+        NSString *jsonString = row[@"value"];
+        NSData *jsonBlob = [jsonString dataUsingEncoding:NSUTF8StringEncoding];
+        NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:jsonBlob 
options:0 error:nil];
+        [arr addObject:dict];
+    }
+    return [NSArray arrayWithArray:arr];
+}
+
+- (void)removeOldData
+{
+    if ([self hasData]) {
+        NSLog(@"todo: implement removeOldData in DataMigrator");
+    }
+}
+
+#pragma mark - Private methods
+
+/**
+ * Return absolute path for relative path to the installed app's documents 
folder.
+ */
+- (NSString *)localDocumentPath:(NSString *)local
+{
+    return [[self documentRootPath] stringByAppendingPathComponent:local];
+}
+
+- (NSString *)documentRootPath
+{
+    NSArray* documentPaths = 
NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
+    NSString* documentRootPath = [documentPaths objectAtIndex:0];
+    return documentRootPath;
+}
+
+/**
+ * Return absolute path for relative path to the installed app's Library 
folder.
+ */
+- (NSString *)localLibraryPath:(NSString *)local
+{
+    return [[self libraryRootPath] stringByAppendingPathComponent:local];
+}
+
+- (NSString *)libraryRootPath
+{
+    NSArray* libraryPaths = 
NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES);
+    NSString* libraryRootPath = [libraryPaths objectAtIndex:0];
+    return libraryRootPath;
+}
+
+- (NSArray *)fetchRawSavedPages
+{
+    savedPagesDB = [self openDatabaseWithName:@"savedPagesDB"];
+    return [savedPagesDB query:@"SELECT value FROM savedPagesDB" params:nil];
+}
+
+- (SQLiteHelper *)openDatabaseWithName:(NSString *)dbname
+{
+    NSArray *rows = [masterDB query:@"SELECT origin, path FROM Databases WHERE 
name=?" params:@[dbname]];
+    NSDictionary *row = rows[0];
+    NSLog(@"row: %@", row);
+    NSString *path = [[[self localLibraryPath:@"Caches"] 
stringByAppendingPathComponent:row[@"origin"]] 
stringByAppendingPathComponent:row[@"path"]];
+    NSLog(@"opening path %@", path);
+    return [[SQLiteHelper alloc] initWithPath:path];
+}
+
+@end
diff --git a/wikipedia/SQLiteHelper.h b/wikipedia/SQLiteHelper.h
new file mode 100644
index 0000000..5a4bb2a
--- /dev/null
+++ b/wikipedia/SQLiteHelper.h
@@ -0,0 +1,16 @@
+//
+//  SQLiteHelper.h
+//  Wikipedia
+//
+//  Created by Brion on 4/23/14.
+//  Copyright (c) 2014 Wikimedia Foundation. Some rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+
+@interface SQLiteHelper : NSObject
+
+- (id)initWithPath:(NSString *)path;
+- (NSArray *)query:(NSString *)query params:(NSArray *)params;
+
+@end
diff --git a/wikipedia/SQLiteHelper.m b/wikipedia/SQLiteHelper.m
new file mode 100644
index 0000000..73334ee
--- /dev/null
+++ b/wikipedia/SQLiteHelper.m
@@ -0,0 +1,139 @@
+//
+//  SQLiteHelper.m
+//  Wikipedia
+//
+//  Created by Brion on 4/23/14.
+//  Copyright (c) 2014 Wikimedia Foundation. All rights reserved.
+//
+
+#import "SQLiteHelper.h"
+#import <sqlite3.h>
+
+#define SQLITE_THROW(x) {\
+    int sqlite_errno = (x); \
+    if (sqlite_errno != SQLITE_OK) { \
+        @throw [NSException exceptionWithName:@"SQLiteHelperException" \
+                                       reason:[NSString 
stringWithUTF8String:sqlite3_errmsg(_database)] \
+                                     userInfo:@{@"sqlite_errno": [NSNumber 
numberWithInt:sqlite_errno]}]; \
+    } \
+}
+
+@implementation SQLiteHelper
+{
+    sqlite3 *_database;
+}
+
+- (id)initWithPath:(NSString *)path {
+    self = [super init];
+    if (self) {
+        SQLITE_THROW(sqlite3_open([path UTF8String], &_database));
+    }
+    return self;
+}
+
+- (void)dealloc {
+    SQLITE_THROW(sqlite3_close(_database));
+}
+
+/**
+ * Return an array of dictionaries for each matching row
+ */
+- (NSArray *)query:(NSString *)query params:(NSArray *)params
+{
+    sqlite3_stmt *statement;
+    SQLITE_THROW(sqlite3_prepare_v2(_database, [query UTF8String], -1, 
&statement, nil));
+    if (params) {
+        [self bindParams:params statement:statement];
+    }
+    
+    NSMutableArray *rows = [[NSMutableArray alloc] init];
+    
+    while (true) {
+        int ret = sqlite3_step(statement);
+        if (ret == SQLITE_ROW) {
+            NSDictionary *row = [self extractRowFromStatement:statement];
+            [rows addObject: row];
+        } else if (ret == SQLITE_DONE) {
+            // We're done!
+            break;
+        } else {
+            SQLITE_THROW(ret);
+        }
+    }
+    
+    SQLITE_THROW(sqlite3_finalize(statement));
+    
+    return rows;
+}
+
+#pragma mark - Private methods
+
+- (void)bindParams:(NSArray *)params statement:(sqlite3_stmt *)statement
+{
+    for (int i = 0; i < [params count]; i++) {
+        int col = i + 1;
+        NSObject *param = params[i];
+        if ([param isKindOfClass:[NSString class]]) {
+            NSString *str = (NSString *)param;
+            SQLITE_THROW(sqlite3_bind_text(statement, col, [str UTF8String], 
-1, nil));
+        } else {
+            @throw [NSException exceptionWithName:@"SQLiteHelperException"
+                                           reason:@"Unimplemented type in 
SQLHelper bindParams:statement:"
+                                         userInfo:@{}];
+        }
+    }
+}
+
+- (NSDictionary *)extractRowFromStatement:(sqlite3_stmt *)statement
+{
+    NSMutableDictionary *row = [[NSMutableDictionary alloc] init];
+    
+    int columnCount = sqlite3_column_count(statement);
+    for (int i = 0; i < columnCount; i++) {
+        int col = i;
+        NSString *name = [NSString 
stringWithUTF8String:sqlite3_column_name(statement, col)];
+        NSObject *value;
+        switch (sqlite3_column_type(statement, col)) {
+            case SQLITE_INTEGER:
+                value = [NSNumber numberWithInt:sqlite3_column_int(statement, 
col)];
+                break;
+            case SQLITE_FLOAT:
+                value = [NSNumber 
numberWithDouble:sqlite3_column_double(statement, col)];
+                break;
+            case SQLITE_TEXT:
+            {
+                const char *bytes = (const char 
*)sqlite3_column_text(statement, col);
+                int nbytes = sqlite3_column_bytes(statement, col);
+                if (nbytes > 0) {
+                    value = [NSString stringWithUTF8String:bytes];
+                } else {
+                    value = @"";
+                }
+                break;
+            }
+            case SQLITE_BLOB:
+            {
+                const char *bytes = sqlite3_column_blob(statement, col);
+                int nbytes = sqlite3_column_bytes(statement, col);
+                if (nbytes > 0) {
+                    value = [NSData dataWithBytes:bytes length:nbytes];
+                } else {
+                    value = [[NSData alloc] init];
+                }
+                break;
+            }
+            case SQLITE_NULL:
+                value = [NSNull null];
+                break;
+            default:
+                @throw [NSException exceptionWithName:@"SQLiteHelperException"
+                                               reason:@"Unimplmemented column 
type in SQLHelper extractRowFromStatement:"
+                                             userInfo:@{}];
+        }
+        row[name] = value;
+    }
+    
+    return [NSDictionary dictionaryWithDictionary:row];
+}
+
+@end

-- 
To view, visit https://gerrit.wikimedia.org/r/129307
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: I1dc4e230c2dc8320528045081fc834e4c992e992
Gerrit-PatchSet: 1
Gerrit-Project: apps/ios/wikipedia
Gerrit-Branch: master
Gerrit-Owner: Brion VIBBER <br...@wikimedia.org>

_______________________________________________
MediaWiki-commits mailing list
MediaWiki-commits@lists.wikimedia.org
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to