You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cordova.apache.org by ag...@apache.org on 2014/03/31 20:43:15 UTC

git commit: Revert "CB-6344: Specify after which sibling to add config-changes in plugin.xml"

Repository: cordova-plugman
Updated Branches:
  refs/heads/master 54fc8582c -> e85004a12


Revert "CB-6344: Specify after which sibling to add config-changes in plugin.xml"

This reverts commit ac1160d470db03c2d2de2bbd7ad0ece336cf0394.

It broke CLI's unit tests.


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

Branch: refs/heads/master
Commit: e85004a125cd43f14203eeffea265a40a06cb6e4
Parents: 54fc858
Author: Andrew Grieve <ag...@chromium.org>
Authored: Mon Mar 31 14:42:46 2014 -0400
Committer: Andrew Grieve <ag...@chromium.org>
Committed: Mon Mar 31 14:42:46 2014 -0400

----------------------------------------------------------------------
 spec/platforms/wp8.spec.js          |  21 ---
 spec/plugins/DummyPlugin/plugin.xml |  22 ---
 spec/util/config-changes.spec.js    |  70 +++++-----
 spec/util/xml-helpers.spec.js       |  27 ----
 src/util/config-changes.js          | 228 ++++++++++---------------------
 src/util/xml-helpers.js             |  24 +---
 6 files changed, 107 insertions(+), 285 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-plugman/blob/e85004a1/spec/platforms/wp8.spec.js
----------------------------------------------------------------------
diff --git a/spec/platforms/wp8.spec.js b/spec/platforms/wp8.spec.js
index 2b0f265..398e567 100644
--- a/spec/platforms/wp8.spec.js
+++ b/spec/platforms/wp8.spec.js
@@ -70,11 +70,6 @@ describe('wp8 project handler', function() {
     });
 
     describe('installation', function() {
-        var done;
-        function installPromise(f) {
-            done = false;
-            f.then(function() { done = true; }, function(err) { done = err; });
-        }
         beforeEach(function() {
             shell.mkdir('-p', temp);
         });
@@ -107,22 +102,6 @@ describe('wp8 project handler', function() {
                 }).toThrow('"' + target + '" already exists!');
             });
         });
