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 <[email protected]>
_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits