You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cordova.apache.org by an...@apache.org on 2015/09/02 13:31:41 UTC

[3/5] cordova-lib git commit: CB-9597 Initial Implementation of PlatformApiPoly

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/07271a5c/cordova-lib/spec-plugman/util/config-changes.spec.js
----------------------------------------------------------------------
diff --git a/cordova-lib/spec-plugman/util/config-changes.spec.js b/cordova-lib/spec-plugman/util/config-changes.spec.js
index 09bd350..4ffd737 100644
--- a/cordova-lib/spec-plugman/util/config-changes.spec.js
+++ b/cordova-lib/spec-plugman/util/config-changes.spec.js
@@ -44,6 +44,7 @@ var configChanges = require('../../src/plugman/util/config-changes'),
 var mungeutil = require('../../src/plugman/util/munge-util');
 var PlatformJson = require('../../src/plugman/util/PlatformJson');
 var PluginInfoProvider = require('../../src/PluginInfoProvider');
+var PluginInfo = require('../../src/PluginInfo');
 
 // TODO: dont do fs so much
 
@@ -134,7 +135,7 @@ describe('config-changes module', function() {
                 var xml;
                 var dummy_xml = new et.ElementTree(et.XML(fs.readFileSync(path.join(dummyplugin, 'plugin.xml'), 'utf-8')));
                 var munger = new configChanges.PlatformMunger('android', temp, 'unused', null, pluginInfoProvider);
-                var munge = munger.generate_plugin_config_munge(dummyplugin, {});
+                var munge = munger.generate_plugin_config_munge(pluginInfoProvider.get(dummyplugin), {});
                 expect(munge.files['AndroidManifest.xml']).toBeDefined();
                 expect(munge.files['AndroidManifest.xml'].parents['/manifest/application']).toBeDefined();
                 xml = (new et.ElementTree(dummy_xml.find('./platform[@name="android"]/config-file[@target="AndroidManifest.xml"]'))).write({xml_declaration:false});
@@ -153,7 +154,7 @@ describe('config-changes module', function() {
             });
             it('should split out multiple children of config-file elements into individual leaves', function() {
                 var munger = new configChanges.PlatformMunger('android', temp, 'unused', null, pluginInfoProvider);
-                var munge = munger.generate_plugin_config_munge(childrenplugin, {});
+                var munge = munger.generate_plugin_config_munge(pluginInfoProvider.get(childrenplugin), {PACKAGE_NAME: 'com.alunny.childapp'});
                 expect(munge.files['AndroidManifest.xml']).toBeDefined();
                 expect(munge.files['AndroidManifest.xml'].parents['/manifest']).toBeDefined();
                 expect(get_munge_change(munge, 'AndroidManifest.xml', '/manifest', '<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />')).toBeDefined();
@@ -168,48 +169,35 @@ describe('config-changes module', function() {
             });
             it('should not use xml comments as config munge leaves', function() {
                 var munger = new configChanges.PlatformMunger('android', temp, 'unused', null, pluginInfoProvider);
-                var munge = munger.generate_plugin_config_munge(childrenplugin, {});
+                var munge = munger.generate_plugin_config_munge(pluginInfoProvider.get(childrenplugin), {});
                 expect(get_munge_change(munge, 'AndroidManifest.xml', '/manifest', '<!--library-->')).not.toBeDefined();
                 expect(get_munge_change(munge, 'AndroidManifest.xml', '/manifest', '<!-- GCM connects to Google Services. -->')).not.toBeDefined();
             });
             it('should increment config hierarchy leaves if different config-file elements target the same file + selector + xml', function() {
                 var munger = new configChanges.PlatformMunger('android', temp, 'unused', null, pluginInfoProvider);
-                var munge = munger.generate_plugin_config_munge(configplugin, {});
+                var munge = munger.generate_plugin_config_munge(pluginInfoProvider.get(configplugin), {});
                 expect(get_munge_change(munge, 'res/xml/config.xml', '/widget', '<poop />').count).toEqual(2);
             });
             it('should take into account interpolation variables', function() {
                 var munger = new configChanges.PlatformMunger('android', temp, 'unused', null, pluginInfoProvider);
-                var munge = munger.generate_plugin_config_munge(childrenplugin, {PACKAGE_NAME:'ca.filmaj.plugins'});
+                var munge = munger.generate_plugin_config_munge(pluginInfoProvider.get(childrenplugin), {PACKAGE_NAME:'ca.filmaj.plugins'});
                 expect(get_munge_change(munge, 'AndroidManifest.xml', '/manifest', '<uses-permission android:name="ca.filmaj.plugins.permission.C2D_MESSAGE" />')).toBeDefined();
             });
             it('should create munges for platform-agnostic config.xml changes', function() {
                 var munger = new configChanges.PlatformMunger('android', temp, 'unused', null, pluginInfoProvider);
-                var munge = munger.generate_plugin_config_munge(dummyplugin, {});
+                var munge = munger.generate_plugin_config_munge(pluginInfoProvider.get(dummyplugin), {});
                 expect(get_munge_change(munge, 'config.xml', '/*', '<access origin="build.phonegap.com" />')).toBeDefined();
                 expect(get_munge_change(munge, 'config.xml', '/*', '<access origin="s3.amazonaws.com" />')).toBeDefined();
             });
-            it('should automatically add on app java identifier as PACKAGE_NAME variable for android config munges', function() {
-                shell.cp('-rf', android_two_project, temp);
-                var munger = new configChanges.PlatformMunger('android', temp, 'unused', null, pluginInfoProvider);
-                var munge = munger.generate_plugin_config_munge(varplugin, {});
-                var expected_xml = '<package>com.alunny.childapp</package>';
-                expect(get_munge_change(munge, 'AndroidManifest.xml', '/manifest', expected_xml)).toBeDefined();
-            });
         });
 
         describe('for ios projects', function() {
             beforeEach(function() {
                 shell.cp('-rf', ios_config_xml, temp);
             });
-            it('should automatically add on ios bundle identifier as PACKAGE_NAME variable for ios config munges', function() {
-                var munger = new configChanges.PlatformMunger('ios', temp, 'unused', null, pluginInfoProvider);
-                var munge = munger.generate_plugin_config_munge(varplugin, {});
-                var expected_xml = '<cfbundleid>com.example.friendstring</cfbundleid>';
-                expect(get_munge_change(munge, 'config.xml', '/widget', expected_xml)).toBeDefined();
-            });
             it('should special case framework elements for ios', function() {
                 var munger = new configChanges.PlatformMunger('ios', temp, 'unused', null, pluginInfoProvider);
-                var munge = munger.generate_plugin_config_munge(cbplugin, {});
+                var munge = munger.generate_plugin_config_munge(pluginInfoProvider.get(cbplugin), {});
                 expect(munge.files['framework']).toBeDefined();
                 expect(get_munge_change(munge, 'framework', 'libsqlite3.dylib', false)).toBeDefined();
                 expect(get_munge_change(munge, 'framework', 'social.framework', true)).toBeDefined();
@@ -223,11 +211,8 @@ describe('config-changes module', function() {
             });
             it('should special case config-file elements for windows', function() {
                 var munger = new configChanges.PlatformMunger('windows', temp, 'unused', null, pluginInfoProvider);
-                // Unit testing causes a failure when the package_name function is called from generate_plugin_config_munge
-                // the results aren't really important during the unit test
-                munger.platform_handler.package_name = function() { return 'org.apache.testapppackage'; };
 
-                var munge = munger.generate_plugin_config_munge(configplugin, {});
+                var munge = munger.generate_plugin_config_munge(pluginInfoProvider.get(configplugin), {});
                 var packageAppxManifest = munge.files['package.appxmanifest'];
                 var windows80AppxManifest = munge.files['package.windows80.appxmanifest'];
                 var windows81AppxManifest = munge.files['package.windows.appxmanifest'];
@@ -257,10 +242,10 @@ describe('config-changes module', function() {
             shell.cp('-rf', android_two_project, temp);
             var platformJson = PlatformJson.load(plugins_dir, 'android');
             platformJson.root.prepare_queue.installed = [{'plugin':'org.test.plugins.dummyplugin', 'vars':{}}];
-            var munger = new configChanges.PlatformMunger('android', temp, plugins_dir, platformJson, pluginInfoProvider);
+            var munger = new configChanges.PlatformMunger('android', temp, platformJson, pluginInfoProvider);
             var spy = spyOn(munger, 'generate_plugin_config_munge').andReturn({});
-            munger.process();
-            expect(spy).toHaveBeenCalledWith(path.join(plugins_dir, 'org.test.plugins.dummyplugin'), {});
+            munger.process(plugins_dir);
+            expect(spy).toHaveBeenCalledWith(jasmine.any(PluginInfo), {});
         });
         describe(': installation', function() {
             describe('of xml config files', function() {
@@ -273,8 +258,8 @@ describe('config-changes module', function() {
 
                     var spy = spyOn(xml_helpers, 'graftXML').andReturn(true);
 
-                    var munger = new configChanges.PlatformMunger('android', temp, plugins_dir, platformJson, pluginInfoProvider);
-                    munger.process();
+                    var munger = new configChanges.PlatformMunger('android', temp, platformJson, pluginInfoProvider);
+                    munger.process(plugins_dir);
                     expect(spy.calls.length).toEqual(4);
                     expect(spy.argsForCall[0][2]).toEqual('/*');
                     expect(spy.argsForCall[1][2]).toEqual('/*');
@@ -287,8 +272,8 @@ describe('config-changes module', function() {
                     platformJson.addInstalledPluginToPrepareQueue('org.test.configtest', {});
 
                     var spy = spyOn(xml_helpers, 'graftXML').andReturn(true);
-                    var munger = new configChanges.PlatformMunger('android', temp, plugins_dir, platformJson, pluginInfoProvider);
-                    munger.process();
+                    var munger = new configChanges.PlatformMunger('android', temp, platformJson, pluginInfoProvider);
+                    munger.process(plugins_dir);
                     expect(spy.calls.length).toEqual(1);
                 });
                 it('should not call graftXML for a config munge targeting a config file that does not exist', function() {
@@ -297,8 +282,8 @@ describe('config-changes module', function() {
 
                     var spy = spyOn(fs, 'readFileSync').andCallThrough();
 
-                    var munger = new configChanges.PlatformMunger('android', temp, plugins_dir, platformJson, pluginInfoProvider);
-                    munger.process();
+                    var munger = new configChanges.PlatformMunger('android', temp, platformJson, pluginInfoProvider);
+                    munger.process(plugins_dir);
                     expect(spy).not.toHaveBeenCalledWith(path.join(temp, 'res', 'xml', 'plugins.xml'), 'utf-8');
                 });
             });
@@ -333,8 +318,8 @@ describe('config-changes module', function() {
                 it('should call into xcode.addFramework if plugin has <framework> file defined and is ios',function() {
                     var platformJson = PlatformJson.load(plugins_dir, 'ios');
                     platformJson.addInstalledPluginToPrepareQueue('org.test.plugins.childbrowser', {});
-                    var munger = new configChanges.PlatformMunger('ios', temp, plugins_dir, platformJson, pluginInfoProvider);
-                    munger.process();
+                    var munger = new configChanges.PlatformMunger('ios', temp, platformJson, pluginInfoProvider);
+                    munger.process(plugins_dir);
                     expect(xcode_add).toHaveBeenCalledWith('libsqlite3.dylib', {weak:false});
                     expect(xcode_add).toHaveBeenCalledWith('social.framework', {weak:true});
                     expect(xcode_add).toHaveBeenCalledWith('music.framework', {weak:false});
@@ -348,8 +333,8 @@ describe('config-changes module', function() {
                 platformJson.addInstalledPluginToPrepareQueue('org.test.plugins.childbrowser', {});
                 var spy = spyOn(fs, 'readFileSync').andCallThrough();
 
-                var munger = new configChanges.PlatformMunger('ios', temp, plugins_dir, platformJson, pluginInfoProvider);
-                munger.process();
+                var munger = new configChanges.PlatformMunger('ios', temp, platformJson, pluginInfoProvider);
+                munger.process(plugins_dir);
                 expect(spy).toHaveBeenCalledWith(path.join(temp, 'SampleApp', 'SampleApp-Info.plist').replace(/\\/g, '/'), 'utf8');
             });
             it('should move successfully installed plugins from queue to installed plugins section, and include/retain vars if applicable', function() {
@@ -358,8 +343,8 @@ describe('config-changes module', function() {
                 var platformJson = PlatformJson.load(plugins_dir, 'android');
                 platformJson.addInstalledPluginToPrepareQueue('com.adobe.vars', {'API_KEY':'hi'}, true);
 
-                var munger = new configChanges.PlatformMunger('android', temp, plugins_dir, platformJson, pluginInfoProvider);
-                munger.process();
+                var munger = new configChanges.PlatformMunger('android', temp, platformJson, pluginInfoProvider);
+                munger.process(plugins_dir);
 
                 expect(platformJson.root.prepare_queue.installed.length).toEqual(0);
                 expect(platformJson.root.installed_plugins['com.adobe.vars']).toBeDefined();
@@ -374,13 +359,13 @@ describe('config-changes module', function() {
                 // Run through an "install"
                 var platformJson = PlatformJson.load(plugins_dir, 'android');
                 platformJson.addInstalledPluginToPrepareQueue('org.test.plugins.dummyplugin', {});
-                var munger = new configChanges.PlatformMunger('android', temp, plugins_dir, platformJson, pluginInfoProvider);
-                munger.process();
+                var munger = new configChanges.PlatformMunger('android', temp, platformJson, pluginInfoProvider);
+                munger.process(plugins_dir);
 
                 // Now set up an uninstall and make sure prunexml is called properly
                 platformJson.addUninstalledPluginToPrepareQueue('org.test.plugins.dummyplugin');
                 var spy = spyOn(xml_helpers, 'pruneXML').andReturn(true);
-                munger.process();
+                munger.process(plugins_dir);
                 expect(spy.calls.length).toEqual(4);
                 expect(spy.argsForCall[0][2]).toEqual('/*');
                 expect(spy.argsForCall[1][2]).toEqual('/*');
@@ -393,15 +378,16 @@ describe('config-changes module', function() {
                 // Run through an "install"
                 var platformJson = PlatformJson.load(plugins_dir, 'android');
                 platformJson.addInstalledPluginToPrepareQueue('com.adobe.vars', {'API_KEY':'canucks'});
-                var munger = new configChanges.PlatformMunger('android', temp, plugins_dir, platformJson, pluginInfoProvider);
-                munger.process();
+                var munger = new configChanges.PlatformMunger('android', temp, platformJson, pluginInfoProvider);
+                munger.process(plugins_dir);
 
                 // Now set up an uninstall and make sure prunexml is called properly
                 platformJson.addUninstalledPluginToPrepareQueue('com.adobe.vars');
                 var spy = spyOn(munger, 'generate_plugin_config_munge').andReturn({});
-                munger.process();
+                munger.process(plugins_dir);
                 var munge_params = spy.mostRecentCall.args;
-                expect(munge_params[0]).toEqual(path.join(plugins_dir, 'com.adobe.vars'));
+                expect(munge_params[0]).toEqual(jasmine.any(PluginInfo));
+                expect(munge_params[0].dir).toEqual(path.join(plugins_dir, 'com.adobe.vars'));
                 expect(munge_params[1]['API_KEY']).toEqual('canucks');
             });
             it('should not call pruneXML for a config munge that another plugin depends on', function() {
@@ -413,12 +399,12 @@ describe('config-changes module', function() {
                 var platformJson = PlatformJson.load(plugins_dir, 'android');
                 platformJson.addInstalledPluginToPrepareQueue('org.test.multiple-children', {});
                 platformJson.addInstalledPluginToPrepareQueue('org.test.shareddeps', {});
-                var munger = new configChanges.PlatformMunger('android', temp, plugins_dir, platformJson, pluginInfoProvider);
-                munger.process();
+                var munger = new configChanges.PlatformMunger('android', temp, platformJson, pluginInfoProvider);
+                munger.process(plugins_dir);
 
                 // Now set up an uninstall for multi-child plugin
                 platformJson.addUninstalledPluginToPrepareQueue('org.test.multiple-children');
-                munger.process();
+                munger.process(plugins_dir);
                 munger.save_all();
                 var am_xml = new et.ElementTree(et.XML(fs.readFileSync(path.join(temp, 'AndroidManifest.xml'), 'utf-8')));
                 var permission = am_xml.find('./uses-permission');
@@ -430,14 +416,14 @@ describe('config-changes module', function() {
                 // install a plugin
                 var platformJson = PlatformJson.load(plugins_dir, 'android');
                 platformJson.addInstalledPluginToPrepareQueue('org.test.plugins.dummyplugin', {});
-                var munger = new configChanges.PlatformMunger('android', temp, plugins_dir, platformJson, pluginInfoProvider);
-                munger.process();
+                var munger = new configChanges.PlatformMunger('android', temp, platformJson, pluginInfoProvider);
+                munger.process(plugins_dir);
 
                 // set up an uninstall for the same plugin
                 platformJson.addUninstalledPluginToPrepareQueue('org.test.plugins.dummyplugin');
 
                 var spy = spyOn(fs, 'readFileSync').andCallThrough();
-                munger.process();
+                munger.process(plugins_dir);
 
                 expect(spy).not.toHaveBeenCalledWith(path.join(temp, 'res', 'xml', 'plugins.xml'), 'utf-8');
             });
@@ -447,12 +433,12 @@ describe('config-changes module', function() {
                 // install the var plugin
                 var platformJson = PlatformJson.load(plugins_dir, 'android');
                 platformJson.addInstalledPluginToPrepareQueue('com.adobe.vars', {'API_KEY':'eat my shorts'});
-                var munger = new configChanges.PlatformMunger('android', temp, plugins_dir, platformJson, pluginInfoProvider);
-                munger.process();
+                var munger = new configChanges.PlatformMunger('android', temp, platformJson, pluginInfoProvider);
+                munger.process(plugins_dir);
 
                 // queue up an uninstall for the same plugin
                 platformJson.addUninstalledPluginToPrepareQueue('com.adobe.vars');
-                munger.process();
+                munger.process(plugins_dir);
 
                 expect(platformJson.root.prepare_queue.uninstalled.length).toEqual(0);
                 expect(platformJson.root.installed_plugins['com.adobe.vars']).not.toBeDefined();

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/07271a5c/cordova-lib/src/PluginInfo.js
----------------------------------------------------------------------
diff --git a/cordova-lib/src/PluginInfo.js b/cordova-lib/src/PluginInfo.js
index 08b0a97..1802f24 100644
--- a/cordova-lib/src/PluginInfo.js
+++ b/cordova-lib/src/PluginInfo.js
@@ -83,7 +83,11 @@ function PluginInfo(dirname) {
             throw new Error(msg);
         }
 
-        var asset = { src: src, target: target };
+        var asset = {
+            itemType: 'asset',
+            src: src,
+            target: target
+        };
         return asset;
     }
 
@@ -258,6 +262,7 @@ function PluginInfo(dirname) {
 
     function _parseJsModule(tag) {
         var ret = {
+            itemType: 'js-module',
             name: tag.attrib.name,
             src: tag.attrib.src,
             clobbers: tag.findall('clobbers').map(function(tag) { return { target: tag.attrib.target }; }),

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/07271a5c/cordova-lib/src/cordova/clean.js
----------------------------------------------------------------------
diff --git a/cordova-lib/src/cordova/clean.js b/cordova-lib/src/cordova/clean.js
index 8814ff6..59696ed 100644
--- a/cordova-lib/src/cordova/clean.js
+++ b/cordova-lib/src/cordova/clean.js
@@ -17,12 +17,11 @@
     under the License.
 */
 
-var path              = require('path'),
-    cordova_util      = require('./util'),
-    HooksRunner       = require('../hooks/HooksRunner'),
-    events            = require('../events'),
-    chain             = require('../util/promise-util').Q_chainmap,
-    superspawn        = require('./superspawn');
+var cordova_util = require('./util'),
+    HooksRunner  = require('../hooks/HooksRunner'),
+    events       = require('../events'),
+    chain        = require('../util/promise-util').Q_chainmap,
+    platform_lib = require('../platforms/platforms');
 
 // Returns a promise.
 module.exports = function clean(options) {
@@ -34,12 +33,9 @@ module.exports = function clean(options) {
     .then(function () {
         return chain(options.platforms, function (platform) {
             events.emit('verbose', 'Running cleanup for ' + platform + ' platform.');
-            var cmd = path.join(projectRoot, 'platforms', platform, 'cordova', 'clean');
-            return superspawn.spawn(cmd, options.options, {
-                stdio: options.silent ? 'ignore' : 'inherit', // hide script output in silent mode
-                printCommand: !!options.verbose,              // print command only if --verbose specified
-                chmod: true
-            });
+            return platform_lib
+                .getPlatformApi(platform)
+                .clean();
         });
     })
     .then(function() {

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/07271a5c/cordova-lib/src/cordova/compile.js
----------------------------------------------------------------------
diff --git a/cordova-lib/src/cordova/compile.js b/cordova-lib/src/cordova/compile.js
index 3728b67..dbf69ec 100644
--- a/cordova-lib/src/cordova/compile.js
+++ b/cordova-lib/src/cordova/compile.js
@@ -17,12 +17,12 @@
     under the License.
 */
 
-var path              = require('path'),
-    cordova_util      = require('./util'),
-    HooksRunner       = require('../hooks/HooksRunner'),
-    events            = require('../events'),
-    Q                 = require('q'),
-    superspawn        = require('./superspawn');
+var cordova_util = require('./util'),
+    HooksRunner  = require('../hooks/HooksRunner'),
+    events       = require('../events'),
+    Q            = require('q'),
+    promiseUtil  = require('../util/promise-util'),
+    platform_lib = require('../platforms/platforms');
 
 // Returns a promise.
 module.exports = function compile(options) {
@@ -30,18 +30,17 @@ module.exports = function compile(options) {
     options = cordova_util.preProcessOptions(options);
 
     var hooksRunner = new HooksRunner(projectRoot);
-    var ret = hooksRunner.fire('before_compile', options);
-    options.platforms.forEach(function(platform) {
-        ret = ret.then(function() {
-            var cmd = path.join(projectRoot, 'platforms', platform, 'cordova', 'build');
-            return superspawn.spawn(cmd, options.options, { stdio: 'inherit', printCommand: true, chmod: true });
+    return hooksRunner.fire('before_compile', options)
+    .then(function () {
+        return promiseUtil.Q_chainmap(options.platforms, function (platform) {
+            return platform_lib
+                .getPlatformApi(platform)
+                .build(options.options);
         });
-    });
-    ret = ret.then(function() {
+    }).then(function() {
         return hooksRunner.fire('after_compile', options);
     }, function(error) {
         events.emit('log', 'ERROR building one of the platforms: ' + error + '\nYou may not have the required environment or OS to build this project');
         return Q.reject(error);
     });
-    return ret;
 };

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/07271a5c/cordova-lib/src/cordova/emulate.js
----------------------------------------------------------------------
diff --git a/cordova-lib/src/cordova/emulate.js b/cordova-lib/src/cordova/emulate.js
index 3b09545..67dedeb 100644
--- a/cordova-lib/src/cordova/emulate.js
+++ b/cordova-lib/src/cordova/emulate.js
@@ -17,16 +17,17 @@
     under the License.
 */
 
-var cordova_util      = require('./util'),
-    path              = require('path'),
-    HooksRunner            = require('../hooks/HooksRunner'),
-    superspawn        = require('./superspawn'),
-    Q                 = require('q');
+var cordova_util = require('./util'),
+    HooksRunner  = require('../hooks/HooksRunner'),
+    Q            = require('q'),
+    platform_lib = require('../platforms/platforms');
 
 // Returns a promise.
 module.exports = function emulate(options) {
     var projectRoot = cordova_util.cdProjectRoot();
     options = cordova_util.preProcessOptions(options);
+    options.options.device = false;
+    options.options.emulator = true;
 
     var hooksRunner = new HooksRunner(projectRoot);
     return hooksRunner.fire('before_emulate', options)
@@ -36,10 +37,9 @@ module.exports = function emulate(options) {
     }).then(function() {
         // Deploy in parallel (output gets intermixed though...)
         return Q.all(options.platforms.map(function(platform) {
-            var cmd = path.join(projectRoot, 'platforms', platform, 'cordova', 'run');
-            var args = ['--emulator'].concat(options.options);
-
-            return superspawn.spawn(cmd, args, {stdio: 'inherit', printCommand: true, chmod: true});
+            return platform_lib
+                .getPlatformApi(platform)
+                .run(options.options);
         }));
     }).then(function() {
         return hooksRunner.fire('after_emulate', options);

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/07271a5c/cordova-lib/src/cordova/platform.js
----------------------------------------------------------------------
diff --git a/cordova-lib/src/cordova/platform.js b/cordova-lib/src/cordova/platform.js
index 4739f80..3e963b0 100644
--- a/cordova-lib/src/cordova/platform.js
+++ b/cordova-lib/src/cordova/platform.js
@@ -33,7 +33,6 @@ var config            = require('./config'),
     promiseutil       = require('../util/promise-util'),
     superspawn        = require('./superspawn'),
     semver            = require('semver'),
-    unorm             = require('unorm'),
     shell             = require('shelljs'),
     _                 = require('underscore'),
     PlatformJson      = require('../plugman/util/PlatformJson'),
@@ -124,59 +123,69 @@ function addHelper(cmd, hooksRunner, projectRoot, targets, opts) {
                 var platformPath = path.join(projectRoot, 'platforms', platform);
                 var platformAlreadyAdded = fs.existsSync(platformPath);
 
-                return Q().then(function() {
-                    if (cmd == 'add') {
-                        if (platformAlreadyAdded) {
-                            throw new CordovaError('Platform ' + platform + ' already added.');
-                        }
-
-                        // Remove the <platform>.json file from the plugins directory, so we start clean (otherwise we
-                        // can get into trouble not installing plugins if someone deletes the platform folder but
-                        // <platform>.json still exists).
-                        removePlatformPluginsJson(projectRoot, target);
-
-                        var template_dir = config_json && config_json.lib && config_json.lib[platform] && config_json.lib[platform].template || null;
-                        events.emit('log', 'Adding ' + platform + ' project...');
-
-                        return getCreateArgs(platDetails, projectRoot, cfg, template_dir, opts);
-                    } else if (cmd == 'update') {
-                        if (!platformAlreadyAdded) {
-                            throw new CordovaError('Platform "' + platform + '" is not yet added. See `' +
-                                cordova_util.binname + ' platform list`.');
-                        }
-                        events.emit('log', 'Updating ' + platform + ' project...');
-
-                        // CB-6976 Windows Universal Apps. Special case to upgrade from windows8 to windows platform
-                        if (platform == 'windows8' && !fs.existsSync(path.join(projectRoot, 'platforms', 'windows'))) {
-                            var platformPathWindows = path.join(projectRoot, 'platforms', 'windows');
-                            fs.renameSync(platformPath, platformPathWindows);
-                            platform = 'windows';
-                            platformPath = platformPathWindows;
-                        }
-                        // Call the platform's update script.
-                        var args = [platformPath];
-                        if (opts.link) {
-                            args.push('--link');
-                        }
-                        return args;
+                if (cmd == 'add') {
+                    if (platformAlreadyAdded) {
+                        throw new CordovaError('Platform ' + platform + ' already added.');
                     }
-                }).then(function(args) {
-                    var bin = path.join(platDetails.libDir, 'bin', cmd == 'add' ? 'create' : 'update');
-                    var copts = { stdio: 'inherit', chmod: true };
-                    if ('spawnoutput' in opts) {
-                        copts = { stdio: opts.spawnoutput };
+
+                    // Remove the <platform>.json file from the plugins directory, so we start clean (otherwise we
+                    // can get into trouble not installing plugins if someone deletes the platform folder but
+                    // <platform>.json still exists).
+                    removePlatformPluginsJson(projectRoot, target);
+                } else if (cmd == 'update') {
+                    if (!platformAlreadyAdded) {
+                        throw new CordovaError('Platform "' + platform + '" is not yet added. See `' +
+                            cordova_util.binname + ' platform list`.');
                     }
-                    return superspawn.spawn(bin, args, copts);
-                }).then(function() {
-                    var platform_www = path.join(projectRoot, 'platforms', platform, 'platform_www');
 
-                    copy_cordova_js(projectRoot, platform);
+                    // CB-6976 Windows Universal Apps. Special case to upgrade from windows8 to windows platform
+                    if (platform == 'windows8' && !fs.existsSync(path.join(projectRoot, 'platforms', 'windows'))) {
+                        var platformPathWindows = path.join(projectRoot, 'platforms', 'windows');
+                        fs.renameSync(platformPath, platformPathWindows);
+                        platform = 'windows';
+                        platformPath = platformPathWindows;
+                    }
+                }
 
-                    // only want to copy cordova-js-src once, when the platform is added
-                    if (!fs.existsSync(path.join(platform_www, 'cordova-js-src'))) {
-                        copy_cordovajs_src(projectRoot, platform, platDetails.libDir);
+                var cordovaProject = {
+                    root: projectRoot,
+                    projectConfig: cfg,
+                    locations: {
+                        www: path.join(projectRoot, 'www'),
+                        platforms: path.join(projectRoot, 'platforms'),
+                        configXml: path.join(projectRoot, 'config.xml')
                     }
-                }).then(function () {
+                };
+
+                var options = {
+                    // We need to pass a platformDetails into update/create
+                    // since PlatformApiPoly needs to know something about
+                    // platform, it is going to create.
+                    platformDetails: platDetails,
+                    link: opts.link
+                };
+
+                if (config_json && config_json.lib && config_json.lib[platform] &&
+                    config_json.lib[platform].template) {
+                    options.customTemplate = config_json.lib[platform].template;
+                }
+
+                events.emit('log', (cmd === 'add' ? 'Adding ' : 'Updating ') + platform + ' project...');
+
+                var PlatformApi;
+                try {
+                    // Try to get PlatformApi class from platform
+                    PlatformApi = require(path.resolve(platDetails.libDir, 'bin/PlatformApi'));
+                } catch (err) {
+                    PlatformApi = require('../platforms/PlatformApiPoly');
+                }
+
+                var promise = cmd === 'add' ?
+                    PlatformApi.createPlatform :
+                    PlatformApi.updatePlatform;
+
+                return promise(cordovaProject, options)
+                .then(function () {
                     // Call prepare for the current platform.
                     var prepOpts = {
                         platforms :[platform],
@@ -597,37 +606,6 @@ function hostSupports(platform) {
     return false;
 }
 
-// Returns a promise.
-function getCreateArgs(platDetails, projectRoot, cfg, template_dir, opts) {
-    var output = path.join(projectRoot, 'platforms', platDetails.platform);
-
-    var args = [];
-    if (/android|ios/.exec(platDetails.platform) && semver.gt(platDetails.version, '3.3.0')) {
-        args.push('--cli');
-    }
-
-    var pkg = cfg.packageName().replace(/[^\w.]/g,'_');
-    // CB-6992 it is necessary to normalize characters
-    // because node and shell scripts handles unicode symbols differently
-    // We need to normalize the name to NFD form since iOS uses NFD unicode form
-    var name = platDetails.platform == 'ios' ? unorm.nfd(cfg.name()) : cfg.name();
-    args.push(output, pkg, name);
-
-    var activityName = cfg.android_activityName();
-    if (activityName && platDetails.platform === 'android' && semver.gte(platDetails.version, '4.0.0-dev')) {
-        activityName = activityName.replace(/\W/g, '');
-        args.push('--activity-name', activityName);
-    }
-
-    if (template_dir) {
-        args.push(template_dir);
-    }
-    if (opts.link) {
-        args.push('--link');
-    }
-    return args;
-}
-
 function installPluginsForNewPlatform(platform, projectRoot, opts) {
     // Install all currently installed plugins into this new platform.
     var plugins_dir = path.join(projectRoot, 'plugins');
@@ -669,29 +647,6 @@ function installPluginsForNewPlatform(platform, projectRoot, opts) {
     }, Q());
 }
 
-// Copy the cordova.js file to platforms/<platform>/platform_www/
-// The www dir is nuked on each prepare so we keep cordova.js in platform_www
-function copy_cordova_js(projectRoot, platform) {
-    var platformPath = path.join(projectRoot, 'platforms', platform);
-    var parser = platforms.getPlatformProject(platform, platformPath);
-    var platform_www = path.join(platformPath, 'platform_www');
-    shell.mkdir('-p', platform_www);
-    shell.cp('-f', path.join(parser.www_dir(), 'cordova.js'), path.join(platform_www, 'cordova.js'));
-}
-
-// Copy cordova-js-src directory into platform_www directory.
-// We need these files to build cordova.js if using browserify method.
-function copy_cordovajs_src(projectRoot, platform, platLib) {
-    var platformPath = path.join(projectRoot, 'platforms', platform);
-    var parser = platforms.getPlatformProject(platform, platformPath);
-    var platform_www = path.join(platformPath, 'platform_www');
-    var cordovaJsSrcPath = parser.cordovajs_src_path(platLib);
-    //only exists for platforms that have shipped cordova-js-src directory
-    if(fs.existsSync(cordovaJsSrcPath)) {
-        shell.cp('-rf', cordovaJsSrcPath, platform_www);
-    }
-}
-
 // Remove <platform>.json file from plugins directory.
 function removePlatformPluginsJson(projectRoot, target) {
     var plugins_json = path.join(projectRoot, 'plugins', target + '.json');

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/07271a5c/cordova-lib/src/cordova/plugin.js
----------------------------------------------------------------------
diff --git a/cordova-lib/src/cordova/plugin.js b/cordova-lib/src/cordova/plugin.js
index 0f90de2..f49205a 100644
--- a/cordova-lib/src/cordova/plugin.js
+++ b/cordova-lib/src/cordova/plugin.js
@@ -30,7 +30,8 @@ var cordova_util  = require('./util'),
     plugman       = require('../plugman/plugman'),
     pluginMapper  = require('cordova-registry-mapper').newToOld,
     events        = require('../events'),
-    metadata      = require('../plugman/util/metadata');
+    metadata      = require('../plugman/util/metadata'),
+    chainMap      = require('../util/promise-util').Q_chainmap;
 
 // Returns a promise.
 module.exports = function plugin(command, targets, opts) {
@@ -134,14 +135,23 @@ module.exports = function plugin(command, targets, opts) {
                         // Fetch the plugin first.
                         events.emit('verbose', 'Calling plugman.fetch on plugin "' + target + '"');
 
-                        return plugman.raw.fetch(target, pluginPath, { searchpath: searchPath, noregistry: opts.noregistry, link: opts.link,
-                                                                       pluginInfoProvider: pluginInfoProvider, variables: opts.cli_variables,
-                                                                       is_top_level: true });
+                        var fetchOptions = {
+                            searchpath: searchPath,
+                            noregistry: opts.noregistry,
+                            link: opts.link,
+                            pluginInfoProvider: pluginInfoProvider,
+                            variables: opts.cli_variables,
+                            is_top_level: true
+                        };
+
+                        return plugman.raw.fetch(target, pluginPath, fetchOptions)
+                        .then(function (directory) {
+                            return pluginInfoProvider.get(directory);
+                        });
                     })
-                    .then(function(dir){
+                    .then(function(pluginInfo){
                         // save to config.xml
-                        if(saveToConfigXmlOn(config_json,opts)){
-                            var pluginInfo =  pluginInfoProvider.get(dir);
+                        if(saveToConfigXmlOn(config_json, opts)){
 
                             var attributes = {};
                             attributes.name = pluginInfo.id;
@@ -149,77 +159,48 @@ module.exports = function plugin(command, targets, opts) {
                             var src = parseSource(target, opts);
                             attributes.spec = src ? src : '~' + pluginInfo.version;
 
-                            var variables = [];
-                            if (opts.cli_variables) {
-                                for (var varname in opts.cli_variables) {
-                                    if (opts.cli_variables.hasOwnProperty(varname)) {
-                                        variables.push({name: varname, value: opts.cli_variables[varname]});
-                                    }
-                                }
-                            }
+                            var variables = Object.keys(opts.cli_variables || [])
+                            .map(function (variableName) {
+                                return {name: variableName, value: opts.cli_variables[variableName]};
+                            });
+
                             cfg.removePlugin(pluginInfo.id);
                             cfg.addPlugin(attributes, variables);
                             cfg.write();
                             events.emit('results', 'Saved plugin info for "' + pluginInfo.id + '" to config.xml');
                         }
-                        return dir;
+                        return pluginInfo;
                     })
-                    .then(function(dir) {
+                    .then(function(pluginInfo) {
                         // Validate top-level required variables
-                        var pluginVariables = pluginInfoProvider.get(dir).getPreferences();
-                        var requiredVariables = [];
-
-                        for(var i in pluginVariables) {
-                            var v = pluginVariables[i];
+                        var pluginVariables = pluginInfo.getPreferences();
+                        var missingVariables = Object.keys(pluginVariables)
+                        .filter(function (variableName) {
                             // discard variables with default value
-                            if (!v) {
-                                requiredVariables.push(i);
-                            }
-                        }
-
-                        opts.cli_variables = opts.cli_variables || {}; 
-                        var missingVariables = requiredVariables.filter(function (v) {
-                            return !(v in opts.cli_variables);
+                            return !(pluginVariables[variableName] || opts.cli_variables[variableName]);
                         });
 
                         if (missingVariables.length) {
-                            shell.rm('-rf', dir);
+                            shell.rm('-rf', pluginInfo.dir);
                             var msg = 'Variable(s) missing (use: --variable ' + missingVariables.join('=value --variable ') + '=value).';
                             return Q.reject(new CordovaError(msg));
                         }
+
                         // Iterate (in serial!) over all platforms in the project and install the plugin.
-                        return platformList.reduce(function(soFar, platform) {
-                            return soFar.then(function() {
-                                var platformRoot = path.join(projectRoot, 'platforms', platform),
-                                    options = {
-                                        cli_variables: opts.cli_variables || {},
-                                        browserify: opts.browserify || false,
-                                        searchpath: searchPath,
-                                        noregistry: opts.noregistry,
-                                        link: opts.link,
-                                        pluginInfoProvider: pluginInfoProvider
-                                    },
-                                    tokens,
-                                    key,
-                                    i;
-
-                                // TODO: Remove this. CLI vars are passed as part of the opts object after "nopt" refactoring.
-                                // Keeping for now for compatibility for API users.
-                                //parse variables into cli_variables
-                                for (i=0; i< opts.options.length; i++) {
-                                    if (opts.options[i] === '--variable' && typeof opts.options[++i] === 'string') {
-                                        tokens = opts.options[i].split('=');
-                                        key = tokens.shift().toUpperCase();
-                                        if (/^[\w-_]+$/.test(key)) {
-                                            options.cli_variables[key] = tokens.join('=');
-                                        }
-                                    }
-                                }
-
-                                events.emit('verbose', 'Calling plugman.install on plugin "' + dir + '" for platform "' + platform + '" with options "' + JSON.stringify(options)  + '"');
-                                return plugman.raw.install(platform, platformRoot, path.basename(dir), pluginPath, options);
-                            });
-                        }, Q());
+                        return chainMap(platformList, function (platform) {
+                            var platformRoot = path.join(projectRoot, 'platforms', platform),
+                            options = {
+                                cli_variables: opts.cli_variables || {},
+                                browserify: opts.browserify || false,
+                                searchpath: searchPath,
+                                noregistry: opts.noregistry,
+                                link: opts.link,
+                                pluginInfoProvider: pluginInfoProvider
+                            };
+
+                            events.emit('verbose', 'Calling plugman.install on plugin "' + pluginInfo.dir + '" for platform "' + platform);
+                            return plugman.raw.install(platform, platformRoot, path.basename(pluginInfo.dir), pluginPath, options);
+                        });
                     });
                 }, Q()); // end Q.all
             }).then(function() {

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/07271a5c/cordova-lib/src/cordova/prepare.js
----------------------------------------------------------------------
diff --git a/cordova-lib/src/cordova/prepare.js b/cordova-lib/src/cordova/prepare.js
index 9e27833..4125bb3 100644
--- a/cordova-lib/src/cordova/prepare.js
+++ b/cordova-lib/src/cordova/prepare.js
@@ -19,201 +19,64 @@
 
 var cordova_util      = require('./util'),
     ConfigParser      = require('../configparser/ConfigParser'),
-    path              = require('path'),
     platforms         = require('../platforms/platforms'),
-    fs                = require('fs'),
-    shell             = require('shelljs'),
-    et                = require('elementtree'),
     HooksRunner       = require('../hooks/HooksRunner'),
-    events            = require('../events'),
     Q                 = require('q'),
-    plugman           = require('../plugman/plugman'),
-    PlatformMunger    = require('../plugman/util/config-changes').PlatformMunger,
-    PlatformJson      = require('../plugman/util/PlatformJson'),
     restore           = require('./restore-util'),
+    path              = require('path'),
+    browserify = require('../plugman/browserify'),
     config            = require('./config');
 
-
-var PluginInfoProvider = require('../PluginInfoProvider');
-
 // Returns a promise.
 exports = module.exports = prepare;
 function prepare(options) {
     var projectRoot = cordova_util.cdProjectRoot();
-    var xml = cordova_util.projectConfig(projectRoot);
     var config_json = config.read(projectRoot);
-
-    if (!options) {
-        options = {
-            verbose: false,
-            platforms: [],
-            options: []
-        };
-    }
-
-    options.searchpath = options.searchpath || config_json.plugin_search_path;
+    options = options || { verbose: false, platforms: [], options: [] };
 
     var hooksRunner = new HooksRunner(projectRoot);
     return hooksRunner.fire('before_prepare', options)
     .then(function(){
-        return restore.installPlatformsFromConfigXML(options.platforms);
-    })
-    .then(function(){
-        options = cordova_util.preProcessOptions(options);
-        var paths = options.platforms.map(function(p) {
-            var platform_path = path.join(projectRoot, 'platforms', p);
-            var parser = platforms.getPlatformProject(p, platform_path);
-            return parser.www_dir();
-        });
-        options.paths = paths;
+        var platformsToRestore = options && options.platforms || [];
+        return restore.installPlatformsFromConfigXML(platformsToRestore);
     })
     .then(function() {
-        var pluginInfoProvider = new PluginInfoProvider();
-
+        options = cordova_util.preProcessOptions(options);
+        options.searchpath = options.searchpath || config_json.plugin_search_path;
         // Iterate over each added platform
         return Q.all(options.platforms.map(function(platform) {
-            var platformPath = path.join(projectRoot, 'platforms', platform);
-
-            var parser = platforms.getPlatformProject(platform, platformPath);
-            var defaults_xml_path = path.join(platformPath, 'cordova', 'defaults.xml');
-            // If defaults.xml is present, overwrite platform config.xml with
-            // it Otherwise save whatever is there as defaults so it can be
-            // restored or copy project config into platform if none exists.
-            if (fs.existsSync(defaults_xml_path)) {
-                shell.cp('-f', defaults_xml_path, parser.config_xml());
-                events.emit('verbose', 'Generating config.xml from defaults for platform "' + platform + '"');
-            } else {
-                if(fs.existsSync(parser.config_xml())){
-                    shell.cp('-f', parser.config_xml(), defaults_xml_path);
-                }else{
-                    shell.cp('-f', xml, parser.config_xml());
+            // TODO: this need to be replaced by real projectInfo
+            // instance for current project.
+            var project = {
+                root: projectRoot,
+                projectConfig: new ConfigParser(cordova_util.projectConfig(projectRoot)),
+                locations: {
+                    plugins: path.join(projectRoot, 'plugins'),
+                    www: cordova_util.projectWww(projectRoot)
                 }
-            }
-
-            var stagingPath = path.join(platformPath, '.staging');
-            if (fs.existsSync(stagingPath)) {
-                events.emit('log', 'Deleting now-obsolete intermediate directory: ' + stagingPath);
-                shell.rm('-rf', stagingPath);
-            }
-
-            // Replace the existing web assets with the app master versions
-            parser.update_www();
-
-            // Call plugman --prepare for this platform. sets up js-modules appropriately.
-            var plugins_dir = path.join(projectRoot, 'plugins');
-            events.emit('verbose', 'Calling plugman.prepare for platform "' + platform + '"');
-
-            if (options.browserify) {
-                plugman.prepare = require('../plugman/prepare-browserify');
-            }
-
-            return plugman.prepare(platformPath, platform, plugins_dir, null, true, pluginInfoProvider)
+            };
+
+            // platformApi prepare takes care of all functionality
+            // which previously had been executed by cordova.prepare:
+            //   - reset config.xml and then merge changes from project's one,
+            //   - update www directory from project's one and merge assets from platform_www,
+            //   - reapply config changes, made by plugins,
+            //   - update platform's project
+            // Please note that plugins' changes, such as installes js files, assets and
+            // config changes is not being reinstalled on each prepare.
+            var platformApi = platforms.getPlatformApi(platform);
+            return platformApi.prepare(project)
             .then(function () {
-                // Remove cordova-js-src from application www directory
-                // otherwise it will be included into resultant app bundle
-                var cordovaJsSrcPath = path.join(platformPath, 'www/cordova-js-src');
-                if(fs.existsSync(cordovaJsSrcPath)) {
-                    shell.rm('-rf', cordovaJsSrcPath);
-                }
-            }).then(function () {
-                // Make sure that config changes for each existing plugin is in place
-                var platformJson = PlatformJson.load(plugins_dir, platform);
-                var munger = new PlatformMunger(platform, platformPath, plugins_dir, platformJson, pluginInfoProvider);
-                munger.reapply_global_munge();
-                munger.save_all();
-
-                // Update platform config.xml based on top level config.xml
-                var cfg = new ConfigParser(xml);
-                var platform_cfg = new ConfigParser(parser.config_xml());
-                exports._mergeXml(cfg.doc.getroot(), platform_cfg.doc.getroot(), platform, true);
-
-                // CB-6976 Windows Universal Apps. For smooth transition and to prevent mass api failures
-                // we allow using windows8 tag for new windows platform
-                if (platform == 'windows') {
-                    exports._mergeXml(cfg.doc.getroot(), platform_cfg.doc.getroot(), 'windows8', true);
-                }
-
-                platform_cfg.write();
-
-                return parser.update_project(cfg);
+                if (options.browserify)
+                    return browserify(project, platformApi);
             });
-        })).then(function() {
-            return hooksRunner.fire('after_prepare', options);
+        }));
+    }).then(function() {
+        options.paths = options.platforms.map(function(platform) {
+            return platforms.getPlatformApi(platform).getPlatformInfo().locations.www;
         });
+        return hooksRunner.fire('after_prepare', options);
     }).then(function () {
         return restore.installPluginsFromConfigXML(options);
     });
 }
-
-var BLACKLIST = ['platform', 'feature','plugin','engine'];
-var SINGLETONS = ['content', 'author'];
-function mergeXml(src, dest, platform, clobber) {
-    // Do nothing for blacklisted tags.
-    if (BLACKLIST.indexOf(src.tag) != -1) return;
-
-    //Handle attributes
-    Object.getOwnPropertyNames(src.attrib).forEach(function (attribute) {
-        if (clobber || !dest.attrib[attribute]) {
-            dest.attrib[attribute] = src.attrib[attribute];
-        }
-    });
-    //Handle text
-    if (src.text && (clobber || !dest.text)) {
-        dest.text = src.text;
-    }
-    //Handle platform
-    if (platform) {
-        src.findall('platform[@name="' + platform + '"]').forEach(function (platformElement) {
-            platformElement.getchildren().forEach(mergeChild);
-        });
-    }
-
-    //Handle children
-    src.getchildren().forEach(mergeChild);
-
-    function mergeChild (srcChild) {
-        var srcTag = srcChild.tag,
-            destChild = new et.Element(srcTag),
-            foundChild,
-            query = srcTag + '',
-            shouldMerge = true;
-
-        if (BLACKLIST.indexOf(srcTag) === -1) {
-            if (SINGLETONS.indexOf(srcTag) !== -1) {
-                foundChild = dest.find(query);
-                if (foundChild) {
-                    destChild = foundChild;
-                    dest.remove(destChild);
-                }
-            } else {
-                //Check for an exact match and if you find one don't add
-                Object.getOwnPropertyNames(srcChild.attrib).forEach(function (attribute) {
-                    query += '[@' + attribute + '="' + srcChild.attrib[attribute] + '"]';
-                });
-                var foundChildren = dest.findall(query);
-                for(var i = 0; i < foundChildren.length; i++) {
-                    foundChild = foundChildren[i];
-                    if (foundChild && textMatch(srcChild, foundChild) && (Object.keys(srcChild.attrib).length==Object.keys(foundChild.attrib).length)) {
-                        destChild = foundChild;
-                        dest.remove(destChild);
-                        shouldMerge = false;
-                        break;
-                    }
-                }
-            }
-
-            mergeXml(srcChild, destChild, platform, clobber && shouldMerge);
-            dest.append(destChild);
-        }
-    }
-}
-
-// Expose for testing.
-exports._mergeXml = mergeXml;
-
-
-function textMatch(elm1, elm2) {
-    var text1 = elm1.text ? elm1.text.replace(/\s+/, '') : '',
-        text2 = elm2.text ? elm2.text.replace(/\s+/, '') : '';
-    return (text1 === '' || text1 === text2);
-}

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/07271a5c/cordova-lib/src/cordova/requirements.js
----------------------------------------------------------------------
diff --git a/cordova-lib/src/cordova/requirements.js b/cordova-lib/src/cordova/requirements.js
index 46a7284..a0fa79b 100644
--- a/cordova-lib/src/cordova/requirements.js
+++ b/cordova-lib/src/cordova/requirements.js
@@ -18,51 +18,31 @@
 */
 
 var cordova_util = require('./util');
-var events       = require('../events');
-var path         = require('path');
 var Q            = require('q');
 var CordovaError = require('../CordovaError');
+var knownPlatforms = require('../platforms/platforms');
 
 /**
  * Runs requirements check against platforms specified in 'platfoms' argument
  *
- * @param  {String[]} platforms List of platforms for requirements check. If none, all
- *                                      platforms, added to project will be checked
+ * @param  {String[]} platforms List of platforms for requirements check. If
+ *   none, all platforms, added to project will be checked
  *
- * @return {Promise}            Promise fullfilled with map of platforms and requirements
- *                                      check results for each platform
+ * @return {Promise<Object>}    Promise fullfilled with map of platforms and
+ *   requirements check results for each platform.
  */
 module.exports = function check_reqs(platforms) {
     platforms = cordova_util.preProcessOptions(platforms).platforms;
 
-    var projectRoot = cordova_util.isCordova();
-    var platformsDir = path.join(projectRoot, 'platforms');
-    var platformChecks = platforms.map(function (platform) {
-        var modulePath = path.join(platformsDir, platform, 'cordova', 'lib', 'check_reqs');
-        try {
-            events.emit('verbose', 'Checking requirements for ' + platform + ' platform');
-            return require(modulePath).check_all();
-        } catch (e) {
-            var errorMsg = 'Failed to check requirements for ' + platform + ' platform. ' +
-                'check_reqs module is missing for platform. Skipping it...';
-            return Q.reject(errorMsg);
-        }
-    });
-
-    var checks = {};
-
-    return Q.allSettled(platformChecks)
+    return Q.allSettled(platforms.map(function (platform) {
+        return knownPlatforms.getPlatformApi(platform).requirements();
+    }))
     .then(function (settledChecks) {
-
-        settledChecks.forEach(function (settledCheck, idx) {
+        return settledChecks.reduce(function (result, settledCheck, idx) {
             var platformName = platforms[idx];
-            var result  = settledCheck.state === 'fulfilled' ?
+            result[platformName] = settledCheck.state === 'fulfilled' ?
                 settledCheck.value :
                 new CordovaError(settledCheck.reason);
-
-            checks[platformName] = result;
-        });
-
-        return checks;
+        }, {});
     });
 };

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/07271a5c/cordova-lib/src/cordova/run.js
----------------------------------------------------------------------
diff --git a/cordova-lib/src/cordova/run.js b/cordova-lib/src/cordova/run.js
index b5c1e27..b739580 100644
--- a/cordova-lib/src/cordova/run.js
+++ b/cordova-lib/src/cordova/run.js
@@ -17,12 +17,12 @@
     under the License.
 */
 
-var cordova_util      = require('./util'),
-    path              = require('path'),
-    HooksRunner            = require('../hooks/HooksRunner'),
-    events            = require('../events'),
-    superspawn        = require('./superspawn'),
-    Q                 = require('q');
+var cordova_util = require('./util'),
+    HooksRunner  = require('../hooks/HooksRunner'),
+    events       = require('../events'),
+    Q            = require('q'),
+    platform_lib = require('../platforms/platforms');
+
 
 // Returns a promise.
 module.exports = function run(options) {
@@ -37,8 +37,9 @@ module.exports = function run(options) {
     }).then(function() {
         // Deploy in parallel (output gets intermixed though...)
         return Q.all(options.platforms.map(function(platform) {
-            var cmd = path.join(projectRoot, 'platforms', platform, 'cordova', 'run');
-            return superspawn.spawn(cmd, options.options, { printCommand: true, stdio: 'inherit', chmod: true });
+            return platform_lib
+                .getPlatformApi(platform)
+                .run(options.options);
         }));
     }).then(function() {
         return hooksRunner.fire('after_run', options);

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/07271a5c/cordova-lib/src/cordova/serve.js
----------------------------------------------------------------------
diff --git a/cordova-lib/src/cordova/serve.js b/cordova-lib/src/cordova/serve.js
index a187bb8..274f8e0 100644
--- a/cordova-lib/src/cordova/serve.js
+++ b/cordova-lib/src/cordova/serve.js
@@ -63,7 +63,6 @@ function processUrlPath(urlPath, request, response, do302, do404, serveFile) {
     }
 
     var firstSegment = /\/(.*?)\//.exec(urlPath);
-    var parser;
 
     if (!firstSegment) {
         doRoot();
@@ -77,8 +76,9 @@ function processUrlPath(urlPath, request, response, do302, do404, serveFile) {
     // Strip the platform out of the path.
     urlPath = urlPath.slice(platformId.length + 1);
 
+    var platformApi;
     try {
-        parser = platforms.getPlatformProject(platformId, path.join(projectRoot, 'platforms', platformId));
+        platformApi = platforms.getPlatformApi(platformId);
     } catch (e) {
         do404();
         return;
@@ -87,12 +87,12 @@ function processUrlPath(urlPath, request, response, do302, do404, serveFile) {
     var filePath = null;
 
     if (urlPath == '/config.xml') {
-        filePath = parser.config_xml();
+        filePath = platformApi.getPlatformInfo().configXml;
     } else if (urlPath == '/project.json') {
-        processAddRequest(request, response, platformId, projectRoot);
+        processAddRequest(request, response, platformApi);
         return;
     } else if (/^\/www\//.test(urlPath)) {
-        filePath = path.join(parser.www_dir(), urlPath.slice(5));
+        filePath = path.join(platformApi.getPlatformInfo().locations.www, urlPath.slice(5));
     } else if (/^\/+[^\/]*$/.test(urlPath)) {
         do302('/' + platformId + '/www/');
         return;
@@ -125,12 +125,11 @@ function calculateMd5(fileName) {
     return md5sum.digest('hex');
 }
 
-function processAddRequest(request, response, platformId, projectRoot) {
-    var parser = platforms.getPlatformProject(platformId, path.join(projectRoot, 'platforms', platformId));
-    var wwwDir = parser.www_dir();
+function processAddRequest(request, response, platformApi) {
+    var wwwDir = platformApi.getPlatformInfo().locations.www;
     var payload = {
-        'configPath': '/' + platformId + '/config.xml',
-        'wwwPath': '/' + platformId + '/www',
+        'configPath': '/' + platformApi.platform + '/config.xml',
+        'wwwPath': '/' + platformApi.platform + '/www',
         'wwwFileList': shell.find(wwwDir)
             .filter(function(a) { return !fs.statSync(a).isDirectory() && !/(^\.)|(\/\.)/.test(a); })
             .map(function(a) { return {'path': a.slice(wwwDir.length), 'etag': '' + calculateMd5(a)}; })

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/07271a5c/cordova-lib/src/cordova/targets.js
----------------------------------------------------------------------
diff --git a/cordova-lib/src/cordova/targets.js b/cordova-lib/src/cordova/targets.js
index ed0d40b..2f5566e 100644
--- a/cordova-lib/src/cordova/targets.js
+++ b/cordova-lib/src/cordova/targets.js
@@ -49,14 +49,11 @@ module.exports = function targets(options) {
     var projectRoot = cordova_util.cdProjectRoot();
     options = cordova_util.preProcessOptions(options);
 
-    // Remove --list from parameters
-    options.options.splice(options.options.indexOf('--list'), 1);
-
     var result = Q();
     options.platforms.forEach(function(platform) {
-        if (options.options.indexOf('--device') >= 0) {
+        if (options.options.device) {
             result = result.then(displayDevices.bind(null, projectRoot, platform, options.options));
-        } else if(options.options.indexOf('--emulator') >= 0) {
+        } else if(options.options.emulator) {
             result = result.then(displayVirtualDevices.bind(null, projectRoot, platform, options.options));
         } else {
             result = result.then(displayDevices.bind(null, projectRoot, platform, options.options))

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/07271a5c/cordova-lib/src/cordova/util.js
----------------------------------------------------------------------
diff --git a/cordova-lib/src/cordova/util.js b/cordova-lib/src/cordova/util.js
index 0231ec0..c177689 100644
--- a/cordova-lib/src/cordova/util.js
+++ b/cordova-lib/src/cordova/util.js
@@ -233,7 +233,7 @@ function preProcessOptions (inputOptions) {
     }
     result.verbose = result.verbose || false;
     result.platforms = result.platforms || [];
-    result.options = result.options || [];
+    result.options = result.options || {};
 
     var projectRoot = this.isCordova();
 
@@ -248,11 +248,8 @@ function preProcessOptions (inputOptions) {
         result.platforms = projectPlatforms;
     }
 
-    var buildConfigFound = result.options.some(function (option) {
-        return option.indexOf('--buildConfig') === 0;
-    });
-    if (!buildConfigFound && fs.existsSync(path.join(projectRoot, 'build.json'))) {
-        result.options.push('--buildConfig=' + path.join(projectRoot, 'build.json'));
+    if (!result.options.buildConfig && fs.existsSync(path.join(projectRoot, 'build.json'))) {
+        result.options.buildConfig = path.join(projectRoot, 'build.json');
     }
 
     return result;


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@cordova.apache.org
For additional commands, e-mail: commits-help@cordova.apache.org