-        describe('of <config-changes> elements', function() {
-            beforeEach(function() {
-                shell.cp('-rf', path.join(wp8_project, '*'), temp);
-            });
-            it('should process and pass the after parameter to graftXML', function () {
-                var graftXML = spyOn(xml_helpers, 'graftXML').andCallThrough();
-
-                runs(function () { installPromise(install('wp8', temp, dummyplugin, plugins_dir, {})); });
-                waitsFor(function () { return done; }, 'install promise never resolved', 500);
-                runs(function () {
-                    expect(graftXML).toHaveBeenCalledWith(jasmine.any(Object), jasmine.any(Array), "/Deployment/App", "Tokens");
-                    expect(graftXML).toHaveBeenCalledWith(jasmine.any(Object), jasmine.any(Array), "/Deployment/App/Extensions", "Extension");
-                    expect(graftXML).toHaveBeenCalledWith(jasmine.any(Object), jasmine.any(Array), "/Deployment/App/Extensions", "FileTypeAssociation;Extension");
-                });
-            });
-        });
     });
 
     describe('uninstallation', function() {

http://git-wip-us.apache.org/repos/asf/cordova-plugman/blob/e85004a1/spec/plugins/DummyPlugin/plugin.xml
----------------------------------------------------------------------
diff --git a/spec/plugins/DummyPlugin/plugin.xml b/spec/plugins/DummyPlugin/plugin.xml
index 4733afb..39642e2 100644
--- a/spec/plugins/DummyPlugin/plugin.xml
+++ b/spec/plugins/DummyPlugin/plugin.xml
@@ -155,28 +155,6 @@
             <feature id="dummyPlugin" required="true" version="1.0.0.0"/>
         </config-file>
 
-        <config-file target="Properties/WMAppManifest.xml" parent="/Deployment/App" after="Tokens">
-            <Extensions />
-        </config-file>
-
-        <config-file target="Properties/WMAppManifest.xml" parent="/Deployment/App/Extensions" after="Extension">
-            <Extension ExtensionName="DummyExtension1" ConsumerID="{5B04B775-356B-4AA0-AAF8-6491FFEA5661}" TaskID="_default" ExtraFile="Extensions\\Extras.xml" />
-            <Extension ExtensionName="DummyExtension2" ConsumerID="{5B04B775-356B-4AA0-AAF8-6491FFEA5661}" TaskID="_default" ExtraFile="Extensions\\Extras.xml" />
-        </config-file>
-
-        <config-file target="Properties/WMAppManifest.xml" parent="/Deployment/App/Extensions" after="FileTypeAssociation;Extension">
-            <FileTypeAssociation TaskID="_default" Name="DummyFileType1" NavUriFragment="fileToken=%s">
-                <SupportedFileTypes>
-                    <FileType ContentType="application/dummy1">.dummy1</FileType>
-                </SupportedFileTypes>
-            </FileTypeAssociation>
-            <FileTypeAssociation TaskID="_default" Name="DummyFileType2" NavUriFragment="fileToken=%s">
-                <SupportedFileTypes>
-                    <FileType ContentType="application/dummy2">.dummy2</FileType>
-                </SupportedFileTypes>
-            </FileTypeAssociation>
-        </config-file>
-
         <source-file src="src/wp8/DummyPlugin.cs"/>
         <js-module src="www/dummyplugin.js" name="Dummy">
             <clobbers target="dummy" />

http://git-wip-us.apache.org/repos/asf/cordova-plugman/blob/e85004a1/spec/util/config-changes.spec.js
----------------------------------------------------------------------
diff --git a/spec/util/config-changes.spec.js b/spec/util/config-changes.spec.js
index 2efae84..3c3c918 100644
--- a/spec/util/config-changes.spec.js
+++ b/spec/util/config-changes.spec.js
@@ -118,10 +118,7 @@ describe('config-changes module', function() {
         });
         it('should return the json file if it exists', function() {
             var filepath = path.join(plugins_dir, 'android.json');
-            var json = {
-                prepare_queue: {installed: [], uninstalled: []},
-                config_munge: {files: {"some_file": {parents: {"some_parent": [{"xml": "some_change", "count": 1}]}}}},
-                installed_plugins: {}};
+            var json = {prepare_queue:{installed:[],uninstalled:[]},config_munge:{somechange:"blah"},installed_plugins:{}};
             fs.writeFileSync(filepath, JSON.stringify(json), 'utf-8');
             var cfg = configChanges.get_platform_json(plugins_dir, 'android');
             expect(JSON.stringify(json)).toEqual(JSON.stringify(cfg));
@@ -147,65 +144,64 @@ describe('config-changes module', function() {
                 var xml;
                 var munger = new configChanges.PlatformMunger('android', temp, 'unused');
                 var munge = munger.generate_plugin_config_munge(dummyplugin, {});
-                expect(munge.files['AndroidManifest.xml']).toBeDefined();
-                expect(munge.files['AndroidManifest.xml'].parents['/manifest/application']).toBeDefined();
+                expect(munge['AndroidManifest.xml']).toBeDefined();
+                expect(munge['AndroidManifest.xml']['/manifest/application']).toBeDefined();
                 xml = (new et.ElementTree(dummy_xml.find('./platform[@name="android"]/config-file[@target="AndroidManifest.xml"]'))).write({xml_declaration:false});
                 xml = innerXML(xml);
-                expect(configChanges.get_munge_change(munge, 'AndroidManifest.xml', '/manifest/application', xml).count).toEqual(1);
-                expect(munge.files['res/xml/plugins.xml']).toBeDefined();
-                expect(munge.files['res/xml/plugins.xml'].parents['/plugins']).toBeDefined();
+                expect(munge['AndroidManifest.xml']['/manifest/application'][xml]).toEqual(1);
+                expect(munge['res/xml/plugins.xml']).toBeDefined();
+                expect(munge['res/xml/plugins.xml']['/plugins']).toBeDefined();
                 xml = (new et.ElementTree(dummy_xml.find('./platform[@name="android"]/config-file[@target="res/xml/plugins.xml"]'))).write({xml_declaration:false});
                 xml = innerXML(xml);
-                expect(configChanges.get_munge_change(munge, 'res/xml/plugins.xml', '/plugins', xml).count).toEqual(1);
-                expect(munge.files['res/xml/config.xml']).toBeDefined();
-                expect(munge.files['res/xml/config.xml'].parents['/cordova/plugins']).toBeDefined();
+                expect(munge['res/xml/plugins.xml']['/plugins'][xml]).toEqual(1);
+                expect(munge['res/xml/config.xml']).toBeDefined();
+                expect(munge['res/xml/config.xml']['/cordova/plugins']).toBeDefined();
                 xml = (new et.ElementTree(dummy_xml.find('./platform[@name="android"]/config-file[@target="res/xml/config.xml"]'))).write({xml_declaration:false});
                 xml = innerXML(xml);
-                expect(configChanges.get_munge_change(munge, 'res/xml/config.xml', '/cordova/plugins', xml).count).toEqual(1);
+                expect(munge['res/xml/config.xml']['/cordova/plugins'][xml]).toEqual(1);
             });
             it('should split out multiple children of config-file elements into individual leaves', function() {
                 var munger = new configChanges.PlatformMunger('android', temp, 'unused');
                 var munge = munger.generate_plugin_config_munge(childrenplugin, {});
-                expect(munge.files['AndroidManifest.xml']).toBeDefined();
-                expect(munge.files['AndroidManifest.xml'].parents['/manifest']).toBeDefined();
-                expect(configChanges.get_munge_change(munge, 'AndroidManifest.xml', '/manifest', '<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />')).toBeDefined();
-                expect(configChanges.get_munge_change(munge, 'AndroidManifest.xml', '/manifest', '<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />')).toBeDefined();
-                expect(configChanges.get_munge_change(munge, 'AndroidManifest.xml', '/manifest', '<uses-permission android:name="android.permission.READ_PHONE_STATE" />')).toBeDefined();
-                expect(configChanges.get_munge_change(munge, 'AndroidManifest.xml', '/manifest', '<uses-permission android:name="android.permission.INTERNET" />')).toBeDefined();
-                expect(configChanges.get_munge_change(munge, 'AndroidManifest.xml', '/manifest', '<uses-permission android:name="android.permission.GET_ACCOUNTS" />')).toBeDefined();
-                expect(configChanges.get_munge_change(munge, 'AndroidManifest.xml', '/manifest', '<uses-permission android:name="android.permission.WAKE_LOCK" />')).toBeDefined();
-                expect(configChanges.get_munge_change(munge, 'AndroidManifest.xml', '/manifest', '<permission android:name="com.alunny.childapp.permission.C2D_MESSAGE" android:protectionLevel="signature" />')).toBeDefined();
-                expect(configChanges.get_munge_change(munge, 'AndroidManifest.xml', '/manifest', '<uses-permission android:name="com.alunny.childapp.permission.C2D_MESSAGE" />')).toBeDefined();
-                expect(configChanges.get_munge_change(munge, 'AndroidManifest.xml', '/manifest', '<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />')).toBeDefined();
+                expect(munge['AndroidManifest.xml']).toBeDefined();
+                expect(munge['AndroidManifest.xml']['/manifest']).toBeDefined();
+                expect(munge['AndroidManifest.xml']['/manifest']['<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />']).toBeDefined();
+                expect(munge['AndroidManifest.xml']['/manifest']['<uses-permission android:name="android.permission.READ_PHONE_STATE" />']).toBeDefined();
+                expect(munge['AndroidManifest.xml']['/manifest']['<uses-permission android:name="android.permission.INTERNET" />']).toBeDefined();
+                expect(munge['AndroidManifest.xml']['/manifest']['<uses-permission android:name="android.permission.GET_ACCOUNTS" />']).toBeDefined();
+                expect(munge['AndroidManifest.xml']['/manifest']['<uses-permission android:name="android.permission.WAKE_LOCK" />']).toBeDefined();
+                expect(munge['AndroidManifest.xml']['/manifest']['<permission android:name="com.alunny.childapp.permission.C2D_MESSAGE" android:protectionLevel="signature" />']).toBeDefined();
+                expect(munge['AndroidManifest.xml']['/manifest']['<uses-permission android:name="com.alunny.childapp.permission.C2D_MESSAGE" />']).toBeDefined();
+                expect(munge['AndroidManifest.xml']['/manifest']['<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />']).toBeDefined();
             });
             it('should not use xml comments as config munge leaves', function() {
                 var munger = new configChanges.PlatformMunger('android', temp, 'unused');
                 var munge = munger.generate_plugin_config_munge(childrenplugin, {});
-                expect(configChanges.get_munge_change(munge, 'AndroidManifest.xml', '/manifest', '<!--library-->')).not.toBeDefined();
-                expect(configChanges.get_munge_change(munge, 'AndroidManifest.xml', '/manifest', '<!-- GCM connects to Google Services. -->')).not.toBeDefined();
+                expect(munge['AndroidManifest.xml']['/manifest']['<!--library-->']).not.toBeDefined();
+                expect(munge['AndroidManifest.xml']['/manifest']['<!-- GCM connects to Google Services. -->']).not.toBeDefined();
             });
             it('should increment config heirarchy leaves if dfferent config-file elements target the same file + selector + xml', function() {
                 var munger = new configChanges.PlatformMunger('android', temp, 'unused');
                 var munge = munger.generate_plugin_config_munge(configplugin, {});
-                expect(configChanges.get_munge_change(munge, 'res/xml/config.xml', '/widget', '<poop />').count).toEqual(2);
+                expect(munge['res/xml/config.xml']['/widget']['<poop />']).toEqual(2);
             });
             it('should take into account interpolation variables', function() {
                 var munger = new configChanges.PlatformMunger('android', temp, 'unused');
                 var munge = munger.generate_plugin_config_munge(childrenplugin, {PACKAGE_NAME:'ca.filmaj.plugins'});
-                expect(configChanges.get_munge_change(munge, 'AndroidManifest.xml', '/manifest', '<uses-permission android:name="ca.filmaj.plugins.permission.C2D_MESSAGE" />')).toBeDefined();
+                expect(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');
                 var munge = munger.generate_plugin_config_munge(dummyplugin, {});
-                expect(configChanges.get_munge_change(munge, 'config.xml', '/*', '<access origin="build.phonegap.com" />')).toBeDefined();
-                expect(configChanges.get_munge_change(munge, 'config.xml', '/*', '<access origin="s3.amazonaws.com" />')).toBeDefined();
+                expect(munge['config.xml']['/*']['<access origin="build.phonegap.com" />']).toBeDefined();
+                expect(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');
                 var munge = munger.generate_plugin_config_munge(varplugin, {});
                 var expected_xml = '<package>com.alunny.childapp</package>';
-                expect(configChanges.get_munge_change(munge, 'AndroidManifest.xml', '/manifest', expected_xml)).toBeDefined();
+                expect(munge['AndroidManifest.xml']['/manifest'][expected_xml]).toBeDefined();
             });
         });
 
@@ -217,16 +213,16 @@ describe('config-changes module', function() {
                 var munger = new configChanges.PlatformMunger('ios', temp, 'unused');
                 var munge = munger.generate_plugin_config_munge(varplugin, {});
                 var expected_xml = '<cfbundleid>com.example.friendstring</cfbundleid>';
-                expect(configChanges.get_munge_change(munge, 'config.xml', '/widget', expected_xml)).toBeDefined();
+                expect(munge['config.xml']['/widget'][expected_xml]).toBeDefined();
             });
             it('should special case framework elements for ios', function() {
                 var munger = new configChanges.PlatformMunger('ios', temp, 'unused');
                 var munge = munger.generate_plugin_config_munge(cbplugin, {});
-                expect(munge.files['framework']).toBeDefined();
-                expect(configChanges.get_munge_change(munge, 'framework', 'libsqlite3.dylib', 'false')).toBeDefined();
-                expect(configChanges.get_munge_change(munge, 'framework', 'social.framework', 'true')).toBeDefined();
-                expect(configChanges.get_munge_change(munge, 'framework', 'music.framework', 'false')).toBeDefined();
-                expect(munge.files['framework'].parents['Custom.framework']).not.toBeDefined();
+                expect(munge['framework']).toBeDefined();
+                expect(munge['framework']['libsqlite3.dylib']['false']).toBeDefined();
+                expect(munge['framework']['social.framework']['true']).toBeDefined();
+                expect(munge['framework']['music.framework']['false']).toBeDefined();
+                expect(munge['framework']['Custom.framework']).not.toBeDefined();
             });
         });
     });

