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/13 20:22:17 UTC

[54/78] git commit: first pass at lazy loading

first pass at lazy loading


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

Branch: refs/heads/master2
Commit: 944c2e4225af1ecd9d7de395c80b66fec0543a1e
Parents: 67fa7eb
Author: Fil Maj <ma...@gmail.com>
Authored: Mon Jun 10 17:03:17 2013 -0700
Committer: Fil Maj <ma...@gmail.com>
Committed: Thu Jun 13 11:13:20 2013 -0700

----------------------------------------------------------------------
 bootstrap.js                      | 102 --------------------------
 package.json                      |   8 +-
 src/lazy_load.js                  |  94 ++++++++++++++++++++++++
 src/metadata/android_parser.js    |   4 +-
 src/metadata/blackberry_parser.js |   8 +-
 src/metadata/ios_parser.js        |   2 +-
 src/metadata/wp7_parser.js        |   5 +-
 src/metadata/wp8_parser.js        |   7 +-
 src/platform.js                   | 129 ++++++++++++++++++---------------
 src/util.js                       |  33 ++++++---
 test_runner.js                    |   2 +
 11 files changed, 210 insertions(+), 184 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/944c2e42/bootstrap.js
----------------------------------------------------------------------
diff --git a/bootstrap.js b/bootstrap.js
deleted file mode 100644
index 41dc854..0000000
--- a/bootstrap.js
+++ /dev/null
@@ -1,102 +0,0 @@
-/**
-    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.
- **
- * BOOTSTRAP
- * Runs through any bs to make sure the libraries and tests are good to go.
- **/
-
-var util      = require('./src/util'),
-    create    = require('./src/create'),
-    n         = require('ncallbacks'),
-    path      = require('path'),
-    fs        = require('fs'),
-    shell     = require('shelljs'),
-    platforms = require('./platforms');
-
-// Create native projects using bin/create
-var projectFixtures = path.join(__dirname, 'spec', 'fixtures', 'projects');
-var tempDir = path.join(projectFixtures, 'native');
-shell.rm('-rf', tempDir);
-shell.mkdir('-p', tempDir);
-
-// Also create a standard cordova project for tests
-var cordovaDir = path.join(projectFixtures, 'cordova');
-shell.rm('-rf', cordovaDir);
-create(cordovaDir);
-var platformsDir = path.join(cordovaDir, 'platforms');
-// kill the stupid spec shit!
-shell.rm('-rf', path.join(cordovaDir, 'www', 'spec'));
-
-var end = n(Object.keys(platforms).length, function() {
-    // Check that we are installing globally into a root-only directory.
-    if (process.env.USER == 'root') {
-        console.log("**************************************************************************");
-        console.log("* WARNING: YOU ARE INSTALLING GLOBALLY INTO A ROOT-ONLY DIRECTORY!!!1one *");
-        console.log("* Your node install is global, so global modules get installed there too.*");
-        console.log("* You should probably run the following command for this tool to run:    *");
-        console.log("    $ sudo chown -R " + process.env.SUDO_USER + " " + process.env.PWD);
-        console.log("* This will allow you to run this tool globally without using `sudo`.    *");
-        console.log("**************************************************************************");
-    }
-});
-
-Object.keys(platforms).forEach(function(platform) {
-    platforms[platform].parser.check_requirements(function(err) {
-        if (err) {
-            console.error('WARNING: Your system does not meet requirements to create ' + platform + ' projects. See error output below.');
-            console.error(err);
-            console.error('SKIPPING ' + platform + ' bootstrap.');
-            end();
-        } else {
-            console.log('SUCCESS: Minimum requirements for ' + platform + ' met.');
-            var fix_path = path.join(tempDir, platform + '_fixture');
-            var create = path.join(util.libDirectory, 'cordova-' + platform, 'bin', 'create');
-            console.log('BOOTSTRAPPING ' + platform + '...');
-            var cmd = create + ' "' + fix_path + '" org.apache.cordova.cordovaExample cordovaExample';
-            shell.exec(cmd, {silent:true, async:true}, function(code, output) {
-                if (code > 0) {
-                    console.error('ERROR! Could not create a native ' + platform + ' project test fixture. See below for error output.');
-                    console.error(output);
-                } else {
-                    var platformDir = path.join(platformsDir, platform);
-                    // remove extra spec bullshit as it intereferes with jasmine-node
-                    var dub = path.join(fix_path, 'www');
-                    if (platform == 'android') dub = path.join(fix_path, 'assets', 'www');
-                    shell.rm('-rf', path.join(dub, 'spec'));
-                    // copy over to full cordova project test fixture
-                    shell.mkdir('-p', platformDir);
-                    shell.cp('-rf', path.join(fix_path, '*'), platformDir);
-                    shell.mkdir('-p',path.join(util.appDir(cordovaDir),'merges',platform));
-
-                    // set permissions on executables
-                    var scripts_path = path.join(fix_path, 'cordova');
-                    var other_path = path.join(platformDir, 'cordova');
-                    var scripts = fs.readdirSync(scripts_path);
-                    scripts.forEach(function(script) {
-                        var script_path = path.join(scripts_path, script);
-                        var other_script_path = path.join(other_path, script);
-                        shell.chmod('+x', script_path);
-                        shell.chmod('+x', other_script_path);
-                    });
-                    console.log('SUCCESS: ' + platform + ' ready to rock!');
-                }
-                end();
-            });
-        }
-    });
-});

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/944c2e42/package.json
----------------------------------------------------------------------
diff --git a/package.json b/package.json
index b22d925..587cb3b 100644
--- a/package.json
+++ b/package.json
@@ -11,8 +11,7 @@
     "cordova": "./bin/cordova"
   },
   "scripts": {
-    "test": "node test_runner.js",
-    "install": "node bootstrap.js"
+    "test": "jasmine-node --color spec/cordova-cli"
   },
   "repository": {
     "type": "git",
@@ -32,9 +31,12 @@
     "express":"3.0",
     "shelljs":"0.1.2",
     "ncallbacks":"1.0.0",
-    "request":"2.11.4",
+    "request":"2.12.x",
     "semver":"1.1.0",
+    "glob":"3.2.x",
+    "follow-redirects":"0.0.x",
     "prompt":"0.2.7",
+    "tar.gz":"0.1.x",
     "ripple-emulator":">=0.9.15",
     "open": "0.0.3"
   },

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/944c2e42/src/lazy_load.js
----------------------------------------------------------------------
diff --git a/src/lazy_load.js b/src/lazy_load.js
new file mode 100644
index 0000000..688e101
--- /dev/null
+++ b/src/lazy_load.js
@@ -0,0 +1,94 @@
+/**
+    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 path          = require('path'),
+    fs            = require('fs'),
+    shell         = require('shelljs'),
+    platforms     = require('../platforms'),
+    events        = require('./events'),
+    glob          = require('glob'),
+    https         = require('follow-redirects').https,
+    targz         = require('tar.gz'),
+    util          = require('./util');
+
+/**
+ * Usage:
+ **/
+module.exports = function lazy_load(platform, callback) {
+    if (!(platform in platforms)) {
+        var err = new Error('platform "' + platform + '" not recognized.');
+        if (callback) return callback(err);
+        else throw err;
+    }
+
+    if (util.has_platform_lib(platform)) {
+        events.emit('log', 'Platform library for "' + platform + '" already exists. No need to download. Continuing.');
+        return (callback ? callback() : true);
+    } else {
+        // TODO: hook in before_library_dl event
+        var url = platforms[platform].url + ';a=snapshot;h=' + util.cordovaTag + ';sf=tgz';
+        var filename = path.join(util.libDirectory, 'cordova-' + platform + '-' + util.cordovaTag + '.tar.gz');
+        var req_opts = {
+            hostname: 'git-wip-us.apache.org',
+            path: '/repos/asf?p=cordova-' + platform + '.git;a=snapshot;h=' + util.cordovaTag + ';sf=tgz'
+        };
+        events.emit('log', 'Requesting ' + req_opts.hostname + req_opts.path + '...');
+        var req = https.request(req_opts, function(res) {
+            var downloadfile = fs.createWriteStream(filename, {'flags': 'a'});
+
+            res.on('data', function(chunk){
+                // TODO: hook in progress event
+                downloadfile.write(chunk, 'binary');
+                events.emit('log', 'Wrote ' + chunk.length + ' bytes...');
+            });
+
+            res.on('end', function(){
+                // TODO: hook in end event
+                downloadfile.end();
+                events.emit('log', 'Download complete. Extracting...');
+                
+                new targz().extract(filename, util.libDirectory, function(err) {
+                    if (err) {
+                        if (callback) return callback(err);
+                        else throw err;
+                    } else {
+                        // rename the extracted dir to remove the trailing SHA
+                        glob(path.join(util.libDirectory, 'cordova-' + platform + '-' + util.cordovaTag + '-*'), function(err, entries) {
+                            if (err) {
+                                if (callback) return callback(err);
+                                else throw err;
+                            } else {
+                                var entry = entries[0];
+                                var final_dir = path.join(util.libDirectory, 'cordova-' + platform + '-' + util.cordovaTag);
+                                shell.mkdir(final_dir);
+                                shell.mv('-f', path.join(entry, (platform=='blackberry'?'blackberry10':''), '*'), final_dir);
+                                shell.rm('-rf', entry);
+                                if (callback) callback();
+                            }
+                        });
+                    }
+                });
+            });
+        });
+        req.on('error', function(err) {
+            if (callback) return callback(err);
+            else throw err;
+        });
+        req.end();
+    }
+};

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/944c2e42/src/metadata/android_parser.js
----------------------------------------------------------------------
diff --git a/src/metadata/android_parser.js b/src/metadata/android_parser.js
index 314338d..dce21e2 100644
--- a/src/metadata/android_parser.js
+++ b/src/metadata/android_parser.js
@@ -51,7 +51,7 @@ module.exports.check_requirements = function(callback) {
             if (output.indexOf('android-17') == -1) {
                 callback('Please install Android target 17 (the Android 4.2 SDK). Make sure you have the latest Android tools installed as well. Run `android` from your command-line to install/update any missing SDKs or tools.');
             } else {
-                var cmd = 'android update project -p ' + path.join(__dirname, '..', '..', 'lib', 'cordova-android', 'framework') + ' -t android-17';
+                var cmd = 'android update project -p ' + path.join(util.libDirectory, 'cordova-android-' + util.cordovaTag, 'framework') + ' -t android-17';
                 events.emit('log', 'Running "' + cmd + '" (output to follow)...');
                 shell.exec(cmd, {silent:true, async:true}, function(code, output) {
                     events.emit('log', output);
@@ -160,7 +160,7 @@ module.exports.prototype = {
         shell.cp('-rf', www, platformWww);
 
         // write out android lib's cordova.js
-        var jsPath = path.join(util.libDirectory, 'cordova-android', 'framework', 'assets', 'www', 'cordova.js');
+        var jsPath = path.join(util.libDirectory, 'cordova-android-' + util.cordovaTag, 'framework', 'assets', 'www', 'cordova.js');
         fs.writeFileSync(path.join(this.www_dir(), 'cordova.js'), fs.readFileSync(jsPath, 'utf-8'), 'utf-8');
 
     },

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/944c2e42/src/metadata/blackberry_parser.js
----------------------------------------------------------------------
diff --git a/src/metadata/blackberry_parser.js b/src/metadata/blackberry_parser.js
index 9144d13..853ae03 100644
--- a/src/metadata/blackberry_parser.js
+++ b/src/metadata/blackberry_parser.js
@@ -120,18 +120,18 @@ module.exports.prototype = {
         shell.cp('-rf', www, this.path);
 
         // add cordova.js
-        shell.cp('-f', path.join(util.libDirectory, 'cordova-blackberry', 'javascript', 'cordova.blackberry10.js'), path.join(this.www_dir(), 'cordova.js'));
+        shell.cp('-f', path.join(util.libDirectory, 'cordova-blackberry-' + util.cordovaTag, 'javascript', 'cordova.blackberry10.js'), path.join(this.www_dir(), 'cordova.js'));
 
         // add webworks ext directories
-        shell.cp('-rf', path.join(util.libDirectory, 'cordova-blackberry', 'framework', 'ext*'), this.www_dir());
+        shell.cp('-rf', path.join(util.libDirectory, 'cordova-blackberry-' + util.cordovaTag, 'framework', 'ext*'), this.www_dir());
 
         // add config.xml
         // @TODO should use project www/config.xml but it must use BBWP elements
-        shell.cp('-f', path.join(util.libDirectory, 'cordova-blackberry', 'bin', 'templates', 'project', 'www', 'config.xml'), this.www_dir());
+        shell.cp('-f', path.join(util.libDirectory, 'cordova-blackberry-' + util.cordovaTag, 'bin', 'templates', 'project', 'www', 'config.xml'), this.www_dir());
 
         // add res/
         // @TODO remove this when config.xml is generalized
-        shell.cp('-rf', path.join(util.libDirectory, 'cordova-blackberry', 'bin', 'templates', 'project', 'www', 'res'), this.www_dir());
+        shell.cp('-rf', path.join(util.libDirectory, 'cordova-blackberry-' + util.cordovaTag, 'bin', 'templates', 'project', 'www', 'res'), this.www_dir());
     },
 
     // update the overrides folder into the www folder

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/944c2e42/src/metadata/ios_parser.js
----------------------------------------------------------------------
diff --git a/src/metadata/ios_parser.js b/src/metadata/ios_parser.js
index 8ed1af8..7570930 100644
--- a/src/metadata/ios_parser.js
+++ b/src/metadata/ios_parser.js
@@ -177,7 +177,7 @@ module.exports.prototype = {
         shell.cp('-rf', www, this.path);
 
         // write out proper cordova.js
-        shell.cp('-f', path.join(util.libDirectory, 'cordova-ios', 'CordovaLib', 'cordova.js'), path.join(project_www, 'cordova.js'));
+        shell.cp('-f', path.join(util.libDirectory, 'cordova-ios-' + util.cordovaTag, 'CordovaLib', 'cordova.js'), path.join(project_www, 'cordova.js'));
 
     },
 

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/944c2e42/src/metadata/wp7_parser.js
----------------------------------------------------------------------
diff --git a/src/metadata/wp7_parser.js b/src/metadata/wp7_parser.js
index a00f6f0..038da5a 100644
--- a/src/metadata/wp7_parser.js
+++ b/src/metadata/wp7_parser.js
@@ -40,8 +40,9 @@ module.exports = function wp7_parser(project) {
 };
 
 module.exports.check_requirements = function(callback) {
+    // TODO: requires the libraries to be available.
     events.emit('log', 'Checking WP7 requirements...');
-    var command = '"' + path.join(util.libDirectory, 'cordova-wp7', 'bin', 'check_reqs') + '"';
+    var command = '"' + path.join(util.libDirectory, 'cordova-wp7-' + util.cordovaTag, 'bin', 'check_reqs') + '"';
     events.emit('log', 'Running "' + command + '" (output to follow)');
     shell.exec(command, {silent:true, async:true}, function(code, output) {
         events.emit('log', output);
@@ -144,7 +145,7 @@ module.exports.prototype = {
         shell.cp('-rf', project_www, this.wp7_proj_dir);
 
         // copy over wp7 lib's cordova.js
-        var cordovajs_path = path.join(util.libDirectory, 'cordova-wp7', 'templates', 'standalone', 'www', 'cordova.js');
+        var cordovajs_path = path.join(util.libDirectory, 'cordova-wp7-' + util.cordovaTag, 'templates', 'standalone', 'www', 'cordova.js');
         fs.writeFileSync(path.join(this.www_dir(), 'cordova.js'), fs.readFileSync(cordovajs_path, 'utf-8'), 'utf-8');
         this.update_csproj();
     },

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/944c2e42/src/metadata/wp8_parser.js
----------------------------------------------------------------------
diff --git a/src/metadata/wp8_parser.js b/src/metadata/wp8_parser.js
index a6d9bea..110f3be 100644
--- a/src/metadata/wp8_parser.js
+++ b/src/metadata/wp8_parser.js
@@ -40,8 +40,9 @@ module.exports = function wp8_parser(project) {
 };
 
 module.exports.check_requirements = function(callback) {
-    events.emit('log', 'Checking wp8 requirements...');
-    var command = '"' + path.join(util.libDirectory, 'cordova-wp8', 'bin', 'check_reqs') + '"';
+    events.emit('log', 'Checking WP8 requirements...');
+    // TODO: requires the libraries to be available.
+    var command = '"' + path.join(util.libDirectory, 'cordova-wp8-' + util.cordovaTag, 'bin', 'check_reqs') + '"';
     events.emit('log', 'Running "' + command + '" (output to follow)');
     shell.exec(command, {silent:true, async:true}, function(code, output) {
         events.emit('log', output);
@@ -144,7 +145,7 @@ module.exports.prototype = {
         shell.cp('-rf', project_www, this.wp8_proj_dir);
 
         // copy over wp8 lib's cordova.js
-        var cordovajs_path = path.join(util.libDirectory, 'cordova-wp8', 'templates', 'standalone', 'www', 'cordova.js');
+        var cordovajs_path = path.join(util.libDirectory, 'cordova-wp8-' + util.cordovaTag, 'templates', 'standalone', 'www', 'cordova.js');
         fs.writeFileSync(path.join(this.www_dir(), 'cordova.js'), fs.readFileSync(cordovajs_path, 'utf-8'), 'utf-8');
         this.update_csproj();
     },

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/944c2e42/src/platform.js
----------------------------------------------------------------------
diff --git a/src/platform.js b/src/platform.js
index 82cc532..f0537de 100644
--- a/src/platform.js
+++ b/src/platform.js
@@ -23,6 +23,7 @@ var config_parser     = require('./config_parser'),
     path              = require('path'),
     hooker            = require('./hooker'),
     events            = require('./events'),
+    lazy_load         = require('./lazy_load'),
     n                 = require('ncallbacks'),
     platforms         = require('../platforms'),
     plugman           = require('plugman'),
@@ -85,65 +86,77 @@ module.exports = function platform(command, targets, callback) {
                     }
                 });
             });
-            hooks.fire('before_platform_add', opts, function(err) {
-                if (err) {
-                    if (callback) callback(err);
-                    else throw err;
-                } else {
-                    targets.forEach(function(target) {
-                        var output = path.join(projectRoot, 'platforms', target);
-
-                        // Check if output directory already exists.
-                        if (fs.existsSync(output)) {
-                            var err = new Error('Platform "' + target + '" already exists at "' + output + '"');
-                            if (callback) callback(err);
-                            else throw err;
-                        } else {
-                            // Make sure we have minimum requirements to work with specified platform
-                            events.emit('log', 'Checking if platform "' + target + '" passes minimum requirements...');
-                            module.exports.supports(target, function(err) {
-                                if (err) {
-                                    if (callback) callback(err);
-                                    else throw err;
-                                } else {
-                                    // Create a platform app using the ./bin/create scripts that exist in each repo.
-                                    // Run platform's create script
-                                    var bin = path.join(cordova_util.libDirectory, 'cordova-' + target, 'bin', 'create');
-                                    var args = (target=='ios') ? '--arc' : '';
-                                    var pkg = cfg.packageName().replace(/[^\w.]/g,'_');
-                                    var name = cfg.name().replace(/\W/g,'_');
-                                    var command = util.format('"%s" %s "%s" "%s" "%s"', bin, args, output, pkg, name);
-                                    events.emit('log', 'Running bin/create for platform "' + target + '" with command: "' + command + '" (output to follow)');
-
-                                    shell.exec(command, {silent:true,async:true}, function(code, create_output) {
-                                        events.emit('log', create_output);
-                                        if (code > 0) {
-                                            var err = new Error('An error occured during creation of ' + target + ' sub-project. ' + create_output);
-                                            if (callback) callback(err);
-                                            else throw err;
-                                        } else {
-                                            var parser = new platforms[target].parser(output);
-                                            events.emit('log', 'Updating ' + target + ' project from config.xml...');
-                                            parser.update_project(cfg, function() {
-                                                createOverrides(target);
-                                                end(); //platform add is done by now.
-                                                // Install all currently installed plugins into this new platform.
-                                                var pluginsDir = path.join(projectRoot, 'plugins');
-                                                var plugins = fs.readdirSync(pluginsDir);
-                                                plugins && plugins.forEach(function(plugin) {
-                                                    if (fs.statSync(path.join(projectRoot, 'plugins', plugin)).isDirectory()) {
-                                                        events.emit('log', 'Installing plugin "' + plugin + '" following successful platform add of ' + target);
-                                                        plugman.install(target, output, path.basename(plugin), pluginsDir, { www_dir: parser.staging_dir() });
-                                                    }
+            var add_callback = n(targets.length, function() {
+                hooks.fire('before_platform_add', opts, function(err) {
+                    if (err) {
+                        if (callback) callback(err);
+                        else throw err;
+                    } else {
+                        targets.forEach(function(target) {
+                            var output = path.join(projectRoot, 'platforms', target);
+
+                            // Check if output directory already exists.
+                            if (fs.existsSync(output)) {
+                                var err = new Error('Platform "' + target + '" already exists at "' + output + '"');
+                                if (callback) callback(err);
+                                else throw err;
+                            } else {
+                                // Make sure we have minimum requirements to work with specified platform
+                                events.emit('log', 'Checking if platform "' + target + '" passes minimum requirements...');
+                                module.exports.supports(target, function(err) {
+                                    if (err) {
+                                        if (callback) callback(err);
+                                        else throw err;
+                                    } else {
+                                        // Create a platform app using the ./bin/create scripts that exist in each repo.
+                                        // Run platform's create script
+                                        var bin = path.join(cordova_util.libDirectory, 'cordova-' + target + '-' + cordova_util.cordovaTag, 'bin', 'create');
+                                        var args = (target=='ios') ? '--arc' : '';
+                                        var pkg = cfg.packageName().replace(/[^\w.]/g,'_');
+                                        var name = cfg.name().replace(/\W/g,'_');
+                                        var command = util.format('"%s" %s "%s" "%s" "%s"', bin, args, output, pkg, name);
+                                        events.emit('log', 'Running bin/create for platform "' + target + '" with command: "' + command + '" (output to follow)');
+
+                                        shell.exec(command, {silent:true,async:true}, function(code, create_output) {
+                                            events.emit('log', create_output);
+                                            if (code > 0) {
+                                                var err = new Error('An error occured during creation of ' + target + ' sub-project. ' + create_output);
+                                                if (callback) callback(err);
+                                                else throw err;
+                                            } else {
+                                                var parser = new platforms[target].parser(output);
+                                                events.emit('log', 'Updating ' + target + ' project from config.xml...');
+                                                parser.update_project(cfg, function() {
+                                                    createOverrides(target);
+                                                    end(); //platform add is done by now.
+                                                    // Install all currently installed plugins into this new platform.
+                                                    var pluginsDir = path.join(projectRoot, 'plugins');
+                                                    var plugins = fs.readdirSync(pluginsDir);
+                                                    plugins && plugins.forEach(function(plugin) {
+                                                        if (fs.statSync(path.join(projectRoot, 'plugins', plugin)).isDirectory()) {
+                                                            events.emit('log', 'Installing plugin "' + plugin + '" following successful platform add of ' + target);
+                                                            plugman.install(target, output, path.basename(plugin), pluginsDir, { www_dir: parser.staging_dir() });
+                                                        }
+                                                    });
                                                 });
-                                            });
-                                        }
-                                    });
-                                }
-                            });
-                        }
-                    });
-                }
+                                            }
+                                        });
+                                    }
+                                });
+                            }
+                        });
+                    }
+                });
+            });
+            targets.forEach(function(t) {
+                lazy_load(t, function(err) {
+                    if (err) {
+                        if (callback) callback(err);
+                        else throw err;
+                    } else {
+                        add_callback();
+                    }
+                });
             });
             break;
         case 'rm':

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/944c2e42/src/util.js
----------------------------------------------------------------------
diff --git a/src/util.js b/src/util.js
index 8260b28..d458bc2 100644
--- a/src/util.js
+++ b/src/util.js
@@ -20,27 +20,42 @@ var fs         = require('fs'),
     path       = require('path'),
     shell      = require('shelljs');
 
-var lib_path = path.join(__dirname, '..', 'lib')
+// Global configuration paths
+var HOME = process.env[(process.platform == 'win32') ? 'USERPROFILE' : 'HOME'];
+var global_config_path = path.join(HOME, '.cordova');
+var lib_path = path.join(global_config_path, 'lib');
+shell.mkdir('-p', lib_path);
+// What tag of the cordova libs should be dl'ed
+var TAG = '2.8.0';
 
 function chmod(path) {
     shell.exec('chmod +x "' + path + '"', {silent:true});
 }
 
 module.exports = {
+    cordovaTag:TAG,
+    globalConfig:global_config_path,
     libDirectory:lib_path,
+    has_platform_lib:function has_platform_lib(platform) {
+        return fs.existsSync(path.join(lib_path, 'cordova-' + platform + '-' + TAG, 'bin', 'create'));
+    },
     // Runs up the directory chain looking for a .cordova directory.
     // IF it is found we are in a Cordova project.
-    // If not.. we're not.
+    // If not.. we're not. HOME directory doesnt count.
     isCordova: function isCordova(dir) {
         if (dir) {
-            var contents = fs.readdirSync(dir);
-            if (contents && contents.length && (contents.indexOf('.cordova') > -1)) {
-                return dir;
+            if (dir == HOME) {
+                return false;
             } else {
-                var parent = path.join(dir, '..');
-                if (parent && parent.length > 1) {
-                    return isCordova(parent);
-                } else return false;
+                var contents = fs.readdirSync(dir);
+                if (contents && contents.length && (contents.indexOf('.cordova') > -1)) {
+                    return dir;
+                } else {
+                    var parent = path.join(dir, '..');
+                    if (parent && parent.length > 1) {
+                        return isCordova(parent);
+                    } else return false;
+                }
             }
         } else return false;
     },

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/944c2e42/test_runner.js
----------------------------------------------------------------------
diff --git a/test_runner.js b/test_runner.js
index 0250aa3..5ad1f1c 100644
--- a/test_runner.js
+++ b/test_runner.js
@@ -28,6 +28,8 @@ var end = n(Object.keys(platforms).length, function() {
         }
     });
 });
+/*
+TODO: figure out how the test runner should work w.r.t. platform parsers / platform-specific stuff
 console.log('Determining which platforms to run tests for...');
 Object.keys(platforms).forEach(function(p) {
     platform.supports(p, function(e) {