You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cordova.apache.org by ge...@apache.org on 2015/03/11 14:20:17 UTC

[1/2] cordova-lib git commit: rename references to feature to plugin

Repository: cordova-lib
Updated Branches:
  refs/heads/master 5f0d7fcda -> 92f40d2d4


rename references to feature to plugin

renames the feature references used on tests


Project: http://git-wip-us.apache.org/repos/asf/cordova-lib/repo
Commit: http://git-wip-us.apache.org/repos/asf/cordova-lib/commit/92f40d2d
Tree: http://git-wip-us.apache.org/repos/asf/cordova-lib/tree/92f40d2d
Diff: http://git-wip-us.apache.org/repos/asf/cordova-lib/diff/92f40d2d

Branch: refs/heads/master
Commit: 92f40d2d42a35726fc4c280d011c4558ab18a447
Parents: 00316b3
Author: Gorkem Ercan <go...@gmail.com>
Authored: Wed Mar 11 09:16:49 2015 -0400
Committer: Gorkem Ercan <go...@gmail.com>
Committed: Wed Mar 11 09:18:20 2015 -0400

----------------------------------------------------------------------
 cordova-lib/spec-cordova/ConfigParser.spec.js | 42 +++++++++++-----------
 cordova-lib/spec-cordova/test-config.xml      | 10 +++---
 cordova-lib/src/configparser/ConfigParser.js  | 21 +++++++----
 cordova-lib/src/cordova/platform.js           | 24 ++++++-------
 4 files changed, 53 insertions(+), 44 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/92f40d2d/cordova-lib/spec-cordova/ConfigParser.spec.js
