Skip to content

Commit

Permalink
Merge branch 'master' into TIMOB-26895
Browse files Browse the repository at this point in the history
  • Loading branch information
keerthi1032 committed May 17, 2019
2 parents 475cf27 + 1194af4 commit 8a24496
Show file tree
Hide file tree
Showing 19 changed files with 658 additions and 102 deletions.
6 changes: 4 additions & 2 deletions Jenkinsfile
Original file line number Diff line number Diff line change
Expand Up @@ -108,8 +108,10 @@ def unitTests(os, nodeVersion, npmVersion, testSuiteBranch) {
} finally {
// Kill the emulators!
if ('android'.equals(os)) {
sh returnStatus: true, script: 'adb -e shell am force-stop com.appcelerator.testApp.testing'
sh returnStatus: true, script: 'adb -e uninstall com.appcelerator.testApp.testing'
timeout(5) {
sh returnStatus: true, script: 'adb -e shell am force-stop com.appcelerator.testApp.testing'
sh returnStatus: true, script: 'adb -e uninstall com.appcelerator.testApp.testing'
}
killAndroidEmulators()
} // if
} // finally
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,13 @@
import org.appcelerator.titanium.TiApplication;
import org.appcelerator.titanium.TiFileProxy;
import org.appcelerator.titanium.io.TiBaseFile;
import org.appcelerator.titanium.io.TiFile;
import org.appcelerator.titanium.io.TiFileFactory;
import org.appcelerator.titanium.util.TiConvert;
import org.appcelerator.titanium.util.TiUrl;

import android.content.Context;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.net.Uri;