http://git-wip-us.apache.org/repos/asf/cordova-plugman/blob/e85004a1/spec/util/xml-helpers.spec.js
----------------------------------------------------------------------
diff --git a/spec/util/xml-helpers.spec.js b/spec/util/xml-helpers.spec.js
index edcdedb..5def06e 100644
--- a/spec/util/xml-helpers.spec.js
+++ b/spec/util/xml-helpers.spec.js
@@ -139,32 +139,5 @@ describe('xml-helpers', function(){
                 selector= "/bookstore/book[price>35]/title";
             expect(xml_helpers.graftXML(doc, children, selector)).toBe(false);
         });
-
-        it('appends children after the specified sibling', function () {
-            var doc = new et.ElementTree(et.XML('<widget><A/><B/><C/></widget>')),
-                children = [et.XML('<B id="new"/>'), et.XML('<B id="new2"/>')],
-                selector= "/widget",
-                after= "B;A";
-            expect(xml_helpers.graftXML(doc, children, selector, after)).toBe(true);
-            expect(et.tostring(doc.getroot())).toContain('<B /><B id="new" /><B id="new2" />');
-        });
-
-        it('appends children after the 2nd priority sibling if the 1st one is missing', function () {
-            var doc = new et.ElementTree(et.XML('<widget><A/><C/></widget>')),
-                children = [et.XML('<B id="new"/>'), et.XML('<B id="new2"/>')],
-                selector= "/widget",
-                after= "B;A";
-            expect(xml_helpers.graftXML(doc, children, selector, after)).toBe(true);
-            expect(et.tostring(doc.getroot())).toContain('<A /><B id="new" /><B id="new2" />');
-        });
-
-        it('inserts children at the beginning if specified sibling is missing', function () {
-            var doc = new et.ElementTree(et.XML('<widget><B/><C/></widget>')),
-                children = [et.XML('<A id="new"/>'), et.XML('<A id="new2"/>')],
-                selector= "/widget",
-                after= "A";
-            expect(xml_helpers.graftXML(doc, children, selector, after)).toBe(true);
-            expect(et.tostring(doc.getroot())).toContain('<widget><A id="new" /><A id="new2" />');
-        });
     });
 });