----------------------------------------------------------------------
diff --git a/cordova-lib/spec-cordova/ConfigParser.spec.js b/cordova-lib/spec-cordova/ConfigParser.spec.js
index 29275ce..f8813e7 100644
--- a/cordova-lib/spec-cordova/ConfigParser.spec.js
+++ b/cordova-lib/spec-cordova/ConfigParser.spec.js
@@ -117,60 +117,60 @@ describe('config.xml parser', function () {
         describe('plugin',function(){
             it('should read plugin id list', function() {
                var expectedList = [
-                   'org.apache.cordova.featurewithvars',
-                   'org.apache.cordova.featurewithurl',
-                   'org.apache.cordova.featurewithversion',
-                   'org.apache.cordova.featurewithurlandversion',
-                   'org.apache.cordova.justafeature',
+                   'org.apache.cordova.pluginwithvars',
+                   'org.apache.cordova.pluginwithurl',
+                   'org.apache.cordova.pluginwithversion',
+                   'org.apache.cordova.pluginwithurlandversion',
+                   'org.apache.cordova.justaplugin',
                    'org.apache.cordova.legacyfeature'
                ];
                var list = cfg.getPluginIdList();
                expect(list.length).toEqual(expectedList.length);
                expectedList.forEach(function(plugin){
-               expect(list).toContain(plugin);
+                   expect(list).toContain(plugin);
                });
             });
             it('should read plugin given id', function(){
-                var plugin = cfg.getPlugin('org.apache.cordova.justafeature');
+                var plugin = cfg.getPlugin('org.apache.cordova.justaplugin');
                 expect(plugin).toBeDefined();
-                expect(plugin.name).toEqual('org.apache.cordova.justafeature');
+                expect(plugin.name).toEqual('org.apache.cordova.justaplugin');
                 expect(plugin.variables).toBeDefined();
             });
             it('should not read plugin given undefined id', function(){
-                var plugin = cfg.getPlugin('org.apache.cordova.undefinedfeature');
+                var plugin = cfg.getPlugin('org.apache.cordova.undefinedplugin');
                 expect(plugin).not.toBeDefined();
             });
             it('should read plugin with src', function(){
-                var plugin = cfg.getPlugin('org.apache.cordova.featurewithurl');
-                expect(plugin.src).toEqual('http://cordova.apache.org/featurewithurl');
+                var plugin = cfg.getPlugin('org.apache.cordova.pluginwithurl');
+                expect(plugin.src).toEqual('http://cordova.apache.org/pluginwithurl');
             });
             it('should read plugin with version', function(){
-                var plugin = cfg.getPlugin('org.apache.cordova.featurewithversion');
+                var plugin = cfg.getPlugin('org.apache.cordova.pluginwithversion');
                 expect(plugin.version).toEqual('1.1.1');
             });
             it('should read plugin variables', function () {
-                var plugin = cfg.getPlugin('org.apache.cordova.featurewithvars');
+                var plugin = cfg.getPlugin('org.apache.cordova.pluginwithvars');
                 expect(plugin.variables).toBeDefined();
                 expect(plugin.variables.var).toBeDefined();
                 expect(plugin.variables.var).toEqual('varvalue');
             });
             it('should allow adding a new plugin', function(){
-                cfg.addPlugin({name:'myfeature'});
+                cfg.addPlugin({name:'myplugin'});
                 var plugins = cfg.doc.findall('plugin');
                 var pluginNames = plugins.map(function(plugin){
                     return plugin.attrib.name;
                 });
-                expect(pluginNames).toContain('myfeature');
+                expect(pluginNames).toContain('myplugin');
             });
             it('should allow adding features with params', function(){
-                cfg.addPlugin({name:'afeature'}, [{name:'paraname',value:'paravalue'}]);
+                cfg.addPlugin({name:'aplugin'}, [{name:'paraname',value:'paravalue'}]);
                 var plugins = cfg.doc.findall('plugin');
                 var plugin  = (function(){
                     var i = plugins.length;
                     var f;
                     while (--i >= 0) {
                         f = plugins[i];
-                        if ('afeature' === f.attrib.name) return f;
+                        if ('aplugin' === f.attrib.name) return f;
                     }
                     return undefined;
                 })();
@@ -188,20 +188,20 @@ describe('config.xml parser', function () {
                 expect(plugin.variables.aVar).toEqual('aValue');
             });
             it('it should remove given plugin', function(){
-                cfg.removePlugin('org.apache.cordova.justafeature');
+                cfg.removePlugin('org.apache.cordova.justaplugin');
                 var plugins = cfg.doc.findall('plugin');
                 var pluginNames = plugins.map(function(plugin){
                     return plugin.attrib.name;
                 });
-                expect(pluginNames).not.toContain('org.apache.cordova.justafeature');
+                expect(pluginNames).not.toContain('org.apache.cordova.justaplugin');
             });
             it('it should remove given legacy feature id', function(){
-                cfg.removePlugin('org.apache.cordova.legacyfeature');
+                cfg.removePlugin('org.apache.cordova.legacyplugin');
                 var plugins = cfg.doc.findall('feature');
                 var pluginNames = plugins.map(function(plugin){
                     return plugin.attrib.name;
                 });
-                expect(pluginNames).not.toContain('org.apache.cordova.legacyfeature');
+                expect(pluginNames).not.toContain('org.apache.cordova.legacyplugin');
             });
         });
     });

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/92f40d2d/cordova-lib/spec-cordova/test-config.xml
----------------------------------------------------------------------
diff --git a/cordova-lib/spec-cordova/test-config.xml b/cordova-lib/spec-cordova/test-config.xml
index b634087..e092cf0 100644
--- a/cordova-lib/spec-cordova/test-config.xml
+++ b/cordova-lib/spec-cordova/test-config.xml
@@ -19,13 +19,13 @@
         <preference name="android-minSdkVersion" value="10" />
         <preference name="orientation" value="landscape" />
     </platform>
-    <plugin name="org.apache.cordova.featurewithvars">
+    <plugin name="org.apache.cordova.pluginwithvars">
         <variable name="var" value="varvalue" />
     </plugin>
-    <plugin name="org.apache.cordova.featurewithurl" src="http://cordova.apache.org/featurewithurl" />
-    <plugin name="org.apache.cordova.featurewithversion" version="1.1.1" />
-    <plugin name="org.apache.cordova.featurewithurlandversion" src="http://cordova.apache.org/featurewithurlandversion" version="1.1.1" />
-    <plugin name="org.apache.cordova.justafeature" />
+    <plugin name="org.apache.cordova.pluginwithurl" src="http://cordova.apache.org/pluginwithurl" />
+    <plugin name="org.apache.cordova.pluginwithversion" version="1.1.1" />
+    <plugin name="org.apache.cordova.pluginwithurlandversion" src="http://cordova.apache.org/pluginwithurlandversion" version="1.1.1" />
+    <plugin name="org.apache.cordova.justaplugin" />
     <feature name="Legacy plugin entry">
         <param name="id" value="org.apache.cordova.legacyfeature" />
         <param name="version" value="1.2.3" />

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/92f40d2d/cordova-lib/src/configparser/ConfigParser.js
----------------------------------------------------------------------
diff --git a/cordova-lib/src/configparser/ConfigParser.js b/cordova-lib/src/configparser/ConfigParser.js
index c986bc1..bc1cb9e 100644
--- a/cordova-lib/src/configparser/ConfigParser.js
+++ b/cordova-lib/src/configparser/ConfigParser.js
@@ -270,7 +270,10 @@ ConfigParser.prototype = {
         return scriptElements.filter(filterScriptByHookType);
     },
    /**
-    * Returns a list of plugin (IDs)
+    * Returns a list of plugin (IDs). 
+    *
+    * This function also returns any plugin's that 
+    * were defined using the legacy <feature> tags.
     * @return {string[]} Array of plugin IDs
     */
     getPluginIdList: function () {
@@ -316,6 +319,9 @@ ConfigParser.prototype = {
     },
     /**
      * Retrives the plugin with the given id or null if not found.
+     *
+     * This function also returns any plugin's that 
+     * were defined using the legacy <feature> tags.
      * @name getPlugin
      * @function
      * @param {String} id
@@ -351,7 +357,10 @@ ConfigParser.prototype = {
         return plugin;
     },
     /**
-     * Remove the plugin entry with give name (id)
+     * Remove the plugin entry with give name (id).
+     *
+     * This function also operates on any plugin's that 
+     * were defined using the legacy <feature> tags.
      * @name removePlugin
      * @function
      * @param id name of the plugin
@@ -402,11 +411,11 @@ ConfigParser.prototype = {
     getEngines: function(){
         var engines = this.doc.findall('./engine');
         return engines.map(function(engine){
-        var version = engine.attrib.version;
+            var version = engine.attrib.version;
             return {
-        'name': engine.attrib.name,
-        'version': version ? version : null
-        };
+                'name': engine.attrib.name,
+                'version': version ? version : null
+            };
         });
     },
     write:function() {

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/92f40d2d/cordova-lib/src/cordova/platform.js
----------------------------------------------------------------------
diff --git a/cordova-lib/src/cordova/platform.js b/cordova-lib/src/cordova/platform.js
index 10c31a3..0e3c2e6 100644
--- a/cordova-lib/src/cordova/platform.js
+++ b/cordova-lib/src/cordova/platform.js
@@ -268,20 +268,20 @@ function getPlatformDetailsFromDir(dir, platformIfKnown){
     }
 
     return Q({
-    libDir: libDir,
-    platform: platform,
+        libDir: libDir,
+        platform: platform,
         version: version
     });
 }
 
 function getVersionFromConfigFile(platform, cfg) {
     if(!platform || ( !(platform in platforms) )){
-    throw new CordovaError('Invalid platform: ' + platform);
+        throw new CordovaError('Invalid platform: ' + platform);
     }
 
     // Get appropriate version from config.xml
     var engine = _.find(cfg.getEngines(), function(eng){
-    return eng.name.toLowerCase() === platform.toLowerCase();
+        return eng.name.toLowerCase() === platform.toLowerCase();
     });
 
     return engine && engine.version;
@@ -301,14 +301,14 @@ function remove(hooksRunner, projectRoot, targets, opts) {
     }).then(function() {
         var config_json = config.read(projectRoot);
         var autosave =  config_json.auto_save_platforms || false;
-    if(opts.save || autosave){
-        targets.forEach(function(target) {
-        var platformName = target.split('@')[0];
-        var xml = cordova_util.projectConfig(projectRoot);
-        var cfg = new ConfigParser(xml);
-        events.emit('log', 'Removing ' + target + ' from config.xml file ...');
-        cfg.removeEngine(platformName);
-        cfg.write();
+        if(opts.save || autosave){
+            targets.forEach(function(target) {
+                var platformName = target.split('@')[0];
+                var xml = cordova_util.projectConfig(projectRoot);
+                var cfg = new ConfigParser(xml);
+                events.emit('log', 'Removing ' + target + ' from config.xml file ...');
+                cfg.removeEngine(platformName);
+                cfg.write();
         });
     }
     }).then(function() {


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


[2/2] cordova-lib git commit: Deprecate the old feature syntax from config.xml

Posted by ge...@apache.org.
Deprecate the old feature syntax from config.xml

Deprecates the feature syntax and starts using the new plugin tags for
defining plugins. Adjusts the tests for the new logic. The old feature
syntax is still read or removed but all new entries are done with the new
syntax.


Project: http://git-wip-us.apache.org/repos/asf/cordova-lib/repo
Commit: http://git-wip-us.apache.org/repos/asf/cordova-lib/commit/00316b38
Tree: http://git-wip-us.apache.org/repos/asf/cordova-lib/tree/00316b38
Diff: http://git-wip-us.apache.org/repos/asf/cordova-lib/diff/00316b38

Branch: refs/heads/master
Commit: 00316b38bf96ad6bd0677780a36f9350a8a0d87b
Parents: 5f0d7fc
Author: Gorkem Ercan <go...@gmail.com>
Authored: Mon Mar 9 15:53:38 2015 -0400
Committer: Gorkem Ercan <go...@gmail.com>
Committed: Wed Mar 11 09:18:20 2015 -0400

----------------------------------------------------------------------
 cordova-lib/spec-cordova/ConfigParser.spec.js | 124 ++++++------
 cordova-lib/spec-cordova/test-config.xml      |  51 ++---
 cordova-lib/src/configparser/ConfigParser.js  | 216 +++++++++++----------
 cordova-lib/src/cordova/platform.js           |  37 ++--
 cordova-lib/src/cordova/plugin.js             |  37 ++--
 cordova-lib/src/cordova/prepare.js            |   2 +-
 cordova-lib/src/cordova/restore-util.js       |  18 +-
 7 files changed, 240 insertions(+), 245 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/00316b38/cordova-lib/spec-cordova/ConfigParser.spec.js
----------------------------------------------------------------------
diff --git a/cordova-lib/spec-cordova/ConfigParser.spec.js b/cordova-lib/spec-cordova/ConfigParser.spec.js
index 1449d7b..29275ce 100644
--- a/cordova-lib/spec-cordova/ConfigParser.spec.js
+++ b/cordova-lib/spec-cordova/ConfigParser.spec.js
@@ -114,78 +114,94 @@ describe('config.xml parser', function () {
                 expect(cfg.getPlatformPreference('orientation', 'foobar')).toEqual('');
             });
         });
-        describe('feature',function(){
-            it('should read feature id list', function() {
+        describe('plugin',function(){
+            it('should read plugin id list', function() {
                var expectedList = [
                    'org.apache.cordova.featurewithvars',
                    'org.apache.cordova.featurewithurl',
                    'org.apache.cordova.featurewithversion',
                    'org.apache.cordova.featurewithurlandversion',
-                   'org.apache.cordova.justafeature'
+                   'org.apache.cordova.justafeature',
+                   'org.apache.cordova.legacyfeature'
                ];
-               var list = cfg.getFeatureIdList();
+               var list = cfg.getPluginIdList();
                expect(list.length).toEqual(expectedList.length);
-               expectedList.forEach(function(feature){
-                   expect(list).toContain(feature);
+               expectedList.forEach(function(plugin){
+               expect(list).toContain(plugin);
                });
             });
-            it('should read feature given id', function(){
-                var feature = cfg.getFeature('org.apache.cordova.justafeature');
-                expect(feature).toBeDefined();
-                expect(feature.name).toEqual('A simple feature');
-                expect(feature.id).toEqual('org.apache.cordova.justafeature');
-                expect(feature.params).toBeDefined();
-                expect(feature.params.id).toBeDefined();
-                expect(feature.params.id).toEqual('org.apache.cordova.justafeature');
-            });
-            it('should not read feature given undefined id', function(){
-                var feature = cfg.getFeature('org.apache.cordova.undefinedfeature');
-                expect(feature).not.toBeDefined();
-            });
-            it('should read feature with url and set \'url\' param', function(){
-                var feature = cfg.getFeature('org.apache.cordova.featurewithurl');
-                expect(feature.url).toEqual('http://cordova.apache.org/featurewithurl');
-                expect(feature.params).toBeDefined();
-                expect(feature.params.url).toBeDefined();
-                expect(feature.params.url).toEqual('http://cordova.apache.org/featurewithurl');
-            });
-            it('should read feature with version and set \'version\' param', function(){
-                var feature = cfg.getFeature('org.apache.cordova.featurewithversion');
-                expect(feature.version).toEqual('1.1.1');
-                expect(feature.params).toBeDefined();
-                expect(feature.params.version).toBeDefined();
-                expect(feature.params.version).toEqual('1.1.1');
-            });
-            it('should read feature variables', function () {
-                var feature = cfg.getFeature('org.apache.cordova.featurewithvars');
-                expect(feature.variables).toBeDefined();
-                expect(feature.variables.var).toBeDefined();
-                expect(feature.variables.var).toEqual('varvalue');
-            });
-            it('should allow adding a new feature', function(){
-                cfg.addFeature('myfeature');
-                var features = cfg.doc.findall('feature');
-                var featureNames = features.map(function(feature){
-                    return feature.attrib.name;
+            it('should read plugin given id', function(){
+                var plugin = cfg.getPlugin('org.apache.cordova.justafeature');
+                expect(plugin).toBeDefined();
+                expect(plugin.name).toEqual('org.apache.cordova.justafeature');
+                expect(plugin.variables).toBeDefined();
+            });
+            it('should not read plugin given undefined id', function(){
+                var plugin = cfg.getPlugin('org.apache.cordova.undefinedfeature');
+                expect(plugin).not.toBeDefined();
+            });
+            it('should read plugin with src', function(){
+                var plugin = cfg.getPlugin('org.apache.cordova.featurewithurl');
+                expect(plugin.src).toEqual('http://cordova.apache.org/featurewithurl');
+            });
+            it('should read plugin with version', function(){
+                var plugin = cfg.getPlugin('org.apache.cordova.featurewithversion');
+                expect(plugin.version).toEqual('1.1.1');
+            });
+            it('should read plugin variables', function () {
+                var plugin = cfg.getPlugin('org.apache.cordova.featurewithvars');
+                expect(plugin.variables).toBeDefined();
+                expect(plugin.variables.var).toBeDefined();
+                expect(plugin.variables.var).toEqual('varvalue');
+            });
+            it('should allow adding a new plugin', function(){
+                cfg.addPlugin({name:'myfeature'});
+                var plugins = cfg.doc.findall('plugin');
+                var pluginNames = plugins.map(function(plugin){
+                    return plugin.attrib.name;
                 });
-                expect(featureNames).toContain('myfeature');
+                expect(pluginNames).toContain('myfeature');
             });
             it('should allow adding features with params', function(){
-                cfg.addFeature('afeature', JSON.parse('[{"name":"paraname", "value":"paravalue"}]'));
-                var features = cfg.doc.findall('feature');
-                var feature  = (function(){
-                    var i = features.length;
+                cfg.addPlugin({name:'afeature'}, [{name:'paraname',value:'paravalue'}]);
+                var plugins = cfg.doc.findall('plugin');
+                var plugin  = (function(){
+                    var i = plugins.length;
                     var f;
                     while (--i >= 0) {
-                        f = features[i];
+                        f = plugins[i];
                         if ('afeature' === f.attrib.name) return f;
                     }
                     return undefined;
                 })();
-                expect(feature).toBeDefined();
-                var params = feature.findall('param');
-                expect(params[0].attrib.name).toEqual('paraname');
-                expect(params[0].attrib.value).toEqual('paravalue');
+                expect(plugin).toBeDefined();
+                var variables = plugin.findall('variable');
+                expect(variables[0].attrib.name).toEqual('paraname');
+                expect(variables[0].attrib.value).toEqual('paravalue');
+            });
+            it('should be able to read legacy feature entries', function(){
+                var plugin = cfg.getPlugin('org.apache.cordova.legacyfeature');
+                expect(plugin).toBeDefined();
+                expect(plugin.name).toEqual('org.apache.cordova.legacyfeature');
+                expect(plugin.version).toEqual('1.2.3');
+                expect(plugin.variables).toBeDefined();
+                expect(plugin.variables.aVar).toEqual('aValue');
+            });
+            it('it should remove given plugin', function(){
+                cfg.removePlugin('org.apache.cordova.justafeature');
+                var plugins = cfg.doc.findall('plugin');
+                var pluginNames = plugins.map(function(plugin){
+                    return plugin.attrib.name;
+                });
+                expect(pluginNames).not.toContain('org.apache.cordova.justafeature');
+            });
+            it('it should remove given legacy feature id', function(){
+                cfg.removePlugin('org.apache.cordova.legacyfeature');
+                var plugins = cfg.doc.findall('feature');
+                var pluginNames = plugins.map(function(plugin){
+                    return plugin.attrib.name;
+                });
+                expect(pluginNames).not.toContain('org.apache.cordova.legacyfeature');
             });
         });
     });

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/00316b38/cordova-lib/spec-cordova/test-config.xml
----------------------------------------------------------------------
diff --git a/cordova-lib/spec-cordova/test-config.xml b/cordova-lib/spec-cordova/test-config.xml
index 21d91ab..b634087 100644
--- a/cordova-lib/spec-cordova/test-config.xml
+++ b/cordova-lib/spec-cordova/test-config.xml
@@ -1,53 +1,34 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<widget xmlns     = "http://www.w3.org/ns/widgets"
-        xmlns:cdv = "http://cordova.apache.org/ns/1.0"
-        id        = "io.cordova.hellocordova"
-        version   = "0.0.1"
-        android-packageName="io.cordova.hellocordova.android"
-        ios-CFBundleIdentifier="io.cordova.hellocordova.ios">
+<?xml version='1.0' encoding='utf-8'?>
+<widget android-packageName="io.cordova.hellocordova.android" id="io.cordova.hellocordova" ios-CFBundleIdentifier="io.cordova.hellocordova.ios" version="0.0.1" xmlns="http://www.w3.org/ns/widgets" xmlns:cdv="http://cordova.apache.org/ns/1.0">
     <name>Hello Cordova</name>
-
     <description>
         A sample Apache Cordova application that responds to the deviceready event.
     </description>
-
-    <author href="http://cordova.io" email="dev@cordova.apache.org">
+    <author email="dev@cordova.apache.org" href="http://cordova.io">
         Apache Cordova Team
     </author>
-
     <content src="index.html" />
-
     <access origin="*" />
     <preference name="fullscreen" value="true" />
     <preference name="webviewbounce" value="true" />
     <preference name="orientation" value="portrait" />
     <icon id="icon" src="icon.png" />
-    <icon id="logo" src="logo.png" width="255" height="255" />
+    <icon height="255" id="logo" src="logo.png" width="255" />
     <platform name="android">
-        <icon src="logo-android.png" width="255" height="255" density="mdpi" />
+        <icon density="mdpi" height="255" src="logo-android.png" width="255" />
         <preference name="android-minSdkVersion" value="10" />
         <preference name="orientation" value="landscape" />
     </platform>
-
-    <!-- Features -->
-    <feature name="A feature with preference">
-        <param name="id" value="org.apache.cordova.featurewithvars"/>
-        <param name="var" value="varvalue"/>
-    </feature>
-    <feature name="A feature with url">
-        <param name="id" value="org.apache.cordova.featurewithurl" />
-        <param name="url" value="http://cordova.apache.org/featurewithurl" />
-    </feature>
-    <feature name="A feature with version">
-        <param name="id" value="org.apache.cordova.featurewithversion" />
-        <param name="version" value="1.1.1" />
-    </feature>
-    <feature name="A feature with url and version">
-        <param name="id" value="org.apache.cordova.featurewithurlandversion" />
-        <param name="version" value="1.1.1" />
-        <param name="url" value="http://cordova.apache.org/featurewithurlandversion" />
-    </feature>
-    <feature name="A simple feature">
-        <param name="id" value="org.apache.cordova.justafeature" />
+    <plugin name="org.apache.cordova.featurewithvars">
+        <variable name="var" value="varvalue" />
+    </plugin>
+    <plugin name="org.apache.cordova.featurewithurl" src="http://cordova.apache.org/featurewithurl" />
+    <plugin name="org.apache.cordova.featurewithversion" version="1.1.1" />
+    <plugin name="org.apache.cordova.featurewithurlandversion" src="http://cordova.apache.org/featurewithurlandversion" version="1.1.1" />
+    <plugin name="org.apache.cordova.justafeature" />
+    <feature name="Legacy plugin entry">
+        <param name="id" value="org.apache.cordova.legacyfeature" />
+        <param name="version" value="1.2.3" />
+        <param name="aVar" value="aValue" />
     </feature>
 </widget>

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/00316b38/cordova-lib/src/configparser/ConfigParser.js
----------------------------------------------------------------------
diff --git a/cordova-lib/src/configparser/ConfigParser.js b/cordova-lib/src/configparser/ConfigParser.js
index 213432f..c986bc1 100644
--- a/cordova-lib/src/configparser/ConfigParser.js
+++ b/cordova-lib/src/configparser/ConfigParser.js
@@ -24,16 +24,6 @@ var et = require('elementtree'),
     CordovaError = require('../CordovaError'),
     fs = require('fs');
 
-/**
- * Array of 'feature' params that are set as properties
- * @type {string[]}
- */
-var FEATURE_SPECIAL_PARAMS = [
-    'id',
-    'url',
-    'version',
-    'installPath'
-];
 
 /** Wraps a config.xml file */
 function ConfigParser(path) {
@@ -279,113 +269,108 @@ ConfigParser.prototype = {
 
         return scriptElements.filter(filterScriptByHookType);
     },
-
+   /**
+    * Returns a list of plugin (IDs)
+    * @return {string[]} Array of plugin IDs
+    */
+    getPluginIdList: function () {
+        var plugins = this.doc.findall('plugin');
+        var result = plugins.map(function(plugin){
+            return plugin.attrib.name;
+        });
+        var features = this.doc.findall('feature');
+        features.forEach(function(element ){
+            var idTag = element.find('./param[@name="id"]');
+            if(idTag){
+                result.push(idTag.attrib.value);
+            }
+        });
+        return result;
+    },
     /**
-     * Returns a list of features (IDs)
-     * @return {string[]} Array of feature IDs
+     * Adds a plugin element. Does not check for duplicates.
+     * @name addPlugin
+     * @function
+     * @param {object} attributes name, version and src are supported
+     * @param {Array} variables name, value
      */
-    getFeatureIdList: function () {
-        var features = this.doc.findall('feature'),
-            feature, idTag, id,
-            result = [];
-
-        // Check for valid features that have IDs set
-        for (var i = 0, l = features.length; i < l; ++i) {
-            feature = features[i];
-            idTag = feature.find('./param[@name="id"]');
-            if (null === idTag) {
-                // Invalid feature
-                continue;
-            }
-            id = idTag.attrib.value;
-            if (!!id) {
-                // Has id and id is non-empty
-                result.push(id);
-            }
+    addPlugin: function(attributes, variables){
+        if ( !attributes && !attributes.name ) return;
+        var el = new et.Element('plugin');
+        el.attrib.name =attributes.name;
+        if ( attributes.version) {
+            el.attrib.version =attributes.version;
         }
-
-        return result;
+        if ( attributes.src){
+            el.attrib.src = attributes.src;
+        }
+        if(variables){
+            variables.forEach(function(variable){
+                var v = new et.Element('variable');
+                v.attrib.name=variable.name;
+                v.attrib.value=variable.value;
+                el.append(v);
+            });
+        }
+        this.doc.getroot().append(el);
     },
-
     /**
-     * Gets feature info
-     * @param {string} id Feature id
-     * @returns {Feature} Feature object
+     * Retrives the plugin with the given id or null if not found.
+     * @name getPlugin
+     * @function
+     * @param {String} id
+     * @returns {object} plugin including any variables
      */
-    getFeature: function(id) {
-        if (!id) {
+    getPlugin: function(id){
+        if(!id){
             return undefined;
         }
-        var feature = this.doc.find('./feature/param[@name="id"][@value="' + id + '"]/..');
-        if (null === feature) {
+        var pluginElement = this.doc.find('./plugin/[@name="' + id + '"]');
+        if (null === pluginElement) {
+            var legacyFeature =  this.doc.find('./feature/param[@name="id"][@value="' + id + '"]/..');
+            if(legacyFeature){
+                 var events = require('../events');
+                 events.emit('log', 'Found deprecated feature entry for ' + id +' in config.xml.');
+                return featureToPlugin(legacyFeature);
+            }
             return undefined;
         }
-
-        var result = {};
-        result.id = id;
-        result.name = feature.attrib.name;
-
-        // Iterate params and fill-in 'params' structure
-        // For special cases like 'id', 'url, 'version' - copy to the main space
-        result.params = processChildren (
-            'param',
-            function(name, value) {
-                if (FEATURE_SPECIAL_PARAMS.indexOf(name) >= 0) {
-                    result[name] = value;
-                }
+        var plugin = {};
+        plugin.name = pluginElement.attrib.name;
+        plugin.version = pluginElement.attrib.version;
+        plugin.src = pluginElement.attrib.src;
+        plugin.variables = {};
+        var variableElements = pluginElement.findall('variable');
+        variableElements.forEach(function(varElement){
+            var name = varElement.attrib.name;
+            var value = varElement.attrib.value;
+            if(name){
+                plugin.variables[name] = value;
             }
-        );
-
-        // Iterate preferences
-        result.variables = processChildren('param');
-
-        return result;
-
-        /**
-         * Processes a set of children
-         * having a pair of 'name' and 'value' attributes
-         * filling in 'output' object
-         * @param {string} xPath Search expression
-         * @param {function} [specialProcessing] Performs some additional actions on each valid element
-         * @return {object} A transformed object
-         */
-        function processChildren (xPath, specialProcessing) {
-            var result = {};
-            var needsProcessing = 'function' === typeof specialProcessing;
-            var nodes = feature.findall(xPath);
-            nodes.forEach(function(param){
-                var name = param.attrib.name;
-                var value = param.attrib.value;
-                if (name) {
-                    result[name] = value;
-                    if (needsProcessing) {
-                        specialProcessing(name, value);
-                    }
-                }
-            });
-            return result;
-        }
+        });
+        return plugin;
     },
-
-
     /**
-     *This does not check for duplicate feature entries
+     * Remove the plugin entry with give name (id)
+     * @name removePlugin
+     * @function
+     * @param id name of the plugin
      */
-    addFeature: function (name, params){
-        if(!name) return;
-        var el = new et.Element('feature');
-        el.attrib.name = name;
-        if (params) {
-            params.forEach(function(param){
-                var p = new et.Element('param');
-                p.attrib.name = param.name;
-                p.attrib.value = param.value;
-                el.append(p);
-            });
+    removePlugin: function(id){
+        if(id){
+            var theElement = this.doc.find('./plugin/[@name="' + id + '"]');
+            if(!theElement){
+                theElement = this.doc.find('./feature/param[@name="id"][@value="' + id + '"]/..');
+            }
+            if(theElement){
+                var childs = this.doc.getroot().getchildren();
+                var idx = childs.indexOf(theElement);
+                if(idx > -1){
+                    childs.splice(idx,1);
+                }
+            }
         }
-        this.doc.getroot().append(el);
     },
-
     /**
      * Adds an engine. Does not check for duplicates.
      * @param  {String} name the engine name
@@ -417,11 +402,11 @@ ConfigParser.prototype = {
     getEngines: function(){
         var engines = this.doc.findall('./engine');
         return engines.map(function(engine){
-	    var version = engine.attrib.version;
+        var version = engine.attrib.version;
             return {
-		'name': engine.attrib.name,
-		'version': version ? version : null
-	    };
+        'name': engine.attrib.name,
+        'version': version ? version : null
+        };
         });
     },
     write:function() {
@@ -429,4 +414,25 @@ ConfigParser.prototype = {
     }
 };
 
+function featureToPlugin(featureElement){
+    var plugin = {};
+    plugin.variables=[];
+    var nodes = featureElement.findall('param');
+    nodes.forEach(function(element){
+        var n = element.attrib.name;
+        var v = element.attrib.value;
+        if(n === 'id'){
+            plugin.name = v;
+        }else
+        if(n === 'version'){
+            plugin.version = v;
+        }else
+        if(n === 'url' || n === 'installPath'){
+            plugin.src = v;
+        }else{
+            plugin.variables[n] = v;
+        }
+    });
+    return plugin; 
+}
 module.exports = ConfigParser;

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/00316b38/cordova-lib/src/cordova/platform.js
----------------------------------------------------------------------
diff --git a/cordova-lib/src/cordova/platform.js b/cordova-lib/src/cordova/platform.js
index 03bd775..10c31a3 100644
--- a/cordova-lib/src/cordova/platform.js
+++ b/cordova-lib/src/cordova/platform.js
@@ -268,20 +268,20 @@ function getPlatformDetailsFromDir(dir, platformIfKnown){
     }
 
     return Q({
-	libDir: libDir,
-	platform: platform,
+    libDir: libDir,
+    platform: platform,
         version: version
     });
 }
 
 function getVersionFromConfigFile(platform, cfg) {
     if(!platform || ( !(platform in platforms) )){
-	throw new CordovaError('Invalid platform: ' + platform);
+    throw new CordovaError('Invalid platform: ' + platform);
     }
 
     // Get appropriate version from config.xml
     var engine = _.find(cfg.getEngines(), function(eng){
-	return eng.name.toLowerCase() === platform.toLowerCase();
+    return eng.name.toLowerCase() === platform.toLowerCase();
     });
 
     return engine && engine.version;
@@ -301,16 +301,16 @@ function remove(hooksRunner, projectRoot, targets, opts) {
     }).then(function() {
         var config_json = config.read(projectRoot);
         var autosave =  config_json.auto_save_platforms || false;
-	if(opts.save || autosave){
-	    targets.forEach(function(target) {
-		var platformName = target.split('@')[0];
-		var xml = cordova_util.projectConfig(projectRoot);
-		var cfg = new ConfigParser(xml);
-		events.emit('log', 'Removing ' + target + ' from config.xml file ...');
-		cfg.removeEngine(platformName);
-		cfg.write();
-	    });
-	}
+    if(opts.save || autosave){
+        targets.forEach(function(target) {
+        var platformName = target.split('@')[0];
+        var xml = cordova_util.projectConfig(projectRoot);
+        var cfg = new ConfigParser(xml);
+        events.emit('log', 'Removing ' + target + ' from config.xml file ...');
+        cfg.removeEngine(platformName);
+        cfg.write();
+        });
+    }
     }).then(function() {
         // Remove targets from platforms.json
         targets.forEach(function(target) {
@@ -503,11 +503,11 @@ function platform(command, targets, opts) {
             if (fs.existsSync(pPath)) return;
 
             var msg;
-	    // If target looks like a url, we will try cloning it with git
+        // If target looks like a url, we will try cloning it with git
             if (/[~:/\\.]/.test(t)) {
                 return;
             } else {
-		// Neither path, git-url nor platform name - throw.
+        // Neither path, git-url nor platform name - throw.
                 msg = 'Platform "' + t +
                 '" not recognized as a core cordova platform. See `' +
                 cordova_util.binname + ' platform list`.'
@@ -589,7 +589,6 @@ function getCreateArgs(platDetails, projectRoot, cfg, template_dir, opts) {
     if (opts.link) {
         args.push('--link');
     }
-
     return args;
 }
 
@@ -609,8 +608,8 @@ function installPluginsForNewPlatform(platform, projectRoot, cfg, opts) {
             var options = (function(){
                 // Get plugin preferences from config features if have any
                 // Pass them as cli_variables to plugman
-                var feature = cfg.getFeature(plugin);
-                var variables = feature && feature.variables;
+                var pluginEntry = cfg.getPlugin(plugin);
+                var variables = pluginEntry && pluginEntry.variables;
                 if (!!variables) {
                     events.emit('verbose', 'Found variables for "' + plugin + '". Processing as cli_variables.');
                     return {

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/00316b38/cordova-lib/src/cordova/plugin.js
----------------------------------------------------------------------
diff --git a/cordova-lib/src/cordova/plugin.js b/cordova-lib/src/cordova/plugin.js
index 497722f..08cb09e 100644
--- a/cordova-lib/src/cordova/plugin.js
+++ b/cordova-lib/src/cordova/plugin.js
@@ -140,35 +140,37 @@ module.exports = function plugin(command, targets, opts) {
                         // save to config.xml 
                         if(saveToConfigXmlOn(config_json,opts)){
                             var pluginInfo =  pluginInfoProvider.get(dir);
-                            var existingFeature = cfg.getFeature(pluginInfo.id);
-                            if(!existingFeature){
-                                var params = [{name:'id', value:pluginInfo.id}];
+                            var existingPluginEntry = cfg.getPlugin(pluginInfo.id);
+                            if(!existingPluginEntry){
+                                var attributes = {};
+                                attributes.name = pluginInfo.id;
                                 var pluginVersion = versionFromTargetString(target);
                                 if(!pluginVersion && opts.shrinkwrap){
                                     pluginVersion = pluginInfo.version;
                                 }
                                 if(pluginVersion){
-                                    params.push({ name: 'version', value: pluginVersion});
+                                    attributes.version = pluginVersion;
                                 }
                                 var url = require('url');
 
                                 var uri = url.parse(target);
                                 if ( uri.protocol && uri.protocol != 'file:' && uri.protocol[1] != ':' && !target.match(/^\w+:\\/)) {
-                                    params.push({name:'url', value:target});
+                                    attributes.src = target;
                                 }else{
                                     var plugin_dir = cordova_util.fixRelativePath(path.join(target,  (opts.subdir || '.') ));
                                     if (fs.existsSync(plugin_dir)) {
-                                        params.push({name:'installPath', value:target});
+                                        attributes.src = target;
                                     }
                                 }
+                                var variables = [];
                                 if(opts.cli_variables){
                                     for(var varname in opts.cli_variables){
                                         if(opts.cli_variables.hasOwnProperty(varname)){
-                                            params.push({name:varname, value:opts.cli_variables[varname]});
+                                            variables.push({name:varname, value:opts.cli_variables[varname]});
                                         }
                                     } 
                                 }
-                                cfg.addFeature(pluginInfo.name, params);
+                                cfg.addPlugin(attributes,variables);
                                 cfg.write();
                                 events.emit('results', 'Saved plugin info for "'+pluginInfo.id+'" to config.xml');
                             }else{
@@ -255,7 +257,6 @@ module.exports = function plugin(command, targets, opts) {
                     // If this is a web-only or dependency-only plugin, then
                     // there may be nothing to do here except remove the
                     // reference from the platform's plugin config JSON.
-                    var plugman = require('../plugman/plugman');
                     return platformList.reduce(function(soFar, platform) {
                         return soFar.then(function() {
                             var platformRoot = path.join(projectRoot, 'platforms', platform);
@@ -272,16 +273,9 @@ module.exports = function plugin(command, targets, opts) {
                             var configPath = cordova_util.projectConfig(projectRoot);
                             if(fs.existsSync(configPath)){//should not happen with real life but needed for tests
                                 var configXml = new ConfigParser(configPath);
-                                var feature = configXml.doc.find('./feature/param[@name="id"][@value="' + target + '"]/..');
-                                if(feature){
-                                    var childs = configXml.doc.getroot().getchildren();
-                                    var idx = childs.indexOf(feature);
-                                    if(idx > -1){
-                                        childs.splice(idx,1);
-                                    }
-                                    configXml.write();
-                                    events.emit('results', 'config.xml entry for ' +target+ ' is removed');
-                                }
+                                configXml.removePlugin(target);
+                                configXml.write();
+                                events.emit('results', 'config.xml entry for ' +target+ ' is removed');
                             }
                         }
                     });
@@ -293,7 +287,6 @@ module.exports = function plugin(command, targets, opts) {
         case 'search':
             return hooksRunner.fire('before_plugin_search')
             .then(function() {
-                var plugman = require('../plugman/plugman');
                 return plugman.raw.search(opts.plugins);
             }).then(function(plugins) {
                 for(var plugin in plugins) {
@@ -308,8 +301,8 @@ module.exports = function plugin(command, targets, opts) {
 };
 
 function getVersionFromConfigFile(plugin, cfg){
-    var feature = cfg.getFeature(plugin); 
-    return feature && (feature.params.url || feature.params.installPath || feature.params.version);
+    var pluginEntry = cfg.getPlugin(plugin);
+    return pluginEntry && pluginEntry.version; 
 }
 
 function list(projectRoot, hooksRunner) {

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/00316b38/cordova-lib/src/cordova/prepare.js
----------------------------------------------------------------------
diff --git a/cordova-lib/src/cordova/prepare.js b/cordova-lib/src/cordova/prepare.js
index a956695..9256423 100644
--- a/cordova-lib/src/cordova/prepare.js
+++ b/cordova-lib/src/cordova/prepare.js
@@ -133,7 +133,7 @@ function prepare(options) {
     });
 }
 
-var BLACKLIST = ['platform', 'feature'];
+var BLACKLIST = ['platform', 'feature','plugin','engine'];
 var SINGLETONS = ['content', 'author'];
 function mergeXml(src, dest, platform, clobber) {
     // Do nothing for blacklisted tags.

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/00316b38/cordova-lib/src/cordova/restore-util.js
----------------------------------------------------------------------
diff --git a/cordova-lib/src/cordova/restore-util.js b/cordova-lib/src/cordova/restore-util.js
index 6bf6eb7..c5f6234 100644
--- a/cordova-lib/src/cordova/restore-util.js
+++ b/cordova-lib/src/cordova/restore-util.js
@@ -82,27 +82,27 @@ function installPluginsFromConfigXML(args) {
     var plugins_dir = path.join(projectRoot, 'plugins');
 
     // Get all configured plugins
-    var features = cfg.getFeatureIdList();
-    if (0 === features.length) {
+    var plugins = cfg.getPluginIdList();
+    if (0 === plugins.length) {
         return Q.all('No config.xml plugins to install');
     }
 
-    var promises = features.map(function(featureId){
+    var promises = plugins.map(function(featureId){
         var pluginPath =  path.join(plugins_dir, featureId);
         if (fs.existsSync(pluginPath)) {
             // Plugin already exists
             return Q();
         }
-        events.emit('log', 'Discovered ' + featureId + ' in config.xml. Installing to the project');
-        var feature = cfg.getFeature(featureId);
+        events.emit('log', 'Discovered plugin "' + featureId + '" in config.xml. Installing to the project');
+        var pluginEntry = cfg.getPlugin(featureId);
 
         // Install from given URL if defined or using a plugin id
-        var installFrom = feature.url || feature.installPath || feature.id;
-        if( feature.version && !feature.url && !feature.installPath ){
-            installFrom += ('@' + feature.version);
+        var installFrom = pluginEntry.src || pluginEntry.name;
+        if( pluginEntry.version && !pluginEntry.src ){
+            installFrom += ('@' + pluginEntry.version);
         }
         // Add feature preferences as CLI variables if have any
-        var options = {cli_variables: feature.variables, 
+        var options = {cli_variables: pluginEntry.variables, 
             searchpath: args.searchpath };
             return plugin('add', installFrom, options);
     });


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