@Kroll.module
public class DatabaseModule extends KrollModule
Expand All @@ -53,101 +53,150 @@ public DatabaseModule()
@Kroll.method
public TiDatabaseProxy open(Object file)
{
TiDatabaseProxy dbp = null;

try {
if (file instanceof TiFileProxy) {
TiFileProxy tiFile = (TiFileProxy) file;
String absolutePath = tiFile.getBaseFile().getNativeFile().getAbsolutePath();
Log.d(TAG, "Opening database from filesystem: " + absolutePath);
// Acquire database name or file object providing full file path from argument.
TiBaseFile dbTiBaseFile = null;
String dbName = null;
if (file instanceof TiFileProxy) {
// We were given a file proxy. Fetch its file object.
dbTiBaseFile = ((TiFileProxy) file).getBaseFile();
} else if (file instanceof String) {
String fileString = (String) file;
if (fileString.startsWith(File.separator)) {
// Assume we were given an absolute file system path.
dbTiBaseFile = TiFileFactory.createTitaniumFile(fileString, false);
} else if (Uri.parse(fileString).getScheme() != null) {
// We were given a URL. Box it in a Titanium file object if it's a known file scheme.
if (TiFileFactory.isLocalScheme(fileString)) {
dbTiBaseFile = TiFileFactory.createTitaniumFile(fileString, false);
}
if (dbTiBaseFile == null) {
throw new IllegalArgumentException("Ti.Database.open() was given invalid URL: " + fileString);
}
} else {
// Assume we were given a databas file name only. (This is the most common case.)
dbName = fileString;
}
} else if (file != null) {
throw new IllegalArgumentException("Ti.Database.open() argument must be of type 'String' or 'File'.");
} else {
throw new IllegalArgumentException("Ti.Database.open() was given a null argument.");
}

SQLiteDatabase db = SQLiteDatabase.openDatabase(
absolutePath, null, SQLiteDatabase.CREATE_IF_NECESSARY | SQLiteDatabase.NO_LOCALIZED_COLLATORS);
// Attempt to create/open the given database file/name.
TiDatabaseProxy dbp = null;
if (dbTiBaseFile != null) {
// We were given a file object. Fetch its absolute path and open the database there.
String absolutePath = null;
if (dbTiBaseFile instanceof TiFile) {
File actualFile = ((TiFile) dbTiBaseFile).getFile();
if (actualFile != null) {
absolutePath = actualFile.getAbsolutePath();
}
}
if (absolutePath == null) {
String message = "Ti.Database.open() was given invalid path: " + dbTiBaseFile.nativePath();
throw new IllegalArgumentException(message);
}
Log.d(TAG, "Opening database from filesystem: " + absolutePath);
SQLiteDatabase db = SQLiteDatabase.openDatabase(
absolutePath, null, SQLiteDatabase.CREATE_IF_NECESSARY | SQLiteDatabase.NO_LOCALIZED_COLLATORS);
if (db != null) {
dbp = new TiDatabaseProxy(db);
} else {
String name = TiConvert.toString(file);
SQLiteDatabase db = TiApplication.getInstance().openOrCreateDatabase(name, Context.MODE_PRIVATE, null);
dbp = new TiDatabaseProxy(name, db);
throw new RuntimeException("SQLiteDatabase.openDatabase() returned null for path: " + absolutePath);
}

Log.d(TAG, "Opened database: " + dbp.getName(), Log.DEBUG_MODE);

} catch (SQLException e) {
String msg = "Error opening database: " + dbp.getName() + " msg=" + e.getMessage();
Log.e(TAG, msg, e);
throw e;
} else if (dbName != null) {
// We were given a database name only. Open it under app's default database directory.
SQLiteDatabase db = TiApplication.getInstance().openOrCreateDatabase(dbName, Context.MODE_PRIVATE, null);
if (db != null) {
dbp = new TiDatabaseProxy(dbName, db);
} else {
throw new RuntimeException("Context.openOrCreateDatabase() returned null for name: " + dbName);
}
} else {
throw new IllegalArgumentException("Ti.Database.open() failed to extract path from argument: " + file);
}

// Return a proxy to the opened database.
Log.d(TAG, "Opened database: " + dbp.getName(), Log.DEBUG_MODE);
return dbp;
}

@Kroll.method
public TiDatabaseProxy install(KrollInvocation invocation, String url, String name) throws IOException
{
try {
Context ctx = TiApplication.getInstance();
for (String dbname : ctx.databaseList()) {
if (dbname.equals(name)) {
return open(name);
}
}
// open an empty one to get the full path and then close and delete it
if (name.startsWith("appdata://")) {
String path = name.substring(10);
if (path != null && path.length() > 0 && path.charAt(0) == '/') {
path = path.substring(1);
}
File f = new File(TiFileFactory.getDataDirectory(false), path);
name = f.getAbsolutePath();
}

File dbPath = ctx.getDatabasePath(name);
// Validate arguments.
if ((url == null) || url.isEmpty()) {
throw new IllegalArgumentException("Ti.Database.install() 1st argument must be a non-empty string.");
}
if ((name == null) || name.isEmpty()) {
throw new IllegalArgumentException("Ti.Database.install() 2nd argument must be a non-empty string.");
}

Log.d(TAG, "db path is = " + dbPath, Log.DEBUG_MODE);
Log.d(TAG, "db url is = " + url, Log.DEBUG_MODE);
// Do not continue if the database has already been installed.
// Open a connection to it and stop here.
Context ctx = TiApplication.getInstance();
for (String dbname : ctx.databaseList()) {
if (dbname.equals(name)) {
return open(name);
}
}

// Fetch a path to the source database file. This is the file to be copied/installed.
// Throw an exception if the source database was not found.
Log.d(TAG, "db url is = " + url, Log.DEBUG_MODE);
String resolveUrl = url;
if (invocation != null) {
TiUrl tiUrl = TiUrl.createProxyUrl(invocation.getSourceUrl());
String path = TiUrl.resolve(tiUrl.baseUrl, url, null);
resolveUrl = TiUrl.resolve(tiUrl.baseUrl, url, null);
}
TiBaseFile srcDb = TiFileFactory.createTitaniumFile(resolveUrl, false);
if (srcDb.isFile() == false) {
String message = "Ti.Database.install() failed to find 1st argument's source database file: " + url;
throw new java.io.FileNotFoundException(message);
}

TiBaseFile srcDb = TiFileFactory.createTitaniumFile(path, false);
// If target DB path/name is a URL such as "file://" or "appdata://", then turn it into a file system path.
// Note: Normally you would set this to a file name, but Android also supports absolute file systems paths.
if (Uri.parse(name).getScheme() != null) {
boolean wasSuccessful = false;
if (TiFileFactory.isLocalScheme(name)) {
TiBaseFile tiBaseFile = TiFileFactory.createTitaniumFile(name, false);
if (tiBaseFile instanceof TiFile) {
File file = ((TiFile) tiBaseFile).getFile();
if (file != null) {
name = file.getAbsolutePath();
wasSuccessful = true;
}
}
}
if (!wasSuccessful) {
String message = "Ti.Database.install() 2nd argument was given invalid destination path: " + name;
throw new IllegalArgumentException(message);
}
}

Log.d(TAG, "new url is = " + url, Log.DEBUG_MODE);
// Set up the destination path that the source database file will be copied to.
File dbPath = ctx.getDatabasePath(name);
Log.d(TAG, "db path is = " + dbPath, Log.DEBUG_MODE);

if (srcDb.isFile()) {
InputStream is = null;
OutputStream os = null;
// Create the destination directory tree if it doesn't exist.
dbPath.getParentFile().mkdirs();

byte[] buf = new byte[8096];
int count = 0;
try {
is = new BufferedInputStream(srcDb.getInputStream());
os = new BufferedOutputStream(new FileOutputStream(dbPath));
// Copy the source database file to the destination directory. (ie: Do the install.)
try (InputStream inputStream = new BufferedInputStream(srcDb.getInputStream());
OutputStream outputStream = new BufferedOutputStream(new FileOutputStream(dbPath))) {

while ((count = is.read(buf)) != -1) {
os.write(buf, 0, count);
}
} finally {
try {
is.close();
} catch (Exception ig) {
}
try {
os.close();
} catch (Exception ig) {
}
}
byte[] byteBuffer = new byte[8096];
int byteCount = 0;
while ((byteCount = inputStream.read(byteBuffer)) > 0) {
outputStream.write(byteBuffer, 0, byteCount);
}
return open(name);

} catch (SQLException e) {
String msg = "Error installing database: " + name + " msg=" + e.getMessage();
Log.e(TAG, msg, e);
throw e;
} catch (IOException e) {
String msg = "Error installing database: " + name + " msg=" + e.getMessage();
Log.e(TAG, msg, e);
throw e;
outputStream.flush();
}

// Open a connection to the installed database.
return open(name);
}

@Override
Expand Down
2 changes: 2 additions & 0 deletions apidoc/lib/changes_generator.js
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,8 @@ exports.exportData = function exportChanges (apis) {
endVersion = apis.__endVersion || null,
changed = null;

common.createMarkdown(apis);

common.log(common.LOG_INFO, 'Checking API versions...');

for (className in apis) {
Expand Down
85 changes: 81 additions & 4 deletions apidoc/lib/common.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,14 @@ const yaml = require('js-yaml'),
fs = require('fs'),
colors = require('colors'), // eslint-disable-line no-unused-vars
nodeappc = require('node-appc'),
pagedown = require('pagedown'),
converter = new pagedown.Converter(),
MarkdownIt = require('markdown-it'),
ignoreList = [ 'node_modules', '.travis.yml' ],
LOG_INFO = 0,
LOG_WARN = LOG_INFO + 1,
LOG_ERROR = LOG_WARN + 1;

let logLevel = LOG_INFO;
let md;

exports.VALID_PLATFORMS = [ 'android', 'blackberry', 'iphone', 'ipad', 'windowsphone' ];
exports.VALID_OSES = [ 'android', 'blackberry', 'ios', 'windowsphone' ];
Expand Down Expand Up @@ -61,7 +61,10 @@ exports.REGEXP_CHEVRON_LINKS = /(?!`)<[^>]+?>(?!`)/g;
* @return {string} HTML
*/
exports.markdownToHTML = function markdownToHTML(text) {
return converter.makeHtml(text);
if (!md) {
throw new Error('Markdown parser not initalized. Call "createMarkdown" before trying to render any markdown.');
}
return md.render(text).trim();
};

exports.LOG_INFO = LOG_INFO;
Expand Down Expand Up @@ -216,7 +219,7 @@ exports.parseYAML = function parseYAML(path) {
* @param {Object} type sub-type of class?
* @return {boolean} true if found, false otherwise
*/
exports.findAPI = function (doc, className, memberName, type) {
exports.findAPI = function findAPI(doc, className, memberName, type) {
var cls = doc[className],
x = 0;

Expand All @@ -229,3 +232,77 @@ exports.findAPI = function (doc, className, memberName, type) {
}
return false;
};

exports.createMarkdown = function createMarkdown(doc) {
const typeLinkPattern = /^<([a-zA-Z][a-zA-Z0-9._]+)>/;
md = new MarkdownIt({
html: true
});
md.use(typeAutolinkPlugin);

/**
* Adds a new rule to the inline parser to automatically create link tokens
* for types, e.g. `<Titanium.UI.View>`.
*
* @param {MarkdownIt} md markdown-it parser instance
*/
function typeAutolinkPlugin(md) {
md.inline.ruler.after('autolink', 'type-autolink', (state, silent) => {
const pos = state.pos;
if (state.src.charCodeAt(pos) !== 0x3C/* < */) {
return false;
}

const tail = state.src.slice(pos);
if (tail.indexOf('>') === -1) {
return false;
}

if (typeLinkPattern.test(tail)) {
const linkMatch = tail.match(typeLinkPattern);
const url = linkMatch[0].slice(1, -1);
if (!isValidType(url)) {
return false;
}
if (!silent) {
let token;
token = state.push('link_open', 'a', 1);
token.attrs = [ [ 'href', url ] ];
token.markup = 'autolink';
token.info = 'auto';

token = state.push('text', '', 0);
token.content = url;

token = state.push('link_close', 'a', -1);
token.markup = 'autolink';
token.info = 'auto';
}
state.pos += linkMatch[0].length;
return true;
}

return false;
});
}

function isValidType(apiName) {
if (apiName in doc) {
return true;
}

if (apiName.indexOf('.') === -1) {
return false;
}

const member = apiName.split('.').pop();
const cls = apiName.substring(0, apiName.lastIndexOf('.'));

if (!(cls in doc) && !apiName.startsWith('Modules.')) {
return false;
}

const memberTypeCandidates = [ 'properties', 'methods', 'events' ];
return memberTypeCandidates.some(memberType => exports.findAPI(doc, cls, member, memberType));
}
};
1 change: 1 addition & 0 deletions apidoc/lib/html_generator.js
Original file line number Diff line number Diff line change
Expand Up @@ -519,6 +519,7 @@ exports.exportData = function exportHTML(apis) {
property: []
};
doc = apis;
common.createMarkdown(doc);

common.log(common.LOG_INFO, 'Annotating HTML-specific attributes...');

Expand Down
1 change: 1 addition & 0 deletions apidoc/lib/jsca_generator.js
Original file line number Diff line number Diff line change
Expand Up @@ -334,6 +334,7 @@ exports.exportData = function exportJSCA(apis) {
aliases: [ { type: 'Titanium', name: 'Ti' } ]
};
doc = apis; // TODO make doc a field on a type, rather than this weird file-global!
common.createMarkdown(doc);

common.log(common.LOG_INFO, 'Annotating JSCA-specific attributes...');

Expand Down

0 comments on commit 8a24496

Please sign in to comment.