You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cordova.apache.org by fi...@apache.org on 2013/06/07 03:31:17 UTC

[10/22] git commit: npm version 2.8.5. [CB-3612] added run command. Cleaned up some tests , removed some duplicate specs, added run specs. Updated help documentation. Updated commands invoked by cordova-cli (compile->./cordova/build, emulate->./cordova/em

npm version 2.8.5. [CB-3612] added run command. Cleaned up some tests ,removed some duplicate specs, added run specs. Updated help documentation. Updated commands invoked by cordova-cli (compile->./cordova/build, emulate->./cordova/emulate)


Project: http://git-wip-us.apache.org/repos/asf/cordova-cli/repo
Commit: http://git-wip-us.apache.org/repos/asf/cordova-cli/commit/05196b36
Tree: http://git-wip-us.apache.org/repos/asf/cordova-cli/tree/05196b36
Diff: http://git-wip-us.apache.org/repos/asf/cordova-cli/diff/05196b36

Branch: refs/heads/2.8.x
Commit: 05196b3671422b6d917fcc0ea68d6ae209250bd1
Parents: 1a40e10
Author: Fil Maj <ma...@gmail.com>
Authored: Wed Jun 5 11:54:31 2013 -0700
Committer: Fil Maj <ma...@gmail.com>
Committed: Thu Jun 6 18:29:03 2013 -0700

----------------------------------------------------------------------
 bin/cordova                                  |    2 +-
 cordova.js                                   |    2 +
 doc/help.txt                                 |   27 +++--
 package.json                                 |    2 +-
 spec/cordova-cli/compile.spec.js             |   74 +++++------
 spec/cordova-cli/create.spec.js              |    2 +
 spec/cordova-cli/emulate.spec.js             |   57 +++++----
 spec/cordova-cli/run.spec.js                 |  138 +++++++++++++++++++++
 spec/platform-script/android/android.spec.js |   10 --
 spec/platform-script/ios/ios.spec.js         |   10 --
 src/compile.js                               |   13 +--
 src/create.js                                |    2 +
 src/emulate.js                               |    6 +-
 src/run.js                                   |  101 +++++++++++++++
 14 files changed, 332 insertions(+), 114 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/05196b36/bin/cordova
----------------------------------------------------------------------
diff --git a/bin/cordova b/bin/cordova
index 941f461..17b3569 100755
--- a/bin/cordova
+++ b/bin/cordova
@@ -33,7 +33,7 @@ if (version) {
     var r;
     if (cmd == 'create' || cmd == 'docs' || cmd == 'serve') {
         r = cordova[cmd].apply(this, opts);
-    } else if (cmd == 'emulate' || cmd == 'build' || cmd == 'prepare' || cmd == 'compile') {
+    } else if (cmd == 'emulate' || cmd == 'build' || cmd == 'prepare' || cmd == 'compile' || cmd == 'run') {
         r = cordova[cmd].call(this, opts);
     } else {
         // platform or plugin cmds

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/05196b36/cordova.js
----------------------------------------------------------------------
diff --git a/cordova.js b/cordova.js
index 73d3a64..efdc4b2 100644
--- a/cordova.js
+++ b/cordova.js
@@ -19,6 +19,7 @@
 var cordova_events = require('./src/events'),
     prepare        = require('./src/prepare'),
     platform       = require('./src/platform'),
+    run            = require('./src/run'),
     hooker         = require('./src/hooker'),
     util           = require('./src/util'),
     path           = require('path'),
@@ -40,6 +41,7 @@ module.exports = {
     platforms: platform,
     prepare:   prepare,
     compile:   compile,
+    run:       run,
     emulate:   require('./src/emulate'),
     plugin:    require('./src/plugin'),
     plugins:   require('./src/plugin'),

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/05196b36/doc/help.txt
----------------------------------------------------------------------
diff --git a/doc/help.txt b/doc/help.txt
index fea484c..73510d0 100644
--- a/doc/help.txt
+++ b/doc/help.txt
@@ -5,23 +5,30 @@ Synopsis
 Global Commands
 
     create [path] [id] [name] ......... creates a cordova project in the specified directory optional name and id (package name, reverse-domain style)
-    -v ................................ prints out this utility's version
 
 Project-Level Commands
 
     platform(s) [add|remove|ls [name]] ... adds or removes a platform, or lists all currently-added platforms
     plugin(s) [add|remove|ls [path]] ..... adds or removes a plugin (from the specified path), or lists all currently-added plugins
-    prepare [platform...] ............. copies files into the specified platforms, or all platforms.
-                                        it is then ready for building by Eclipse/Xcode/etc.
-    compile [platform...] ............. builds the app for the specified (or all) platforms
-    build ............................. alias for prepare and then compile
-    emulate ........................... starts emulator for cordova project
-    serve <platform> [port] ........... runs a local web server for the www/ directory of the given platform
+    prepare [platform...] ................ copies files into the specified platforms, or all platforms
+                                        it is then ready for building by Eclipse/Xcode/etc
+    compile [platform...] ................ builds the app for the specified (or all) platforms
+    build [platform...]................... alias for prepare and then compile
+    emulate [platform...] ................ starts emulator for the specified (or all) platforms, then deploys application to emulator 
+    run [platform...] .................... deployes the application to the specified (or all) platform devices, which must be
+                                        connected and configured for running via your machine
+    serve <platform> [port] .............. runs a local web server for the www/ directory of the given platform
                                         the default port is 8000
                                         note that you must edit the native code to point at the server!
-    ripple <platform> [port] .......... uses the serve command as a base and then wraps the server
-                                        with ripple to test your app in your desktop browser.
-    help .............................. shows this!
+    ripple <platform> [port] ............. uses the serve command as a base and then wraps the server
+                                        with ripple to test your app in your desktop browser
+    help ................................. shows this!
+
+Command-line Flags/Options
+
+    -v, --version ......................... prints out this utility's version
+    -d, --verbose ......................... debug, or verbose, mode. Makes this utility very chatty, logging everything it does, including
+                                        redirecting output of commands it shells out to back to stdout
 
 Example usage
 

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/05196b36/package.json
----------------------------------------------------------------------
diff --git a/package.json b/package.json
index 82db18f..f3d386c 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
   "name": "cordova",
-  "version": "2.8.4",
+  "version": "2.8.5",
   "preferGlobal": "true",
   "description": "Cordova command line interface tool",
   "main": "cordova",

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/05196b36/spec/cordova-cli/compile.spec.js
----------------------------------------------------------------------
diff --git a/spec/cordova-cli/compile.spec.js b/spec/cordova-cli/compile.spec.js
index 814d2ab..bd7dc42 100644
--- a/spec/cordova-cli/compile.spec.js
+++ b/spec/cordova-cli/compile.spec.js
@@ -35,53 +35,49 @@ describe('compile command', function() {
         shell.mkdir('-p', tempDir);
     });
 
-    it('should not run inside a Cordova-based project with no added platforms', function() {
-        this.after(function() {
+    describe('failure', function() {
+        afterEach(function() {
             process.chdir(cwd);
+            spyOn(shell, 'exec');
         });
-
-        cordova.create(tempDir);
-        process.chdir(tempDir);
-        expect(function() {
-            cordova.compile();
-        }).toThrow();
-    });
-    
-    it('should run inside a Cordova-based project with at least one added platform', function() {
-        // move platform project fixtures over to fake cordova into thinking platforms were added
-        // TODO: possibly add this to helper?
-        // Just make a folder instead of moving the whole platform? 
-        shell.mkdir('-p', tempDir);
-        shell.mv('-f', path.join(cordova_project, 'platforms', 'android'), path.join(tempDir));
-        this.after(function() {
-            process.chdir(cwd);
-            shell.mv('-f', path.join(tempDir, 'android'), path.join(cordova_project, 'platforms', 'android'));
+        it('should not run inside a Cordova-based project with no added platforms', function() {
+            cordova.create(tempDir);
+            process.chdir(tempDir);
+            expect(function() {
+                cordova.compile();
+            }).toThrow();
+        });
+        it('should not run outside of a Cordova-based project', function() {
+            shell.mkdir('-p', tempDir);
+            process.chdir(tempDir);
+            expect(function() {
+                cordova.compile();
+            }).toThrow();
         });
-
-        process.chdir(cordova_project);
-
-        var sh_spy = spyOn(shell, 'exec');
-
-        expect(function() {
-            cordova.compile();
-            expect(sh_spy).toHaveBeenCalled();
-        }).not.toThrow();
     });
-    it('should not run outside of a Cordova-based project', function() {
-        this.after(function() {
+
+    describe('success', function() {
+        beforeEach(function() {
+            cordova.create(tempDir);
+            shell.cp('-Rf', path.join(cordova_project, 'platforms', 'android'), path.join(tempDir, 'platforms'));
+            process.chdir(tempDir);
+        });
+        afterEach(function() {
             process.chdir(cwd);
         });
+        it('should run inside a Cordova-based project with at least one added platform', function() {
+            // move platform project fixtures over to fake cordova into thinking platforms were added
+            // TODO: possibly add this to helper?
+            var sh_spy = spyOn(shell, 'exec');
 
-        shell.mkdir('-p', tempDir);
-        process.chdir(tempDir);
-
-        // we don't actually want it building the project (if it does somehow exist)
-        var sh_spy = spyOn(shell, 'exec');
-
-        expect(function() {
-            cordova.compile();
-        }).toThrow();
+            expect(function() {
+                cordova.compile();
+                expect(sh_spy).toHaveBeenCalled();
+                expect(sh_spy.mostRecentCall.args[0]).toMatch(/cordova.build"$/gi);
+            }).not.toThrow();
+        });
     });
+
     /* Is this a repeat of the util.spec.js test? */
     it('should not treat a .gitignore file as a platform', function() {
         var gitignore = path.join(cordova_project, 'platforms', '.gitignore');

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/05196b36/spec/cordova-cli/create.spec.js
----------------------------------------------------------------------
diff --git a/spec/cordova-cli/create.spec.js b/spec/cordova-cli/create.spec.js
index 8a31ed6..4dad502 100644
--- a/spec/cordova-cli/create.spec.js
+++ b/spec/cordova-cli/create.spec.js
@@ -42,6 +42,8 @@ describe('create command', function () {
         expect(fs.existsSync(path.join(hooks, 'after_emulate'))).toBe(true);
         expect(fs.existsSync(path.join(hooks, 'before_docs'))).toBe(true);
         expect(fs.existsSync(path.join(hooks, 'after_docs'))).toBe(true);
+        expect(fs.existsSync(path.join(hooks, 'before_run'))).toBe(true);
+        expect(fs.existsSync(path.join(hooks, 'after_run'))).toBe(true);
     });
     it('should throw if the directory is already a cordova project', function() {
         shell.mkdir('-p', path.join(tempDir, '.cordova'));

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/05196b36/spec/cordova-cli/emulate.spec.js
----------------------------------------------------------------------
diff --git a/spec/cordova-cli/emulate.spec.js b/spec/cordova-cli/emulate.spec.js
index a3e5136..64464cb 100644
--- a/spec/cordova-cli/emulate.spec.js
+++ b/spec/cordova-cli/emulate.spec.js
@@ -37,43 +37,44 @@ describe('emulate command', function() {
         cordova.create(tempDir);
     });
 
-    it('should not run inside a Cordova-based project with no added platforms', function() {
-        this.after(function() {
+    describe('failure', function() {
+        afterEach(function() {
             process.chdir(cwd);
         });
+        it('should not run inside a Cordova-based project with no added platforms', function() {
+            process.chdir(tempDir);
+            expect(function() {
+                cordova.emulate();
+            }).toThrow();
+        });
+        it('should not run outside of a Cordova-based project', function() {
+            shell.mkdir('-p', tempDir);
+            process.chdir(tempDir);
 
-        process.chdir(tempDir);
-        expect(function() {
-            cordova.emulate();
-        }).toThrow();
-    });
-    
-    it('should run inside a Cordova-based project with at least one added platform', function() {
-        this.after(function() {
-            process.chdir(cwd);
+            expect(function() {
+                cordova.emulate();
+            }).toThrow();
         });
+    });
 
-        var s = spyOn(shell, 'exec');
-        var a_spy = spyOn(android_parser.prototype, 'update_project');
-        expect(function() {
+    describe('success', function() {
+        beforeEach(function() {
             shell.cp('-Rf', path.join(cordova_project, 'platforms', 'android'), path.join(tempDir, 'platforms'));
             process.chdir(tempDir);
-            cordova.emulate();
-            a_spy.mostRecentCall.args[1](); // fake out android parser
-            expect(s).toHaveBeenCalled();
-        }).not.toThrow();
-    });
-    it('should not run outside of a Cordova-based project', function() {
-        this.after(function() {
+        });
+        afterEach(function() {
             process.chdir(cwd);
         });
-
-        shell.mkdir('-p', tempDir);
-        process.chdir(tempDir);
-
-        expect(function() {
-            cordova.emulate();
-        }).toThrow();
+        it('should run inside a Cordova-based project with at least one added platform', function() {
+            var s = spyOn(shell, 'exec');
+            var a_spy = spyOn(android_parser.prototype, 'update_project');
+            expect(function() {
+                cordova.emulate();
+                a_spy.mostRecentCall.args[1](); // fake out android parser
+                expect(s).toHaveBeenCalled();
+                expect(s.mostRecentCall.args[0]).toMatch(/cordova.emulate"$/gi);
+            }).not.toThrow();
+        });
     });
 
     describe('hooks', function() {

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/05196b36/spec/cordova-cli/run.spec.js
----------------------------------------------------------------------
diff --git a/spec/cordova-cli/run.spec.js b/spec/cordova-cli/run.spec.js
new file mode 100644
index 0000000..fb4da30
--- /dev/null
+++ b/spec/cordova-cli/run.spec.js
@@ -0,0 +1,138 @@
+/**
+    Licensed to the Apache Software Foundation (ASF) under one
+    or more contributor license agreements.  See the NOTICE file
+    distributed with this work for additional information
+    regarding copyright ownership.  The ASF licenses this file
+    to you 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 cordova = require('../../cordova'),
+    et = require('elementtree'),
+    shell = require('shelljs'),
+    path = require('path'),
+    fs = require('fs'),
+    config_parser = require('../../src/config_parser'),
+    android_parser = require('../../src/metadata/android_parser'),
+    hooker = require('../../src/hooker'),
+    fixtures = path.join(__dirname, '..', 'fixtures'),
+    hooks = path.join(fixtures, 'hooks'),
+    tempDir = path.join(__dirname, '..', '..', 'temp'),
+    cordova_project = path.join(fixtures, 'projects', 'cordova');
+
+var cwd = process.cwd();
+
+describe('run command', function() {
+    beforeEach(function() {
+        shell.rm('-rf', tempDir);
+        cordova.create(tempDir);
+    });
+
+    describe('failure', function() {
+        afterEach(function() {
+            process.chdir(cwd);
+        });
+        it('should not run inside a Cordova-based project with no added platforms', function() {
+            process.chdir(tempDir);
+            expect(function() {
+                cordova.run();
+            }).toThrow();
+        });
+        it('should not run outside of a Cordova-based project', function() {
+            shell.mkdir('-p', tempDir);
+            process.chdir(tempDir);
+
+            expect(function() {
+                cordova.run();
+            }).toThrow();
+        });
+    });
+    
+    describe('success', function() {
+        beforeEach(function() {
+            shell.cp('-Rf', path.join(cordova_project, 'platforms', 'android'), path.join(tempDir, 'platforms'));
+            process.chdir(tempDir);
+        });
+        afterEach(function() {
+            process.chdir(cwd);
+        });
+        it('should invoke prepare', function() {
+            var spy = spyOn(cordova, 'prepare');
+            spyOn(shell, 'exec');
+            cordova.run();
+            expect(spy).toHaveBeenCalled();
+        });
+        it('should shell out to underlying `run` platform-level scripts', function(done) {
+            spyOn(cordova, 'prepare').andCallFake(function(platforms, callback) {
+                callback(false);
+            });
+            var spy = spyOn(shell, 'exec').andCallFake(function(cmd, options, cb) {
+                cb(0, 'yep');
+            });
+            cordova.run('android', function() {
+                 expect(spy.mostRecentCall.args[0]).toMatch(/cordova.run"$/gi);
+                 done();
+            });
+        });
+    });
+
+
+    describe('hooks', function() {
+        var s;
+        beforeEach(function() {
+            s = spyOn(hooker.prototype, 'fire').andReturn(true);
+        });
+
+        describe('when platforms are added', function() {
+            beforeEach(function() {
+                shell.cp('-Rf', path.join(cordova_project, 'platforms', 'android'), path.join(tempDir, 'platforms'));
+                process.chdir(tempDir);
+            });
+            afterEach(function() {
+                process.chdir(cwd);
+            });
+
+            it('should fire before hooks through the hooker module', function() {
+
+                spyOn(shell, 'exec');
+                cordova.run();
+                expect(hooker.prototype.fire).toHaveBeenCalledWith('before_run');
+            });
+            it('should fire after hooks through the hooker module', function(done) {
+                spyOn(shell, 'exec').andCallFake(function(cmd, options, callback) {
+                    callback(0, 'fucking eh');
+                });
+                cordova.run('android', function() {
+                     expect(hooker.prototype.fire).toHaveBeenCalledWith('after_run');
+                     done();
+                });
+            });
+        });
+
+        describe('with no platforms added', function() {
+            beforeEach(function() {
+                process.chdir(tempDir);
+            });
+            afterEach(function() {
+                process.chdir(cwd);
+            });
+            it('should not fire the hooker', function() {
+                spyOn(shell, 'exec');
+                expect(function() {
+                    cordova.run();
+                }).toThrow();
+                expect(s).not.toHaveBeenCalledWith('before_run');
+                expect(s).not.toHaveBeenCalledWith('after_run');
+            });
+        });
+    });
+});

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/05196b36/spec/platform-script/android/android.spec.js
----------------------------------------------------------------------
diff --git a/spec/platform-script/android/android.spec.js b/spec/platform-script/android/android.spec.js
index 2433c0a..8890276 100644
--- a/spec/platform-script/android/android.spec.js
+++ b/spec/platform-script/android/android.spec.js
@@ -61,16 +61,6 @@ describe('Test:', function() {
         shell.rm('-rf', tempDir);
         cordova.create(tempDir);
         shell.cp('-rf', path.join(cordova_project, 'platforms', 'android'), path.join(tempDir, 'platforms'));
-        it('should shell out to run command on Android', function() {
-            var proj_spy = spyOn(android_parser.prototype, 'update_project');
-            var s = spyOn(require('shelljs'), 'exec');
-            spyOn(require('plugman'), 'prepare');
-            cordova.emulate('android');
-            proj_spy.mostRecentCall.args[1](); // update_project fake
-            expect(s).toHaveBeenCalled();
-            var emulate_cmd = path.join('android', 'cordova', 'run');
-            expect(s.mostRecentCall.args[0]).toContain(emulate_cmd);
-        });
         it('should call android_parser\'s update_project', function() {
             spyOn(require('shelljs'), 'exec');
             spyOn(android_parser.prototype, 'update_project');

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/05196b36/spec/platform-script/ios/ios.spec.js
----------------------------------------------------------------------
diff --git a/spec/platform-script/ios/ios.spec.js b/spec/platform-script/ios/ios.spec.js
index 04ae4bf..2723b83 100644
--- a/spec/platform-script/ios/ios.spec.js
+++ b/spec/platform-script/ios/ios.spec.js
@@ -62,16 +62,6 @@ describe('Test:', function() {
         shell.rm('-rf', tempDir);
         cordova.create(tempDir);
         shell.cp('-rf', path.join(cordova_project, 'platforms', 'ios'), path.join(tempDir, 'platforms'));
-        it('should shell out to run command on ios', function() {
-            var proj_spy = spyOn(ios_parser.prototype, 'update_project');
-            var s = spyOn(require('shelljs'), 'exec');
-            spyOn(require('plugman'), 'prepare');
-            cordova.emulate('ios');
-            proj_spy.mostRecentCall.args[1](); // update_project fake
-            expect(s).toHaveBeenCalled();
-            var emulate_cmd = path.join('ios', 'cordova', 'run');
-            expect(s.mostRecentCall.args[0]).toContain(emulate_cmd);
-        });
         it('should call ios_parser\'s update_project', function() {
             spyOn(require('shelljs'), 'exec');
             spyOn(ios_parser.prototype, 'update_project');

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/05196b36/src/compile.js
----------------------------------------------------------------------
diff --git a/src/compile.js b/src/compile.js
index 1f550f8..8d9d217 100644
--- a/src/compile.js
+++ b/src/compile.js
@@ -27,15 +27,8 @@ var cordova_util      = require('./util'),
     n                 = require('ncallbacks');
 
 
-function shell_out_to_debug(projectRoot, platform, callback) {
-    var cmd = path.join(projectRoot, 'platforms', platform);
-    // TODO: this is bb10 only for now
-    // TODO: PLATFORM LIBRARY INCONSISTENCY
-    if (platform == 'blackberry') {
-        cmd = 'ant -f "' + path.join(cmd, 'build.xml') + '" qnx load-device';
-    } else {
-        cmd = '"' + path.join(cmd, 'cordova', 'build') + '"';
-    }
+function shell_out_to_build(projectRoot, platform, callback) {
+    var cmd = '"' + path.join(projectRoot, 'platforms', platform, 'cordova', 'build') + '"';
     events.emit('log', 'Compiling platform "' + platform + '" with command "' + cmd + '" (output to follow)...');
     shell.exec(cmd, {silent:true, async:true}, function(code, output) {
         events.emit('log', output);
@@ -96,6 +89,6 @@ module.exports = function compile(platformList, callback) {
 
     // Iterate over each added platform
     platformList.forEach(function(platform) {
-        shell_out_to_debug(projectRoot, platform, end);
+        shell_out_to_build(projectRoot, platform, end);
     });
 };

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/05196b36/src/create.js
----------------------------------------------------------------------
diff --git a/src/create.js b/src/create.js
index 5cced50..be9966c 100644
--- a/src/create.js
+++ b/src/create.js
@@ -78,6 +78,7 @@ module.exports = function create (dir, id, name) {
     shell.mkdir(path.join(hooks, 'after_plugin_ls'));
     shell.mkdir(path.join(hooks, 'after_plugin_rm'));
     shell.mkdir(path.join(hooks, 'after_prepare'));
+    shell.mkdir(path.join(hooks, 'after_run'));
     shell.mkdir(path.join(hooks, 'before_build'));
     shell.mkdir(path.join(hooks, 'before_compile'));
     shell.mkdir(path.join(hooks, 'before_docs'));
@@ -89,6 +90,7 @@ module.exports = function create (dir, id, name) {
     shell.mkdir(path.join(hooks, 'before_plugin_ls'));
     shell.mkdir(path.join(hooks, 'before_plugin_rm'));
     shell.mkdir(path.join(hooks, 'before_prepare'));
+    shell.mkdir(path.join(hooks, 'before_run'));
 
     // Write out .cordova/config.json file with a simple json manifest
     fs.writeFileSync(path.join(dotCordova, 'config.json'), JSON.stringify({

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/05196b36/src/emulate.js
----------------------------------------------------------------------
diff --git a/src/emulate.js b/src/emulate.js
index 9ccfc0b..9dd8857 100644
--- a/src/emulate.js
+++ b/src/emulate.js
@@ -31,11 +31,7 @@ var cordova_util      = require('./util'),
     util              = require('util');
 
 function shell_out_to_emulate(root, platform, callback) {
-    var cmd = '"' + path.join(root, 'platforms', platform, 'cordova', 'run') + '"';
-    // TODO: PLATFORM LIBRARY INCONSISTENCY 
-    if (platform == 'blackberry') {
-        cmd = 'ant -f "' + path.join(root, 'platforms', platform, 'build.xml') + '" qnx load-simulator';
-    }
+    var cmd = '"' + path.join(root, 'platforms', platform, 'cordova', 'emulate') + '"';
     events.emit('log', 'Running on emulator for platform "' + platform + '" via command "' + cmd + '" (output to follow)...');
     shell.exec(cmd, {silent:true, async:true}, function(code, output) {
         events.emit('log', output);

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/05196b36/src/run.js
----------------------------------------------------------------------
diff --git a/src/run.js b/src/run.js
new file mode 100644
index 0000000..c13e4ab
--- /dev/null
+++ b/src/run.js
@@ -0,0 +1,101 @@
+/**
+    Licensed to the Apache Software Foundation (ASF) under one
+    or more contributor license agreements.  See the NOTICE file
+    distributed with this work for additional information
+    regarding copyright ownership.  The ASF licenses this file
+    to you 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 cordova_util      = require('./util'),
+    path              = require('path'),
+    config_parser     = require('./config_parser'),
+    fs                = require('fs'),
+    shell             = require('shelljs'),
+    et                = require('elementtree'),
+    hooker            = require('./hooker'),
+    events            = require('./events'),
+    n                 = require('ncallbacks');
+
+function shell_out_to_run(projectRoot, platform, callback) {
+    var cmd = '"' + path.join(projectRoot, 'platforms', platform, 'cordova', 'run') + '"';
+
+    events.emit('log', 'Running app on platform "' + platform + '" with command "' + cmd + '" (output to follow)...');
+    shell.exec(cmd, {silent:true, async:true}, function(code, output) {
+        events.emit('log', output);
+        if (code > 0) {
+            throw new Error('An error occurred while running the ' + platform + ' project. ' + output);
+        } else {
+            events.emit('log', 'Platform "' + platform + '" ran successfully.');
+            if (callback) callback();
+        }
+    });
+}
+
+module.exports = function run(platformList, callback) {
+    var projectRoot = cordova_util.isCordova(process.cwd());
+
+    if (!projectRoot) {
+        var err = new Error('Current working directory is not a Cordova-based project.');
+        if (callback) callback(err);
+        else throw err;
+        return;
+    }
+
+    var xml = cordova_util.projectConfig(projectRoot);
+    var cfg = new config_parser(xml);
+
+    if (arguments.length === 0 || (platformList instanceof Array && platformList.length === 0)) {
+        platformList = cordova_util.listPlatforms(projectRoot);
+    } else if (typeof platformList == 'string') platformList = [platformList];
+    else if (platformList instanceof Function && callback === undefined) {
+        callback = platformList;
+        platformList = cordova_util.listPlatforms(projectRoot);
+    }
+
+    if (platformList.length === 0) {
+        var err = new Error('No platforms added to this project. Please use `cordova platform add <platform>`.');
+        if (callback) callback(err);
+        else throw err;
+        return;
+    }
+
+    var hooks = new hooker(projectRoot);
+    if (!(hooks.fire('before_run'))) {
+        var err = new Error('before_run hooks exited with non-zero code. Aborting.');
+        if (callback) callback(err);
+        else throw err;
+        return;
+    }
+
+    var end = n(platformList.length, function() {
+        if (!(hooks.fire('after_run'))) {
+            var err = new Error('after_run hooks exited with non-zero code. Aborting.');
+            if (callback) callback(err);
+            else throw err;
+            return;
+        }
+        if (callback) callback();
+    });
+
+    // Run a prepare first, then shell out to run
+    require('../cordova').prepare(platformList, function(err) {
+        if (err) {
+            if (callback) callback(err);
+            else throw err;
+        } else {
+            platformList.forEach(function(platform) {
+                shell_out_to_run(projectRoot, platform, end);
+            });
+        }
+    });
+};