Updated Branches: refs/heads/master f81a76231 -> 011f84210
[CB-4544] Adds a --query flag to query the user for their password when we need it - Rewrite the run script for maintenance Reviewed By: Bryan Higgins <[email protected]> Tested By: Tracy Li <[email protected]> Project: http://git-wip-us.apache.org/repos/asf/cordova-blackberry/repo Commit: http://git-wip-us.apache.org/repos/asf/cordova-blackberry/commit/011f8421 Tree: http://git-wip-us.apache.org/repos/asf/cordova-blackberry/tree/011f8421 Diff: http://git-wip-us.apache.org/repos/asf/cordova-blackberry/diff/011f8421 Branch: refs/heads/master Commit: 011f8421082ecbe14cb4226610d3cd0a652d8199 Parents: f81a762 Author: Jeffrey Heifetz <[email protected]> Authored: Thu Aug 15 10:24:05 2013 -0400 Committer: Jeffrey Heifetz <[email protected]> Committed: Thu Aug 29 09:41:15 2013 -0400 ---------------------------------------------------------------------- blackberry10/.gitignore | 1 + blackberry10/bin/lib/utils.js | 34 +- .../templates/project/cordova/lib/localize.js | 3 + .../bin/templates/project/cordova/lib/run | 439 ++++++++++--------- .../project/cordova/lib/target-utils.js | 40 +- blackberry10/package.json | 4 +- 6 files changed, 291 insertions(+), 230 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/cordova-blackberry/blob/011f8421/blackberry10/.gitignore ---------------------------------------------------------------------- diff --git a/blackberry10/.gitignore b/blackberry10/.gitignore index a87ff43..bd46f91 100644 --- a/blackberry10/.gitignore +++ b/blackberry10/.gitignore @@ -18,6 +18,7 @@ build/ dist/ bin/node_modules bin/templates/project/lib +bin/templates/project/cordova/lib/utils.js example/ node_modules/ .tmp http://git-wip-us.apache.org/repos/asf/cordova-blackberry/blob/011f8421/blackberry10/bin/lib/utils.js ---------------------------------------------------------------------- diff --git a/blackberry10/bin/lib/utils.js b/blackberry10/bin/lib/utils.js index 627cbdd..9831223 100644 --- a/blackberry10/bin/lib/utils.js +++ b/blackberry10/bin/lib/utils.js @@ -20,6 +20,7 @@ var fs = require('fs'), wrench = require('wrench'), localize = require("./localize"), os = require('os'), + prompt = require("prompt"), DEFAULT_BAR_NAME = "bb10app", PROPERTY_FILE_NAME = 'blackberry10.json', CORDOVA_DIR = '.cordova', @@ -234,7 +235,7 @@ _self = { i; for (i = 0; i < args.length; i++) { - if (args[i].indexOf(" ") !== -1) { + if (args[i] && args[i].indexOf(" ") !== -1) { if (!_self.isWindows()) { //remove any escaped spaces on non-Windows platforms and simply use quotes args[i] = args[i].replace(/\\ /g, " "); @@ -247,6 +248,8 @@ _self = { //delete _customOptions from options object before sending to exec delete options._customOptions; + //Use the process env by default + options.env = options.env || process.env; proc = childProcess.exec(args.join(" "), options, callback); @@ -301,6 +304,35 @@ _self = { genBarName: function () { return DEFAULT_BAR_NAME; + }, + + clone: function (original) { + var clone = {}; + if (typeof original !== "object") { + clone = original; + } else if (Array.isArray(original)) { + clone =original.slice(); + } else { + for (var prop in original) { + clone[prop] = original[prop]; + } + } + + return clone; + }, + prompt: function (options, done) { + var promptSchema = { + properties: { + "property": options + } + }; + prompt.start(); + prompt.colors = false; + prompt.message = ""; + prompt.delimiter = ""; + prompt.get(promptSchema, function (err, results) { + done(err, results.property); + }); } }; http://git-wip-us.apache.org/repos/asf/cordova-blackberry/blob/011f8421/blackberry10/bin/templates/project/cordova/lib/localize.js ---------------------------------------------------------------------- diff --git a/blackberry10/bin/templates/project/cordova/lib/localize.js b/blackberry10/bin/templates/project/cordova/lib/localize.js index d51629a..df260f8 100755 --- a/blackberry10/bin/templates/project/cordova/lib/localize.js +++ b/blackberry10/bin/templates/project/cordova/lib/localize.js @@ -198,6 +198,9 @@ var Localize = require("localize"), }, "PROGRESS_GENERATING_DEBUG_TOKEN": { "en": "Generating debug token" + }, + "WARN_RUN_DEVICE_OVERIDES_EMULATOR": { + "en": "Skipping emulator detection and detecting device. Please provide only 1 of --target, --device, and --emulator" } }, "", ""); // TODO maybe a bug in localize, must set default locale to "" in order get it to work http://git-wip-us.apache.org/repos/asf/cordova-blackberry/blob/011f8421/blackberry10/bin/templates/project/cordova/lib/run ---------------------------------------------------------------------- diff --git a/blackberry10/bin/templates/project/cordova/lib/run b/blackberry10/bin/templates/project/cordova/lib/run index 63b7d24..1375859 100755 --- a/blackberry10/bin/templates/project/cordova/lib/run +++ b/blackberry10/bin/templates/project/cordova/lib/run @@ -27,30 +27,26 @@ var childProcess = require("child_process"), 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, + async = require("async"), + properties = utils.getProperties(), workingdir = path.normalize(__dirname + "/.."); -function generateOptions(uninstall) { +function generateOptions(deployTarget, uninstall) { var options = [], - barPath = pkgrUtils.escapeStringForShell(path.normalize(__dirname + "/../../build/" + targets.targets[target].type + "/" + utils.genBarName() + ".bar")); + barPath = pkgrUtils.escapeStringForShell( + path.normalize(__dirname + "/../../build/" + + (deployTarget.type === "device" ? "device" : "simulator") + + "/" + utils.genBarName() + ".bar")); options.push("-device"); - options.push(ip); + options.push(deployTarget.ip); - if (password) { + if (deployTarget.password) { options.push("-password"); - options.push(password); + options.push(deployTarget.password); } options.push("-package"); @@ -80,12 +76,12 @@ function execNativeDeploy(options, callback) { }, callback); } -function checkDeviceInfo(ip, deviceType, callback) { +function checkDeviceInfo(ip, deviceType, devicePass, done) { var props = utils.getProperties(), targetName; - targetUtils.getDeviceInfo(ip, program["devicepass"], function (device) { - if (device.name) { + targetUtils.getDeviceInfo(ip, devicePass, function (err, device) { + if (!err) { targetName = device.name + "-" + device.pin; props.targets[targetName] = { ip: ip, @@ -93,239 +89,262 @@ function checkDeviceInfo(ip, deviceType, callback) { 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); } + done(err, targetName); }); } -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); +function getTargetName (done) { + var ipFinder = program.device ? targetUtils.findConnectedDevice : targetUtils.findConnectedSimulator, + targetType = program.device ? "device" : "emulator"; + + if (program.target) { + done(null, program.target); + } else if (program.device || program.emulator) { + if (program.device && program.emulator) { + localize.translate("WARN_RUN_DEVICE_OVERIDES_EMULATOR"); + } + + async.series( + { + ip: function (done) { + ipFinder(function (ip) { + done(null, ip); + }); + }, + devicePass: function (done) { + if (!program.devicepass && program.devicepass !== "") { + if (program.query) { + utils.prompt({description: "Please enter your " + targetType + " password: ", hidden: true}, done); + } else { + done("Please provide device password using --devicepass"); + } + } else { + done(null, program.devicepass); + } + } + }, + function (err, results) { + if (err) { + done(err); + } else if (!results.ip) { + done("No connected BlackBerry 10 " + targetType + " found"); + } else { + program.devicepass = results.devicePass; + checkDeviceInfo(results.ip, targetType, results.devicePass, done); + } } - }); + ); } else { - callback(); + done(null, properties.defaultTarget); } } -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; + +function validateTarget(targetName, allDone) { + var deployTarget, + err, + runTasks = []; + + if (!targetName) { + err = "No target exists, to add that target please run target add <name> <ip> [-t | --type <device | simulator>] [-p <password>] [--pin <devicepin>]"; + } else if (!properties.targets[targetName]) { + err = "The target \"" + targetName + "\" does not exist, to add that target please run target add " + targetName + " <ip> [-t | --type <device | simulator>] [-p <password>] [--pin <devicepin>]"; } else { - password = program["devicepass"]; + deployTarget = utils.clone(properties.targets[targetName]); + deployTarget.name = targetName; + + if (!deployTarget.ip) { + if (program.query) { + runTasks.push(function (done) { + utils.prompt({description: "Please enter the IP address for target " + deployTarget.name + ": "}, function (e, ip) { + deployTarget.ip = ip; + done(e); + }); + }); + } else { + err = "IP is not defined in target \"" + target + "\""; + } + } + + if (!deployTarget.password && deployTarget.password !== "") { + if (program.devicepass || program.devicepass === "") { + deployTarget.password = program.devicepass; + } else { + if (program.query) { + runTasks.push(function (done) { + utils.prompt({description: "Please enter your " + deployTarget.type + " password: ", hidden: true}, function (e, devicePass) { + deployTarget.password = devicePass; + done(e); + }); + }); + } else { + err = "Please provide device password using --devicepass or add one to the target " + deployTarget.name + " defined at " + utils.getPropertiesFilePath(); + } + } + } } - return true; -} -function deploy() { - var options = generateOptions(false); - execNativeDeploy(options, function (code) { - if (code) { - process.exit(2); - } else { - process.exit(0); + async.series(runTasks, function (e) { + var finalErr = err || e; + if (!finalErr && deployTarget) { + logger.info("Target " + deployTarget.name + " selected"); } + allDone(err || e, deployTarget); }); } -function uninstall() { +function uninstall(deployTarget, allDone) { var script = path.join(process.env.CORDOVA_BBTOOLS, "blackberry-deploy"), args = [ "-listInstalledApps", "-device", - ip, - "-password", - password - ]; + deployTarget.ip + ], + projectRootDir = path.normalize(path.join(__dirname, "..")), + installedAppsOutput, + runTasks = []; - 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(); - }); + if (program.uninstall) { + if (deployTarget.password) { + args.push("-password", deployTarget.password); + } + runTasks = [ + utils.exec.bind(this, script, args, { "cwd": projectRootDir, _customOptions: {silent: true}}), + function listInstalledAppsOutput (stdout, stderr, done) { + installedAppsOutput = stdout; + fs.readFile(path.join(__dirname + "/../../www/", "config.xml"), done); + }, + function configXMLOutput (result, done) { + var parser = new xml2js.Parser(); + parser.parseString(result, done); + }, + function parsedConfigXMLOutput (result, done) { + if (installedAppsOutput.indexOf(result['@'].id) !== -1) { + var options = generateOptions(deployTarget, true); + execNativeDeploy(options, done); } else { - deploy(); + done(); } - }); - }); - }); + } + + ] + } + + async.waterfall(runTasks, + function (err, results) { + //Absorb error for uninstallation + allDone(null, deployTarget); + } + ); } -function checkDebugtoken(previous, baton) { - baton.take(); +function handleDebugToken(deployTarget, allDone) { + program.keystorepass = program.keystorepass || properties.keystorepass; // 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 + if (deployTarget.pin) { + async.waterfall( + [ + debugTokenHelper.checkDebugToken.bind(this, deployTarget.pin), + function (done) { + //If no keystorepass is provided debugTokenHelper will throw an error. + if (!program.keystorepass && program.query) { + utils.prompt({description: "Please enter your keystore password: ", hidden: true}, function (err, result) { + program.keystorepass = result; + done(err, result); + }); + } else { + done(program.keystorepass); + } + }, + debugTokenHelper.createToken.bind(this, properties, "all") + + ], + function (err, results) { + // If the error is true, then the debug token is valid and creation was skipped. + if (err === true) { logger.info(localize.translate("PROGRESS_DEBUG_TOKEN_IS_VALID")); - needDeployDebugToken = true; - } else { - needCreateDebugToken = true; + //Clear the error so it is still deployed + err = null; } - 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; + if (!err) { + debugTokenHelper.deployToken(deployTarget.name, deployTarget.ip, deployTarget.password, function (code) { + allDone(code, deployTarget); + }); + } else { + allDone(err); } - - baton.pass(); - }); + } + ); } else { - baton.pass(); + allDone(null, deployTarget); } } -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 install(deployTarget, done) { + var buildCmd = utils.isWindows() ? "build" : "./build", + buildArgs = program.keystorepass ? ["-k", program.keystorepass] : [], + projectRootDir = path.normalize(path.join(__dirname, "..")); + + async.series( + [ + utils.exec.bind(this, buildCmd, buildArgs, {"cwd": projectRootDir}), + uninstall.bind(this, deployTarget), + execNativeDeploy.bind(this, generateOptions(deployTarget)) + ], + done + ); } -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(); - } -} +program + .usage('[--device] [--emulator] [--target=<id>] [--query] [-k | --keystorepass] [-devicepass] [--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 <id>', 'specifies the target to run the application') + .option('--query', 'query on the commandline when a password is needed') + .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') + .on('--help', function() { + console.log(' Examples:'); + console.log(''); + console.log(" Deploying to a predefined target"); + console.log(' $ run --target=Z10'); + console.log(" Deploying to a connected device"); + console.log(' $ run --device --devicepass devicePassword --keystorepass keystorePassword'); + console.log(''); + }); -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)); +process.argv.forEach(function (argument, index, args) { + if (argument.match(/^--target=/)) { + args.splice(index, 1, "--target", argument.substr("--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(); +}); + +program.parse(process.argv); + +async.waterfall( + [ + getTargetName, + validateTarget, + handleDebugToken, + install + ], + function (err) { + if (err) { + if (typeof err === "string") { + logger.error(err); + process.exit(1); + } else if (typeof err === "number") { + process.exit(err); } } else { - process.exit(1); + process.exit(0); } - }); -} - -exec(); + } +); http://git-wip-us.apache.org/repos/asf/cordova-blackberry/blob/011f8421/blackberry10/bin/templates/project/cordova/lib/target-utils.js ---------------------------------------------------------------------- diff --git a/blackberry10/bin/templates/project/cordova/lib/target-utils.js b/blackberry10/bin/templates/project/cordova/lib/target-utils.js index af95296..3e83200 100644 --- a/blackberry10/bin/templates/project/cordova/lib/target-utils.js +++ b/blackberry10/bin/templates/project/cordova/lib/target-utils.js @@ -80,7 +80,8 @@ _self = { } bb10_utils.exec(cmd, args, options, function (error, stdout, stderr) { - var result = {}, + var err = error, + result = {}, name = /modelname::(.*?)(\r?)\n/.exec(stdout), pin = /devicepin::0x(.*?)(\r?)\n/.exec(stdout); if (name && name.length > 0) { @@ -90,30 +91,33 @@ _self = { result.pin = pin[1]; } - callback(result); + if (!result.name) { + if (stdout.indexOf("Error:") !== -1) { + err = stdout.slice(stdout.indexOf("Error:") + 6); + } else if (stdout === "" && stderr.indexOf("Error:") === 0) { + err = stderr.slice(7); + } else { + err = "Unable to authenticate with BlackBerry 10 device/emulator at " + ip + "."; + } + } + + callback(err, result); }); }, findConnectedDevice: function (callback) { var defaultIp = '169.254.0.1'; _self.discoverUsb(function (result) { - if (result) { - _self.checkConnection(result, 'device', function (connection) { - if (connection) { - callback(result); - } else { - callback(); - } - }); - } else { - _self.checkConnection(defaultIp, 'device', function (connection) { - if (connection) { - callback(defaultIp); - } else { - callback(); - } - }); + if (!result) { + result = defaultIp; } + _self.checkConnection(result, 'device', function (connection) { + if (connection) { + callback(result); + } else { + callback(); + } + }); }); }, http://git-wip-us.apache.org/repos/asf/cordova-blackberry/blob/011f8421/blackberry10/package.json ---------------------------------------------------------------------- diff --git a/blackberry10/package.json b/blackberry10/package.json index 166c66a..2185b89 100644 --- a/blackberry10/package.json +++ b/blackberry10/package.json @@ -26,7 +26,9 @@ "validator": "0.4.1", "wrench": "1.3.9", "shelljs":"0.1.3", - "elementtree": "0.1.5" + "elementtree": "0.1.5", + "prompt": "0.2.11", + "async": "0.2.9" }, "devDependencies": { "jake":"*",
