blob: 63b7d249090ae4ce404f0b7312cf44f43d3eb3d1 [file] [log] [blame]
#!/usr/bin/env node
/*
* Copyright 2012 Research In Motion Limited.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
var childProcess = require("child_process"),
fs = require("fs"),
path = require("path"),
util = require("util"),
wrench = require("wrench"),
conf = require("./conf"),
utils = require("./utils"),
targetUtils = require("./target-utils.js"),
localize = require("./localize"),
pkgrUtils = require("./packager-utils"),
debugTokenHelper = require("./debugtoken-helper"),
targets = utils.getProperties(),
program = require('commander'),
xml2js = require('xml2js'),
jWorkflow = require("jWorkflow"),
logger = require("./logger"),
pin,
needCreateDebugToken = false,
needDeployDebugToken = false,
commandStr,
target,
ip,
password,
workingdir = path.normalize(__dirname + "/..");
function generateOptions(uninstall) {
var options = [],
barPath = pkgrUtils.escapeStringForShell(path.normalize(__dirname + "/../../build/" + targets.targets[target].type + "/" + utils.genBarName() + ".bar"));
options.push("-device");
options.push(ip);
if (password) {
options.push("-password");
options.push(password);
}
options.push("-package");
options.push(barPath);
if (uninstall) {
options.push("-uninstallApp");
return options;
} else {
options.push("-installApp");
if (program.launch) {
options.push("-launchApp");
}
return options;
}
}
function execNativeDeploy(options, callback) {
var script = path.normalize(path.join(process.env.CORDOVA_BBTOOLS, "blackberry-deploy"));
utils.exec(script, options, {
"cwd": workingdir,
"env": process.env
}, callback);
}
function checkDeviceInfo(ip, deviceType, callback) {
var props = utils.getProperties(),
targetName;
targetUtils.getDeviceInfo(ip, program["devicepass"], function (device) {
if (device.name) {
targetName = device.name + "-" + device.pin;
props.targets[targetName] = {
ip: ip,
pin: device.pin,
type: deviceType
};
utils.writeToPropertiesFile(props);
target = targetName;
callback();
} else {
if (deviceType === "device") {
console.error("Unable to authenticate with device at " + ip);
} else {
console.error("Unable to authenticate with simulator at " + ip);
}
if (!program["devicepass"]) {
console.error("Please provide device password using --devicepass");
}
process.exit(1);
}
});
}
function setTarget(callback) {
target = program.args[0] ? program.args[0] : targets.defaultTarget;
if (program["device"]) {
targetUtils.findConnectedDevice(function (ip) {
if (!ip) {
console.error("No connected device found");
process.exit(1);
} else {
checkDeviceInfo(ip, "device", callback);
}
});
} else if (program["emulator"]) {
targetUtils.findConnectedSimulator(function (ip) {
if (!ip) {
console.error("No connected BlackBerry 10 simulator found");
process.exit(1);
} else {
checkDeviceInfo(ip, "simulator", callback);
}
});
} else {
callback();
}
}
function checkTarget() {
if (!target) {
console.log("No target exists, to add that target please run target add <name> <ip> [-t | --type <device | simulator>] [-p <password>] [--pin <devicepin>]");
console.log(program.helpInformation());
return false;
}
if (!targets.targets[target]) {
console.log("The target \"" + target + "\" does not exist, to add that target please run target add " + target + " <ip> [-t | --type <device | simulator>] [-p <password>] [--pin <devicepin>]");
console.log(program.helpInformation());
return false;
}
if (targets.targets[target].ip) {
ip = targets.targets[target].ip;
} else {
console.log("IP is not defined in target \"" + target + "\"");
console.log(program.helpInformation());
return false;
}
if (targets.targets[target].password) {
password = targets.targets[target].password;
} else {
password = program["devicepass"];
}
return true;
}
function deploy() {
var options = generateOptions(false);
execNativeDeploy(options, function (code) {
if (code) {
process.exit(2);
} else {
process.exit(0);
}
});
}
function uninstall() {
var script = path.join(process.env.CORDOVA_BBTOOLS, "blackberry-deploy"),
args = [
"-listInstalledApps",
"-device",
ip,
"-password",
password
];
utils.exec(script, args, {
"cwd": workingdir,
"env": process.env,
_customOptions: { silent: true}
}, function (error, stdout, stderr) {
var parser = new xml2js.Parser();
fs.readFile(path.join(__dirname + "/../../www/", "config.xml"), function (err, data) {
parser.parseString(data, function (err, result) {
if (stdout.indexOf(result['@'].id) !== -1) {
var options = generateOptions(true);
execNativeDeploy(options, function () {
deploy();
});
} else {
deploy();
}
});
});
});
}
function checkDebugtoken(previous, baton) {
baton.take();
// if target has no pin, skip the debug token feature
if (targets.targets[target].pin) {
debugTokenHelper.checkDebugToken(targets.targets[target].pin, function (valid) {
// If the debug token is not valid, we need create new debug token
if (valid) {
// No need to create the debug token
logger.info(localize.translate("PROGRESS_DEBUG_TOKEN_IS_VALID"));
needDeployDebugToken = true;
} else {
needCreateDebugToken = true;
}
baton.pass();
});
} else {
baton.pass();
}
}
function createDebugToken(previous, baton) {
var keystorepass = program["keystorepass"] ? program["keystorepass"] : targets.keystorepass;
baton.take();
if (needCreateDebugToken) {
debugTokenHelper.createToken(targets, "all", keystorepass, function (error, stdout, stderr) {
if (!error) {
// Deploy the debug token if created
needDeployDebugToken = true;
}
baton.pass();
});
} else {
baton.pass();
}
}
function deployDebugToken(previous, baton) {
baton.take();
// If in debug build and debug token was created, deploy the debug token and wait until the deployment is finished
if (needDeployDebugToken) {
debugTokenHelper.deployToken(target, ip, password, function () {
baton.pass();
});
} else {
baton.pass();
}
}
function handleBuildOutput(data) {
var msg = data.toString().replace(/[\n\r]/g, '');
console.log(msg);
}
function build(previous, baton) {
var execName = utils.isWindows() ? "build" : "./build",
callback = function (code) {
// If error happened during building the bar, exit
if (code === 2) {
process.exit(2);
}
baton.pass();
};
baton.take();
utils.exec(execName, [], {
"cwd": path.normalize(__dirname + "/.."),
"env": process.env
}, callback);
}
function postBuild() {
if (program.uninstall) {
uninstall();
} else {
deploy();
}
}
function exec() {
program
.usage('[--device] [--emulator] [--devicepass] [--target=<id>] [-k | --keystorepass] [--no-launch] [--no-uninstall] [--no-build]')
.option('-k, --keystorepass <password>', 'the password of signing key; needed for creating debug token')
.option('--device', 'run on connected device')
.option('--emulator', 'run on BB10 simulator')
.option('--devicepass <password>', 'device password')
.option('--target', 'specifies the target to run the application')
.option('--no-uninstall', 'does not uninstall application from device')
.option('--no-launch', 'do not launch the application on device')
.option('--no-build', 'deploy the pre-built bar file and skip building');
commandStr = typeof process.argv[2] === "string" ? process.argv[2] : undefined;
if (commandStr && commandStr.indexOf("--target=") === 0) {
// Convert "--target=<id>" into "--target id"
process.argv[2] = "--target";
process.argv.splice(3, 0, commandStr.substring("--target=".length));
}
program.parse(process.argv);
setTarget(function () {
if (checkTarget()) {
if (program.build) {
jWorkflow.order(checkDebugtoken)
.andThen(createDebugToken)
.andThen(deployDebugToken)
.andThen(build)
.andThen(postBuild)
.start();
} else {
postBuild();
}
} else {
process.exit(1);
}
});
}
exec();