http://git-wip-us.apache.org/repos/asf/cordova-plugman/blob/e85004a1/src/util/config-changes.js
----------------------------------------------------------------------
diff --git a/src/util/config-changes.js b/src/util/config-changes.js
index d09fcf1..989a582 100644
--- a/src/util/config-changes.js
+++ b/src/util/config-changes.js
@@ -39,7 +39,6 @@ var fs   = require('fs'),
     bplist = require('bplist-parser'),
     xcode = require('xcode'),
     et   = require('elementtree'),
-    _ = require('underscore'), 
     xml_helpers = require('./../util/xml-helpers'),
     platforms = require('./../platforms'),
     events = require('./../events'),
@@ -78,11 +77,6 @@ exports.process = function(plugins_dir, project_dir, platform) {
     munger.process();
     munger.save_all();
 };
-
-exports.get_munge_change = function(munge, keys) {
-    return deep_find.apply(null, arguments);
-}
-
 /******************************************************************************/
 
 
@@ -132,20 +126,19 @@ PlatformMunger.prototype.apply_file_munge = PlatformMunger_apply_file_munge;
 function PlatformMunger_apply_file_munge(file, munge, remove) {
     var self = this;
     var xml_child;
-    
+
     if ( file === 'framework' && self.platform === 'ios' ) {
         // ios pbxproj file
         var pbxproj = self.config_keeper.get(self.project_dir, self.platform, 'framework');
-        for (var src in munge.parents) {
-            for (xml_child in munge.parents[src]) {
-                var xml = munge.parents[src][xml_child].xml;
+        for (var src in munge) {
+            for (xml_child in munge[src]) {
                 // Only add the framework if it's not a cordova-ios core framework
                 if (keep_these_frameworks.indexOf(src) == -1) {
                     // xml_child in this case is whether the framework should use weak or not
                     if (remove) {
                         pbxproj.data.removeFramework(src);
                     } else {
-                        pbxproj.data.addFramework(src, {weak: (xml === 'true')});
+                        pbxproj.data.addFramework(src, {weak: (xml_child === 'true')});
                     }
                     pbxproj.is_changed = true;
                 }
@@ -153,13 +146,13 @@ function PlatformMunger_apply_file_munge(file, munge, remove) {
         }
     } else {
         // all other types of files
-        for (var selector in munge.parents) {
-            for (xml_child in munge.parents[selector]) {
+        for (var selector in munge) {
+            for (xml_child in munge[selector]) {
                 // this xml child is new, graft it (only if config file exists)
                 var config_file = self.config_keeper.get(self.project_dir, self.platform, file);
                 if (config_file.exists) {
-                    if (remove) config_file.prune_child(selector, munge.parents[selector][xml_child]);
-                    else config_file.graft_child(selector, munge.parents[selector][xml_child]);
+                    if (remove) config_file.prune_child(selector, xml_child);
+                    else config_file.graft_child(selector, xml_child);
                 }
             }
         }
@@ -180,7 +173,7 @@ function remove_plugin_changes(plugin_name, plugin_id, is_top_level) {
     var global_munge = platform_config.config_munge;
     var munge = decrement_munge(global_munge, config_munge);
 
-    for (var file in munge.files) {
+    for (var file in munge) {
         if (file == 'plugins-plist' && self.platform == 'ios') {
             // TODO: remove this check and <plugins-plist> sections in spec/plugins/../plugin.xml files.
             events.emit(
@@ -190,7 +183,7 @@ function remove_plugin_changes(plugin_name, plugin_id, is_top_level) {
             );
             continue;
         }
-        self.apply_file_munge(file, munge.files[file], /* remove = */ true);
+        self.apply_file_munge(file, munge[file], /* remove = */ true);
     }
 
     // Remove from installed_plugins
@@ -230,7 +223,7 @@ function add_plugin_changes(plugin_id, plugin_vars, is_top_level, should_increme
         munge = config_munge;
     }
 
-    for (var file in munge.files) {
+    for (var file in munge) {
         // TODO: remove this warning some time after 3.4 is out.
         if (file == 'plugins-plist' && self.platform == 'ios') {
             events.emit(
@@ -240,7 +233,7 @@ function add_plugin_changes(plugin_id, plugin_vars, is_top_level, should_increme
             );
             continue;
         }
-        self.apply_file_munge(file, munge.files[file]);
+        self.apply_file_munge(file, munge[file]);
     }
 
     // Move to installed_plugins if it is a top-level plugin
@@ -264,7 +257,7 @@ function reapply_global_munge () {
 
     var platform_config = exports.get_platform_json(self.plugins_dir, self.platform);
     var global_munge = platform_config.config_munge;
-    for (var file in global_munge.files) {
+    for (var file in global_munge) {
         // TODO: remove this warning some time after 3.4 is out.
         if (file == 'plugins-plist' && self.platform == 'ios') {
             events.emit(
@@ -275,7 +268,7 @@ function reapply_global_munge () {
             continue;
         }
         // TODO: This is mostly file IO and can run in parallel since each file is independent.
-        self.apply_file_munge(file, global_munge.files[file]);
+        self.apply_file_munge(file, global_munge[file]);
     }
 }
 
@@ -292,7 +285,7 @@ function generate_plugin_config_munge(plugin_dir, vars) {
         vars['PACKAGE_NAME'] = self.platform_handler.package_name(self.project_dir);
     }
 
-    var munge = { files: {} };
+    var munge = {};
     var plugin_config = self.config_keeper.get(plugin_dir, '', 'plugin.xml');
     var plugin_xml = plugin_config.data;
 
@@ -310,10 +303,18 @@ function generate_plugin_config_munge(plugin_dir, vars) {
         frameworks.forEach(function(f) {
             var custom = f.attrib['custom'];
             if(!custom) {
+                if (!munge['framework']) {
+                    munge['framework'] = {};
+                }
                 var file = f.attrib['src'];
-                var weak = ('true' == f.attrib['weak']).toString();
-
-                deep_add(munge, 'framework', file, { xml: weak, count: 1 });
+                var weak = ('true' == f.attrib['weak']);
+                if (!munge['framework'][file]) {
+                    munge['framework'][file] = {};
+                }
+                if (!munge['framework'][file][weak]) {
+                    munge['framework'][file][weak] = 0;
+                }
+                munge['framework'][file][weak] += 1;
             }
         });
     }
@@ -321,9 +322,14 @@ function generate_plugin_config_munge(plugin_dir, vars) {
     changes.forEach(function(change) {
         var target = change.attrib['target'];
         var parent = change.attrib['parent'];
-        var after = change.attrib['after'];
+        if (!munge[target]) {
+            munge[target] = {};
+        }
+        if (!munge[target][parent]) {
+            munge[target][parent] = {};
+        }
         var xmls = change.getchildren();
-		xmls.forEach(function(xml) {
+        xmls.forEach(function(xml) {
             // 1. stringify each xml
             var stringified = (new et.ElementTree(xml)).write({xml_declaration:false});
             // interp vars
@@ -334,12 +340,16 @@ function generate_plugin_config_munge(plugin_dir, vars) {
                 });
             }
             // 2. add into munge
-            deep_add(munge, target, parent, { xml: stringified, count: 1, after: after });
+            if (!munge[target][parent][stringified]) {
+                munge[target][parent][stringified] = 0;
+            }
+            munge[target][parent][stringified] += 1;
         });
     });
     return munge;
 }
 
+
 // Go over the prepare queue an apply the config munges for each plugin
 // that has been (un)installed.
 PlatformMunger.prototype.process = PlatformMunger_process;
@@ -416,7 +426,7 @@ function get_platform_json(plugins_dir, platform) {
 
     var filepath = path.join(plugins_dir, platform + '.json');
     if (fs.existsSync(filepath)) {
-        return fix_munge(JSON.parse(fs.readFileSync(filepath, 'utf-8')));
+        return JSON.parse(fs.readFileSync(filepath, 'utf-8'));
     } else {
         var config = {
             prepare_queue:{installed:[], uninstalled:[]},
@@ -435,28 +445,6 @@ function save_platform_json(config, plugins_dir, platform) {
     fs.writeFileSync(filepath, JSON.stringify(config, null, 4), 'utf-8');
 }
 
-
-// convert a munge from the old format ([file][parent][xml] = count) to the current one
-function fix_munge(platform_config) {
-    var munge = platform_config.config_munge;
-    if (!munge.files) {
-        var new_munge = { files: {} };
-        for (var file in munge) {
-            for (var selector in munge[file]) {
-                for (var xml_child in munge[file][selector]) {
-                    var val = parseInt(munge[file][selector][xml_child]);
-                    for (var i = 0; i < val; i++) {
-                        deep_add(new_munge, [file, selector, { xml: xml_child, count: val }]);
-                    }
-                }
-            }
-        }
-        platform_config.config_munge = new_munge;
-    }
-
-    return platform_config;
-}
-
 /**** END of ConfigKeeper ****/
 
 
@@ -540,14 +528,14 @@ function ConfigFile_graft_child(selector, xml_child) {
     var filepath = self.filepath;
     var result;
     if (self.type === 'xml') {
-        var xml_to_graft = [et.XML(xml_child.xml)];
-        result = xml_helpers.graftXML(self.data, xml_to_graft, selector, xml_child.after);
+        var xml_to_graft = [et.XML(xml_child)];
+        result = xml_helpers.graftXML(self.data, xml_to_graft, selector);
         if ( !result) {
             throw new Error('grafting xml at selector "' + selector + '" from "' + filepath + '" during config install went bad :(');
         }
     } else {
         // plist file
-        result = plist_helpers.graftPLIST(self.data, xml_child.xml, selector);
+        result = plist_helpers.graftPLIST(self.data, xml_child, selector);
         if ( !result ) {
             throw new Error('grafting to plist "' + filepath + '" during config install went bad :(');
         }
@@ -562,11 +550,11 @@ function ConfigFile_prune_child(selector, xml_child) {
     var filepath = self.filepath;
     var result;
     if (self.type === 'xml') {
-        var xml_to_graft = [et.XML(xml_child.xml)];
+        var xml_to_graft = [et.XML(xml_child)];
         result = xml_helpers.pruneXML(self.data, xml_to_graft, selector);
     } else {
         // plist file
-        result = plist_helpers.prunePLIST(self.data, xml_child.xml, selector);
+        result = plist_helpers.prunePLIST(self.data, xml_child, selector);
     }
     if ( !result) {
         var err_msg = 'Pruning at selector "' + selector + '" from "' + filepath + '" went bad.';
@@ -662,94 +650,21 @@ function resolveConfigFilePath(project_dir, platform, file) {
 * Munge object manipulations functions
 ******************************************************************************/
 
-// add the count of [key1][key2]...[keyN] to obj
-// return true if it didn't exist before
-function deep_add(obj, keys /* or key1, key2 .... */ ) {
+// Increment obj[key1][key2]...[keyN] by val. If it
+// didn't exist, set it to val.
+function deep_add(obj, val, keys /* or key1, key2 .... */ ) {
     if ( !Array.isArray(keys) ) {
-        keys = Array.prototype.slice.call(arguments, 1);
-    }
-
-    return process_munge(obj, true/*createParents*/, function (parentArray, k) {
-        var found = _.find(parentArray, function(element) {
-            return element.xml == k.xml;
-        });
-        if (found) {
-            found.after = found.after || k.after;
-            found.count += k.count;
-        } else {
-            parentArray.push(k);
-        }
-        return !found;
-    }, keys);
-}
-
-// decrement the count of [key1][key2]...[keyN] from obj and remove if it reaches 0
-// return true if it was removed or not found
-function deep_remove(obj, keys /* or key1, key2 .... */ ) {
-    if ( !Array.isArray(keys) ) {
-        keys = Array.prototype.slice.call(arguments, 1);
-    }
-
-    var result = process_munge(obj, false/*createParents*/, function (parentArray, k) {
-        var index = -1;
-        var found = _.find(parentArray, function (element) {
-            index++;
-            return element.xml == k.xml;
-        });
-        if (found) {
-            found.count -= k.count;
-            if (found.count > 0) {
-                return false;
-            }
-            else {
-                parentArray.splice(index, 1);
-            }
-        }
-        return undefined;
-    }, keys);
-
-    return typeof result === "undefined" ? true : result;
-}
-
-// search for [key1][key2]...[keyN]
-// return the object or undefined if not found
-function deep_find(obj, keys /* or key1, key2 .... */ ) {
-    if ( !Array.isArray(keys) ) {
-        keys = Array.prototype.slice.call(arguments, 1);
-    }
-
-    return process_munge(obj, false/*createParents?*/, function (parentArray, k) {
-        return _.find(parentArray, function (element) {
-            return element.xml == (k.xml || k);
-        });
-    }, keys);
-}
-
-// Execute func passing it the parent array and the xmlChild key.
-// When createParents is true, add the file and parent items  they are missing
-// When createParents is false, stop and return undefined if the file and/or parent items are missing
-
-function process_munge(obj, createParents, func, keys /* or key1, key2 .... */ ) {
-    if ( !Array.isArray(keys) ) {
-        keys = Array.prototype.slice.call(arguments, 1);
+        keys = Array.prototype.slice.call(arguments, 2);
     }
     var k = keys[0];
+
     if (keys.length == 1) {
-        return func(obj, k);
-    } else if (keys.length == 2) {
-        if (!obj.parents[k] && !createParents) {
-            return undefined;
-        }
-        obj.parents[k] = obj.parents[k] || [];
-        return process_munge(obj.parents[k], createParents, func, keys.slice(1));
-    } else if (keys.length == 3){
-        if (!obj.files[k] && !createParents) {
-            return undefined;
-        }
-        obj.files[k] = obj.files[k] || { parents: {} };
-        return process_munge(obj.files[k], createParents, func, keys.slice(1));
+        obj[k] = obj[k] || 0;
+        obj[k] += val;
+        return obj[k];
     } else {
-        throw new Error("Invalid key format. Must contain at most 3 elements (file, parent, xmlChild).");
+        obj[k] = obj[k] || {};
+        return deep_add(obj[k], val, keys.slice(1));
     }
 }
 
@@ -758,17 +673,17 @@ function process_munge(obj, createParents, func, keys /* or key1, key2 .... */ )
 // Returns a munge object containing values that exist in munge
 // but not in base.
 function increment_munge(base, munge) {
-    var diff = { files: {} };
+    var diff = {};
 
-    for (var file in munge.files) {
-        for (var selector in munge.files[file].parents) {
-            for (var xml_child in munge.files[file].parents[selector]) {
-                var val = munge.files[file].parents[selector][xml_child];
+    for (var file in munge) {
+        for (var selector in munge[file]) {
+            for (var xml_child in munge[file][selector]) {
+                var val = munge[file][selector][xml_child];
                 // if node not in base, add it to diff and base
                 // else increment it's value in base without adding to diff
-                var newlyAdded = deep_add(base, [file, selector, val]);
-                if (newlyAdded) {
-                    deep_add(diff, file, selector, val);
+                var new_val = deep_add(base, val, [file, selector, xml_child]);
+                if ( val == new_val ) {
+                    deep_add(diff, val, file, selector, xml_child);
                 }
             }
         }
@@ -778,20 +693,21 @@ function increment_munge(base, munge) {
 
 // Update the base munge object as
 // base[file][selector][child] -= base[file][selector][child]
-// nodes that reached zero value are removed from base and added to the returned munge
+// nodes that reached zero value are removed from base and the returned munge
 // object.
 function decrement_munge(base, munge) {
-    var zeroed = { files: {} };
+    var zeroed = {};
 
-    for (var file in munge.files) {
-        for (var selector in munge.files[file].parents) {
-            for (var xml_child in munge.files[file].parents[selector]) {
-                var val = munge.files[file].parents[selector][xml_child];
+    for (var file in munge) {
+        for (var selector in munge[file]) {
+            for (var xml_child in munge[file][selector]) {
+                var val = munge[file][selector][xml_child];
                 // if node not in base, add it to diff and base
                 // else increment it's value in base without adding to diff
-                var removed = deep_remove(base, [file, selector, val]);
-                if (removed) {
-                    deep_add(zeroed, file, selector, val);
+                var new_val = deep_add(base, -val, [file, selector, xml_child]);
+                if ( new_val <= 0) {
+                    deep_add(zeroed, val, file, selector, xml_child);
+                    delete base[file][selector][xml_child];
                 }
             }
         }

http://git-wip-us.apache.org/repos/asf/cordova-plugman/blob/e85004a1/src/util/xml-helpers.js
----------------------------------------------------------------------
diff --git a/src/util/xml-helpers.js b/src/util/xml-helpers.js
index 265025e..cfb914c 100644
--- a/src/util/xml-helpers.js
+++ b/src/util/xml-helpers.js
@@ -23,7 +23,6 @@
 
 var fs = require('fs')
   , path = require('path')
-  , _ = require('underscore')
   , et = require('elementtree');
 
 module.exports = {
@@ -73,7 +72,7 @@ module.exports = {
     },
 
     // adds node to doc at selector, creating parent if it doesn't exist
-    graftXML: function(doc, nodes, selector, after) {
+    graftXML: function(doc, nodes, selector) {
         var parent = resolveParent(doc, selector);
         if (!parent) {
             //Try to create the parent recursively if necessary
@@ -92,11 +91,7 @@ module.exports = {
         nodes.forEach(function (node) {
             // check if child is unique first
             if (uniqueChild(node, parent)) {
-                var children = parent.getchildren();
-                var insertIdx = after ? findInsertIdx(children, after) : children.length;
-
-                //TODO: replace with parent.insert after the bug in ElementTree is fixed
-                parent.getchildren().splice(insertIdx, 0, node);
+                parent.append(node);
             }
         });
 
@@ -179,18 +174,3 @@ function resolveParent(doc, selector) {
     }
     return parent;
 }
-
-// Find the index at which to insert an entry. After is a ;-separated priority list 
-// of tags after which the insertion should be made. E.g. If we need to 
-// insert an element C, and the rule is that the order of children has to be 
-// As, Bs, Cs. After will be equal to "C;B;A".
-
-function findInsertIdx(children, after) {
-    var childrenTags = children.map(function(child) { return child.tag; });
-    var afters = after.split(";");
-    var afterIndexes = afters.map(function(current) { return childrenTags.lastIndexOf(current); });
-    var foundIndex = _.find(afterIndexes, function(index) { return index != -1; });
-
-    //add to the beginning if no matching nodes are found
-    return typeof foundIndex === 'undefined' ? 0 : foundIndex+1;
-}