You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cordova.apache.org by st...@apache.org on 2017/02/04 01:04:49 UTC

[02/12] cordova-lib git commit: CB-11960: Added more save/restore tests.

CB-11960: Added more save/restore 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/4cd1be81
Tree: http://git-wip-us.apache.org/repos/asf/cordova-lib/tree/4cd1be81
Diff: http://git-wip-us.apache.org/repos/asf/cordova-lib/diff/4cd1be81

Branch: refs/heads/master
Commit: 4cd1be81598406082b075c74081eaf85c9363c66
Parents: 7df35cb
Author: Steve Gill <st...@gmail.com>
Authored: Fri Nov 4 13:55:52 2016 -0700
Committer: Audrey So <au...@apache.org>
Committed: Thu Jan 26 17:36:51 2017 -0800

----------------------------------------------------------------------
 .../fixtures/basePkgJson/merges/.svn            |   0
 .../fixtures/basePkgJson/www/img/logo.png       | Bin 21814 -> 0 bytes
 .../fixtures/basePkgJson2/config.xml            |   2 +
 .../fixtures/basePkgJson2/merges/.svn           |   0
 .../fixtures/basePkgJson2/package.json          |  14 +-
 .../fixtures/basePkgJson2/www/img/logo.png      | Bin 21814 -> 0 bytes
 cordova-lib/spec-cordova/package.json.spec.js   | 389 -------------------
 .../spec-cordova/pkgJson-restore.spec.js        | 227 +++++++++++
 cordova-lib/spec-cordova/pkgJson.spec.js        |  38 +-
 cordova-lib/spec-cordova/platform.spec.js       |  39 +-
 cordova-lib/src/cordova/platform.js             |  72 ++--
 cordova-lib/src/cordova/restore-util.js         | 100 +++--
 12 files changed, 372 insertions(+), 509 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/4cd1be81/cordova-lib/spec-cordova/fixtures/basePkgJson/merges/.svn
----------------------------------------------------------------------
diff --git a/cordova-lib/spec-cordova/fixtures/basePkgJson/merges/.svn b/cordova-lib/spec-cordova/fixtures/basePkgJson/merges/.svn
deleted file mode 100644
index e69de29..0000000

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/4cd1be81/cordova-lib/spec-cordova/fixtures/basePkgJson/www/img/logo.png
----------------------------------------------------------------------
diff --git a/cordova-lib/spec-cordova/fixtures/basePkgJson/www/img/logo.png b/cordova-lib/spec-cordova/fixtures/basePkgJson/www/img/logo.png
deleted file mode 100644
index 9519e7d..0000000
Binary files a/cordova-lib/spec-cordova/fixtures/basePkgJson/www/img/logo.png and /dev/null differ

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/4cd1be81/cordova-lib/spec-cordova/fixtures/basePkgJson2/config.xml
----------------------------------------------------------------------
diff --git a/cordova-lib/spec-cordova/fixtures/basePkgJson2/config.xml b/cordova-lib/spec-cordova/fixtures/basePkgJson2/config.xml
index 9e7b9e0..9c807f1 100644
--- a/cordova-lib/spec-cordova/fixtures/basePkgJson2/config.xml
+++ b/cordova-lib/spec-cordova/fixtures/basePkgJson2/config.xml
@@ -11,4 +11,6 @@
     <access origin="*" />
     <preference name="fullscreen" value="true" />
     <preference name="webviewbounce" value="true" />
+    <engine name="ios"/>
+    <plugin name="cordova-plugin-camera"/>
 </widget>

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/4cd1be81/cordova-lib/spec-cordova/fixtures/basePkgJson2/merges/.svn
----------------------------------------------------------------------
diff --git a/cordova-lib/spec-cordova/fixtures/basePkgJson2/merges/.svn b/cordova-lib/spec-cordova/fixtures/basePkgJson2/merges/.svn
deleted file mode 100644
index e69de29..0000000

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/4cd1be81/cordova-lib/spec-cordova/fixtures/basePkgJson2/package.json
----------------------------------------------------------------------
diff --git a/cordova-lib/spec-cordova/fixtures/basePkgJson2/package.json b/cordova-lib/spec-cordova/fixtures/basePkgJson2/package.json
index 0155e61..746681f 100644
--- a/cordova-lib/spec-cordova/fixtures/basePkgJson2/package.json
+++ b/cordova-lib/spec-cordova/fixtures/basePkgJson2/package.json
@@ -10,17 +10,15 @@
     "scripts": {
         "test": "echo \"Error: no test specified\" && exit 1"
     },
-    "author": "audrey",
+    "author": "",
     "license": "ISC",
     "cordova": {
         "platforms": [
-            "android"
+            "ios"
         ],
-        "plugins": {
-            "cordova-plugin-camera": {
-                "CAMERA_USAGE_DESCRIPTION": " ",
-                "PHOTOLIBRARY_USAGE_DESCRIPTION": " "
-            }
-        }
+        "plugins": [
+            "cordova-plugin-camera",
+            "cordova-plugin-splashscreen"
+        ]
     }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/4cd1be81/cordova-lib/spec-cordova/fixtures/basePkgJson2/www/img/logo.png
----------------------------------------------------------------------
diff --git a/cordova-lib/spec-cordova/fixtures/basePkgJson2/www/img/logo.png b/cordova-lib/spec-cordova/fixtures/basePkgJson2/www/img/logo.png
deleted file mode 100644
index 9519e7d..0000000
Binary files a/cordova-lib/spec-cordova/fixtures/basePkgJson2/www/img/logo.png and /dev/null differ

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/4cd1be81/cordova-lib/spec-cordova/package.json.spec.js
----------------------------------------------------------------------
diff --git a/cordova-lib/spec-cordova/package.json.spec.js b/cordova-lib/spec-cordova/package.json.spec.js
deleted file mode 100644
index 1755834..0000000
--- a/cordova-lib/spec-cordova/package.json.spec.js
+++ /dev/null
@@ -1,389 +0,0 @@
-/**
-    Licensed to the Apache Software Foundation (ASF) under one
-    or more contributor license agreements.  See the NOTICE file
-    distributed with this work for additional information
-    regarding copyright ownership.  The ASF licenses this file
-    to you under the Apache License, Version 2.0 (the
-    "License"); you may not use this file except in compliance
-    with the License.  You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-    Unless required by applicable law or agreed to in writing,
-    software distributed under the License is distributed on an
-    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-    KIND, either express or implied.  See the License for the
-    specific language governing permissions and limitations
-    under the License.
-*/
-var helpers = require('./helpers'),
-    path = require('path'),
-    fs = require('fs'),
-    shell = require('shelljs'),
-    superspawn = require('cordova-common').superspawn,
-    Q = require('q'),
-    events = require('cordova-common').events,
-    cordova = require('../src/cordova/cordova'),
-    rewire = require('rewire'),
-    prepare = require('../src/cordova/prepare'),
-    platforms = require('../src/platforms/platforms'),
-    platform = rewire('../src/cordova/platform.js');
-
-var projectRoot = 'C:\\Projects\\cordova-projects\\move-tracker';
-var pluginsDir = path.join(__dirname, 'fixtures', 'plugins');
-
-function addPlugin(target, id, options) {
-    // Checks that there are no plugins yet.
-    return cordova.raw.plugin('list').then(function() {
-        expect(results).toMatch(/No plugins added/gi);
-    }).then(function() {
-        // Adds a fake plugin from fixtures.
-        return cordova.raw.plugin('add', target, options);
-    }).then(function() {
-        expect(path.join(project, 'plugins', id, 'plugin.xml')).toExist();
-    }).then(function() {
-        return cordova.raw.plugin('ls');
-    }).then(function() {
-        expect(results).toContain(id);
-    });
-}
-// Runs: remove, list.
-function removePlugin(id, options) {
-    return cordova.raw.plugin('rm', id)
-    .then(function() {
-        // The whole dir should be gone.
-        expect(path.join(project, 'plugins', id)).not.toExist();
-    }).then(function() {
-        return cordova.raw.plugin('ls');
-    }).then(function() {
-        expect(results).toMatch(/No plugins added/gi);
-    });
-}
-// Checks if plugin list is empty.
-function emptyPluginList() {
-    return cordova.raw.plugin('list').then(function() {
-        var installed = results.match(/Installed plugins:\n  (.*)/);
-        expect(installed).toBeDefined();
-        expect(installed[1].indexOf('fake-plugin')).toBe(-1);
-    });
-}
-// Checks if plugin list exists.
-function fullPluginList() {
-    return cordova.raw.plugin('list').then(function() {
-        var installed = results.match(/Installed plugins:\n  (.*)/);
-        expect(installed).toBeDefined();
-        expect(installed[1].indexOf('fake-plugin')).toBeGreaterThan(-1);
-    });
-}
-
-// This group of tests checks if plugins are added and removed as expected.
-describe('plugin end-to-end', function() {
-    var pluginId = 'cordova-plugin-device';
-    var tmpDir = helpers.tmpDir('platform_test_pkgjson');
-    var project = path.join(tmpDir, 'project');
-    var results;
-
-    events.on('results', function(res) { results = res; });
-
-    beforeEach(function() {
-        shell.rm('-rf', project);
-
-        // Copy then move because we need to copy everything, but that means it will copy the whole directory.
-        // Using /* doesn't work because of hidden files.
-        shell.cp('-R', path.join(__dirname, 'fixtures', 'basePkgJson'), tmpDir);
-        shell.mv(path.join(tmpDir, 'basePkgJson'), project);
-        // Copy some platform to avoid working on a project with no platforms.
-        shell.cp('-R', path.join(__dirname, 'fixtures', 'platforms', helpers.testPlatform), path.join(project, 'platforms'));
-        process.chdir(project);
-
-        delete process.env.PWD;
-
-        spyOn(prepare, 'preparePlatforms').andCallThrough();
-    });
-
-    afterEach(function() {
-        process.chdir(path.join(__dirname, '..'));  // Needed to rm the dir on Windows.
-        shell.rm('-rf', tmpDir);
-    });
-
-    it('Test#001 : should successfully add and remove a plugin with no options', function(done) {
-        var pkgJsonPath = path.join(process.cwd(),'package.json');
-        var pkgJson;
-        var retPromise;
-
-        expect(pkgJsonPath).toExist();
-
-        // Add the plugin with --save
-        return cordova.raw.plugin('add', pluginId, {'save':true})
-        .then(function() {
-            // Check that the plugin add was successful.
-            delete require.cache[require.resolve(pkgJsonPath)];
-            pkgJson = require(pkgJsonPath);
-            expect(pkgJson).not.toBeUndefined();
-            expect(pkgJson.cordova.plugins).not.toBeUndefined();
-            expect(pkgJson.cordova.plugins[pluginId]).toBeDefined();
-        }).then(function() {
-            // And now remove it with --save.
-            return cordova.raw.plugin('rm', pluginId, {'save':true})
-        }).then(function() {
-            // Delete any previous caches of require(package.json)
-            delete require.cache[require.resolve(pkgJsonPath)];
-            pkgJson = require(pkgJsonPath);
-            // Checking that the plugin removed is in not in the platforms
-            expect(pkgJson.cordova.plugins[pluginId]).toBeUndefined();
-        }).fail(function(err) {
-            expect(err).toBeUndefined();
-        }).fin(done);
-    });
-
-    it('Test#002 : should successfully NOT add a plugin if save is not there', function(done) {
-        var pkgJsonPath = path.join(process.cwd(),'package.json');
-        var pkgJson;
-
-        expect(pkgJsonPath).toExist();
-
-        // Add the plugin with --save.
-        return cordova.raw.plugin('add', 'cordova-plugin-camera', {'save':true})
-        .then(function() {
-            // Add a second plugin without save
-            return cordova.raw.plugin('add', pluginId);
-        }).then(function() {
-            // Check the plugin add was successful for the first plugin that had --save.
-            delete require.cache[require.resolve(pkgJsonPath)];
-            pkgJson = require(pkgJsonPath);
-            expect(pkgJson).not.toBeUndefined();
-            expect(pkgJson.cordova.plugins['cordova-plugin-camera']).toBeDefined();
-            // Expect that the second plugin is not added.
-            expect(pkgJson.cordova.plugins[pluginId]).toBeUndefined();
-        }).fail(function(err) {
-            expect(err).toBeUndefined();
-        }).fin(done);
-    });
-
-    it('Test#003 : should NOT remove plugin if there is no --save', function(done) {
-        var pkgJsonPath = path.join(process.cwd(),'package.json');
-        var pkgJson;
-        var retPromise;
-
-        expect(pkgJsonPath).toExist();
-
-        // Add the plugin with --save.
-        return cordova.raw.plugin('add', pluginId, {'save':true})
-        .then(function() {
-            // Check the platform add was successful.
-            delete require.cache[require.resolve(pkgJsonPath)];
-            pkgJson = require(pkgJsonPath);
-            expect(pkgJson).not.toBeUndefined();
-            expect(pkgJson.cordova.plugins).toBeDefined();
-            expect(pkgJson.cordova.plugins[pluginId]).toBeDefined();
-        }).then(function() {
-            // And now remove it, but without --save.
-            return cordova.raw.plugin('rm', 'cordova-plugin-device')
-        }).then(function() {
-            // Delete any previous caches of require(package.json)
-            delete require.cache[require.resolve(pkgJsonPath)];
-            pkgJson = require(pkgJsonPath);
-            // The plugin should still be in package.json.
-            expect(pkgJson.cordova.plugins[pluginId]).toBeDefined();
-        }).fail(function(err) {
-            expect(err).toBeUndefined();
-        }).fin(done);
-    });
-
-    it('Test#004 : should successfully add and remove a plugin with variables and save', function(done) {
-        var pkgJsonPath = path.join(process.cwd(),'package.json');
-        var pkgJson;
-        var retPromise;
-
-        expect(pkgJsonPath).toExist();
-
-        // Add the plugin with --save.
-        return cordova.raw.plugin('add', pluginId, {'save':true, 'cli_variables': {'someKey':'someValue'}})
-        .then(function() {
-            // Delete any previous caches of require(package.json)
-            delete require.cache[require.resolve(pkgJsonPath)];
-            pkgJson = require(pkgJsonPath);
-            // Check the plugin add was successful and that variables have been added too.
-            expect(pkgJson).not.toBeUndefined();
-            expect(pkgJson.cordova.plugins).toBeDefined();
-            expect(pkgJson.cordova.plugins[pluginId]).toBeDefined();
-            expect(pkgJson.cordova.plugins[pluginId]['someKey']).toEqual('someValue');
-        }).then(function() {
-            // And now remove it with --save.
-            return cordova.raw.plugin('rm', pluginId, {'save':true})
-        }).then(function() {
-            // Delete any previous caches of require(package.json)
-            delete require.cache[require.resolve(pkgJsonPath)];
-            pkgJson = require(pkgJsonPath);
-            // Checking that the plugin and variables were removed successfully.
-            expect(pkgJson.cordova.plugins[pluginId]).toBeUndefined();
-        }).fail(function(err) {
-            expect(err).toBeUndefined();
-        }).fin(done);
-    });
-});
-
-// This group of tests checks if platforms are added and removed as expected.
-describe('platform end-to-end with --save', function () {
-    var tmpDir = helpers.tmpDir('platform_test_pkgjson');
-    var project = path.join(tmpDir, 'project');
-    var results;
-
-    beforeEach(function() {
-        shell.rm('-rf', tmpDir);
-
-        // cp then mv because we need to copy everything, but that means it'll copy the whole directory.
-        // Using /* doesn't work because of hidden files.
-        shell.cp('-R', path.join(__dirname, 'fixtures', 'basePkgJson'), tmpDir);
-        shell.mv(path.join(tmpDir, 'basePkgJson'), project);
-        process.chdir(project);
-
-        // The config.json in the fixture project points at fake "local" paths.
-        // Since it's not a URL, the lazy-loader will just return the junk path.
-        spyOn(superspawn, 'spawn').andCallFake(function(cmd, args) {
-            if (cmd.match(/create\b/)) {
-                // This is a call to the bin/create script, so do the copy ourselves.
-                shell.cp('-R', path.join(__dirname, 'fixtures', 'platforms', 'android'), path.join(project, 'platforms'));
-            } else if(cmd.match(/version\b/)) {
-                return Q('3.3.0');
-            } else if(cmd.match(/update\b/)) {
-                fs.writeFileSync(path.join(project, 'platforms', helpers.testPlatform, 'updated'), 'I was updated!', 'utf-8');
-            }
-            return Q();
-        });
-        events.on('results', function(res) { results = res; });
-    });
-
-    afterEach(function() {
-        delete require.cache[require.resolve(path.join(process.cwd(),'package.json'))];
-        process.chdir(path.join(__dirname, '..'));  // Needed to rm the dir on Windows.
-        shell.rm('-rf', tmpDir);
-
-    });
-
-    // Factoring out some repeated checks.
-    function emptyPlatformList() {
-        return cordova.raw.platform('list').then(function() {
-            var installed = results.match(/Installed platforms:\n  (.*)/);
-            expect(installed).toBeDefined();
-            expect(installed[1].indexOf(helpers.testPlatform)).toBe(-1);
-        });
-    }
-    function fullPlatformList() {
-        return cordova.raw.platform('list').then(function() {
-            var installed = results.match(/Installed platforms:\n  (.*)/);
-            expect(installed).toBeDefined();
-            expect(installed[1].indexOf(helpers.testPlatform)).toBeGreaterThan(-1);
-        });
-    }
-
-    it('Test#006 : platform is added and removed correctly with --save', function(done) {
-        var pkgJsonPath = path.join(process.cwd(),'package.json');
-        expect(pkgJsonPath).toExist();
-        var pkgJson = require(pkgJsonPath);
-
-        // Check there are no platforms yet.
-        emptyPlatformList().then(function() {
-            // Add the testing platform with --save.
-            return cordova.raw.platform('add', [helpers.testPlatform], {'save':true});
-        }).then(function() {
-            // Check the platform add was successful.
-            expect(pkgJson.cordova.platforms).not.toBeUndefined();
-            expect(pkgJson.cordova.platforms.indexOf(helpers.testPlatform)).toBeGreaterThan(-1);
-
-        }).then(fullPlatformList) // Platform should still be in platform ls.
-        .then(function() {
-            // And now remove it with --save.
-            return cordova.raw.platform('rm', [helpers.testPlatform], {'save':true});
-        }).then(function() {
-            // Delete any previous caches of require(package.json)
-            delete require.cache[require.resolve(pkgJsonPath)];
-            pkgJson = require(pkgJsonPath);
-            // Checking that the platform removed is in not in the platforms key
-            expect(pkgJson.cordova.platforms.indexOf(helpers.testPlatform)).toEqual(-1);
-        }).then(emptyPlatformList) // platform ls should be empty too.
-        .fail(function(err) {
-            expect(err).toBeUndefined();
-        }).fin(done);
-    });
-
-    it('Test#007 : should not remove platforms from package.json when removing without --save', function(done) {
-        var pkgJsonPath = path.join(process.cwd(),'package.json');
-        expect(pkgJsonPath).toExist();
-        var pkgJson = require(pkgJsonPath);
-        emptyPlatformList().then(function() {
-            // Add the testing platform with --save.
-            return cordova.raw.platform('add', [helpers.testPlatform], {'save':true});
-        }).then(function() {
-            // Check the platform add was successful.
-            expect(pkgJson.cordova.platforms).not.toBeUndefined();
-            expect(pkgJson.cordova.platforms.indexOf(helpers.testPlatform)).toBeGreaterThan(-1);
-        }).then(fullPlatformList) // Platform should still be in platform ls.
-        .then(function() {
-            // And now remove it without --save.
-            return cordova.raw.platform('rm', [helpers.testPlatform]);
-        }).then(function() {
-            // Delete any previous caches of require(package.json)
-            delete require.cache[require.resolve(pkgJsonPath)];
-            pkgJson = require(pkgJsonPath);
-
-            // Check that the platform removed without --save is still in platforms key.
-            expect(pkgJson.cordova.platforms.indexOf(helpers.testPlatform)).toBeGreaterThan(-1);
-        }).then(emptyPlatformList)
-        .fail(function(err) {
-            expect(err).toBeUndefined();
-        }).fin(done);
-    });
-
-    it('Test#008 : should not add platform to package.json when adding without --save', function(done) {
-        var pkgJsonPath = path.join(process.cwd(),'package.json');
-        var pkgJson;
-        var platformToAdd = helpers.testPlatform;
-        expect(pkgJsonPath).toExist();
-
-        // Add platform without --save.
-        cordova.raw.platform('add',platformToAdd)
-        .then(function() {
-            // Check the platform add was successful, reload, skipping cache
-            delete require.cache[require.resolve(pkgJsonPath)];
-            pkgJson = require(pkgJsonPath);
-            // Beware empty/missing cordova object
-            var pckJsonCordova = pkgJson.cordova || {platforms:[]};
-            // Check that the platform has NOT been added.
-            expect(pckJsonCordova.platforms.indexOf(platformToAdd)).toEqual(-1);
-        })
-        .fail(function(err) {
-            expect(err).toBeUndefined();
-        })
-        .fin(done);
-    });
-
-    it('Test#009 : should only add the platform to package.json with --save', function(done) {
-        var pkgJsonPath = path.join(process.cwd(),'package.json');
-        var pkgJson;
-        var platformToAdd = helpers.testPlatform;
-        var platformNotToAdd = 'ios';
-        expect(pkgJsonPath).toExist();
-
-        // Add a platform without --save.
-        cordova.raw.platform('add',platformNotToAdd)
-        .then(function() {
-            // And now add another platform with --save.
-            return cordova.raw.platform('add', platformToAdd, {'save':true});
-        }).then(function() {
-            // Check the platform add was successful, reload, skipping cache
-            delete require.cache[require.resolve(pkgJsonPath)];
-            pkgJson = require(pkgJsonPath);
-            // Beware empty/missing cordova object
-            var pckJsonCordova = pkgJson.cordova || {platforms:[]};
-            // Check that only the platform added with --save was added to package.json.
-            expect(pckJsonCordova.platforms.indexOf(platformToAdd)).toBeGreaterThan(-1);
-            expect(pckJsonCordova.platforms.indexOf(platformNotToAdd)).toEqual(-1);
-        })
-        .fail(function(err) {
-            expect(err).toBeUndefined();
-        })
-        .fin(done);
-    });
-});
-

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/4cd1be81/cordova-lib/spec-cordova/pkgJson-restore.spec.js
----------------------------------------------------------------------
diff --git a/cordova-lib/spec-cordova/pkgJson-restore.spec.js b/cordova-lib/spec-cordova/pkgJson-restore.spec.js
index e4018e3..61a8945 100644
--- a/cordova-lib/spec-cordova/pkgJson-restore.spec.js
+++ b/cordova-lib/spec-cordova/pkgJson-restore.spec.js
@@ -613,6 +613,233 @@ describe('update config.xml to include platforms in pkg.json', function () {
     },30000);
 });
 
+// PLUGINS START HERE
 
+// Use basePkgJson2 as pkg.json contains 2 plugins and config.xml contains 1 plugin
+describe('update config.xml to include plugins found in pkg.json', function () {
+    var tmpDir = helpers.tmpDir('platform_test_pkgjson');
+    var project = path.join(tmpDir, 'project');
+    var results;
+
+    beforeEach(function() {
+        shell.rm('-rf', tmpDir);
+        // Copy then move because we need to copy everything, but that means it will copy the whole directory.
+        // Using /* doesn't work because of hidden files.
+        shell.cp('-R', path.join(__dirname, 'fixtures', 'basePkgJson2'), tmpDir);
+        shell.mv(path.join(tmpDir, 'basePkgJson2'), project);
+        process.chdir(project);
+        events.on('results', function(res) { results = res; });
+    });
+
+    afterEach(function() {
+        var cwd = process.cwd();
+        delete require.cache[require.resolve(path.join(process.cwd(),'package.json'))];
+        process.chdir(path.join(__dirname, '..'));  // Needed to rm the dir on Windows.
+        shell.rm('-rf', tmpDir);
+    });
+
+    // Factoring out some repeated checks.
+    function emptyPlatformList() {
+        return cordova.raw.platform('list').then(function() {
+            var installed = results.match(/Installed platforms:\n  (.*)/);
+            expect(installed).toBeDefined();
+            expect(installed[1].indexOf(helpers.testPlatform)).toBe(-1);
+        });
+    }
+
+    function fullPlatformList() {
+        return cordova.raw.platform('list').then(function() {
+            var installed = results.match(/Installed platforms:\n  (.*)/);
+            expect(installed).toBeDefined();
+            expect(installed[1].indexOf(helpers.testPlatform)).toBeGreaterThan(-1);
+        });
+    }
+
+    /** Test#008 will check the platform list in package.json and config.xml. 
+    *   When packge.json has 'splashscreen and camera' and config.xml only contains 'splashscreen', run cordova prepare
+    *   and config.xml is updated to include 'camera'.
+    */
+    it('Test#008 :  if pkgJson has 2 plugins and config.xml has only one of those plugins, update config to include both', function(done) {
+        var cwd = process.cwd();
+        var configXmlPath = path.join(cwd, 'config.xml');
+        var pkgJsonPath = path.join(cwd,'package.json');
+        delete require.cache[require.resolve(pkgJsonPath)];
+        var cfg1 = new ConfigParser(configXmlPath);
+        var plugins = cfg1.getPluginIdList();
+        var pkgJson = require(pkgJsonPath);
+        var pluginNames = plugins.map(function(elem) {
+            return elem;
+        });
+        var configPlugArray = pluginNames.slice();
+
+        // Expect that pkg.json exists with 2 plugins
+        expect(pkgJson.cordova.plugins).toBeDefined();
+        expect(pkgJson.cordova.plugins.length === 1);
+        expect(pkgJson.cordova.plugins.indexOf('cordova-plugin-camera')).toEqual(0);
+        expect(pkgJson.cordova.plugins.indexOf('cordova-plugin-splashscreen')).toEqual(1);
+        // Expect that config.xml exists with 1 plugin
+        expect(configPlugArray).toBeDefined();
+        expect(configPlugArray.length === 0);
+        expect(configPlugArray.indexOf('cordova-plugin-splashscreen')).toEqual(-1);
+        expect(configPlugArray.indexOf('cordova-plugin-camera')).toEqual(0);
+
+        emptyPlatformList().then(function() {
+            // Run cordova prepare
+            return cordova.raw.prepare();
+        }).then(function() {
+            // Delete any previous caches of require(package.json)
+            delete require.cache[require.resolve(pkgJsonPath)];
+            pkgJson = require(pkgJsonPath);
+            var cfg2 = new ConfigParser(configXmlPath);
+            plugins = cfg2.getPluginIdList();
+            pluginNames = plugins.map(function(elem) {
+                return elem;
+            });
+            configPlugArray = pluginNames.slice();
+            // Expect that pkg.json exists with 2 plugins
+            expect(pkgJson.cordova.plugins).toBeDefined();
+            expect(pkgJson.cordova.plugins.length === 1);
+            // Expect that config.xml exists with 2 plugins
+            expect(configPlugArray).toBeDefined();
+            expect(configPlugArray.length === 1);
+            // Expect config to contain camera and splashscreen
+            expect(configPlugArray.indexOf('cordova-plugin-camera')).toEqual(0);
+            expect(configPlugArray.indexOf('cordova-plugin-splashscreen')).toEqual(1);
+            // Expect pkg.json to contain camera and splashscreen
+            expect(pkgJson.cordova.plugins.indexOf('cordova-plugin-camera')).toEqual(0);
+            expect(pkgJson.cordova.plugins.indexOf('cordova-plugin-splashscreen')).toEqual(1);
+        }).fail(function(err) {
+            expect(err).toBeUndefined();
+        }).fin(done);
+    // Cordova prepare needs extra wait time to complete.
+    },30000);
+});
+
+// Use basePkgJson7 as config.xml contains 2 plugins and pkg.json contains 1 plugin
+describe('update pkg.json to include plugins found in config.xml', function () {
+    var tmpDir = helpers.tmpDir('platform_test_pkgjson');
+    var project = path.join(tmpDir, 'project');
+    var results;
+
+    beforeEach(function() {
+        shell.rm('-rf', tmpDir);
+        // Copy then move because we need to copy everything, but that means it will copy the whole directory.
+        // Using /* doesn't work because of hidden files.
+        shell.cp('-R', path.join(__dirname, 'fixtures', 'basePkgJson7'), tmpDir);
+        shell.mv(path.join(tmpDir, 'basePkgJson7'), project);
+        process.chdir(project);
+        events.on('results', function(res) { results = res; });
+    });
+
+    afterEach(function() {
+        var cwd = process.cwd();
+        delete require.cache[require.resolve(path.join(process.cwd(),'package.json'))];
+        process.chdir(path.join(__dirname, '..'));  // Needed to rm the dir on Windows.
+        shell.rm('-rf', tmpDir);
+    });
+
+    // Factoring out some repeated checks.
+    function emptyPlatformList() {
+        return cordova.raw.platform('list').then(function() {
+            var installed = results.match(/Installed platforms:\n  (.*)/);
+            expect(installed).toBeDefined();
+            expect(installed[1].indexOf(helpers.testPlatform)).toBe(-1);
+        });
+    }
+
+    function fullPlatformList() {
+        return cordova.raw.platform('list').then(function() {
+            var installed = results.match(/Installed platforms:\n  (.*)/);
+            expect(installed).toBeDefined();
+            expect(installed[1].indexOf(helpers.testPlatform)).toBeGreaterThan(-1);
+        });
+    }
+
+    /** Test#009 will check the platform list in package.json and config.xml. 
+    *   When config.xml has 'splashscreen and camera' and pkg.json only contains 'splashscreen', run cordova prepare
+    *   and pkg.json is updated to include 'camera'. After both files are identical, run cordova prepare
+    *   to double check that neither file is modified once they are the same.
+    */
+    it('Test#009 :  if config.xml has 2 plugins and pkg.json has only one of those plugins, update pkg.json to include both', function(done) {
+        var cwd = process.cwd();
+        var configXmlPath = path.join(cwd, 'config.xml');
+        var pkgJsonPath = path.join(cwd,'package.json');
+        delete require.cache[require.resolve(pkgJsonPath)];
+        var cfg1 = new ConfigParser(configXmlPath);
+        var plugins = cfg1.getPluginIdList();
+        var pkgJson = require(pkgJsonPath);
+        var pluginNames = plugins.map(function(elem) {
+            return elem;
+        });
+        var configPlugArray = pluginNames.slice();
+
+        // Expect that pkg.json exists with 1 plugin
+        expect(pkgJson.cordova.plugins).toBeDefined();
+        expect(pkgJson.cordova.plugins.length === 0);
+        expect(pkgJson.cordova.plugins.indexOf('cordova-plugin-camera')).toEqual(-1);
+        expect(pkgJson.cordova.plugins.indexOf('cordova-plugin-splashscreen')).toEqual(0);
+        // Expect that config.xml exists with 2 plugins
+        expect(configPlugArray).toBeDefined();
+        expect(configPlugArray.length === 1);
+        expect(configPlugArray.indexOf('cordova-plugin-camera')).toEqual(0);
+        expect(configPlugArray.indexOf('cordova-plugin-splashscreen')).toEqual(1);
+
+        emptyPlatformList().then(function() {
+            // Run cordova prepare
+            return cordova.raw.prepare();
+        }).then(function() {
+            // Delete any previous caches of require(package.json)
+            delete require.cache[require.resolve(pkgJsonPath)];
+            pkgJson = require(pkgJsonPath);
+            var cfg2 = new ConfigParser(configXmlPath);
+            plugins = cfg2.getPluginIdList();
+            pluginNames = plugins.map(function(elem) {
+                return elem;
+            });
+            configPlugArray = pluginNames.slice();
+            // Expect that pkg.json exists with 2 plugins
+            expect(pkgJson.cordova.plugins).toBeDefined();
+            expect(pkgJson.cordova.plugins.length === 1);
+            // Expect that config.xml exists with 2 plugins
+            expect(configPlugArray).toBeDefined();
+            expect(configPlugArray.length === 1);
+            // Expect config to contain camera and splashscreen
+            expect(configPlugArray.indexOf('cordova-plugin-camera')).toEqual(0);
+            expect(configPlugArray.indexOf('cordova-plugin-splashscreen')).toEqual(1);
+            // Expect pkg.json to contain camera and splashscreen
+            expect(pkgJson.cordova.plugins.indexOf('cordova-plugin-splashscreen')).toEqual(0);
+            expect(pkgJson.cordova.plugins.indexOf('cordova-plugin-camera')).toEqual(1);
+        }).then(function() {
+            // Now that files are the same, run cordova prepare again to check that neither 
+            // file gets modified again since both are identical now
+            return cordova.raw.prepare();
+        }).then(function() {
+            // Delete any previous caches of require(package.json)
+            delete require.cache[require.resolve(pkgJsonPath)];
+            pkgJson = require(pkgJsonPath);
+            var cfg2 = new ConfigParser(configXmlPath);
+            plugins = cfg2.getPluginIdList();
+            pluginNames = plugins.map(function(elem) {
+                return elem;
+            });
+            configPlugArray = pluginNames.slice();
+            // Expect that pkg.json exists with 2 plugins
+            expect(pkgJson.cordova.plugins).toBeDefined();
+            expect(pkgJson.cordova.plugins.length === 1);
+            // Expect that config.xml exists with 2 plugins
+            expect(configPlugArray).toBeDefined();
+            expect(configPlugArray.length === 1);
+            // Expect config to contain camera and splashscreen
+            expect(configPlugArray.indexOf('cordova-plugin-camera')).toEqual(0);
+            expect(configPlugArray.indexOf('cordova-plugin-splashscreen')).toEqual(1);
+            // Expect pkg.json to contain camera and splashscreen
+            expect(pkgJson.cordova.plugins.indexOf('cordova-plugin-splashscreen')).toEqual(0);
+            expect(pkgJson.cordova.plugins.indexOf('cordova-plugin-camera')).toEqual(1);
+        }).fail(function(err) {
+            expect(err).toBeUndefined();
+        }).fin(done);
+    // Cordova prepare needs extra wait time to complete.
+    },30000);
+});
 
 

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/4cd1be81/cordova-lib/spec-cordova/pkgJson.spec.js
----------------------------------------------------------------------
diff --git a/cordova-lib/spec-cordova/pkgJson.spec.js b/cordova-lib/spec-cordova/pkgJson.spec.js
index 4e90a99..4347a0e 100644
--- a/cordova-lib/spec-cordova/pkgJson.spec.js
+++ b/cordova-lib/spec-cordova/pkgJson.spec.js
@@ -313,7 +313,7 @@ describe('platform end-to-end with --save', function () {
             delete require.cache[require.resolve(pkgJsonPath)];
             pkgJson = require(pkgJsonPath);
             // Platform list should be empty and helpers.testPlatform should NOT have been added.
-            expect(pkgJson.cordova.platforms.indexOf(helpers.testPlatform)).toEqual(-1);
+            expect(pkgJson.cordova).toBeUndefined();
         }).then(fullPlatformList)
         .fail(function(err) {
             expect(err).toBeUndefined();
@@ -347,5 +347,41 @@ describe('platform end-to-end with --save', function () {
         })
         .fin(done);
     });
+    it('Test#010 : two platforms are added and removed correctly with --save --fetch', function(done) {
+        var pkgJsonPath = path.join(process.cwd(),'package.json');
+        expect(pkgJsonPath).toExist();
+        var pkgJson;
+
+        // Check there are no platforms yet.
+        emptyPlatformList().then(function() {
+            // Add the testing platform with --save.
+            return cordova.raw.platform('add', ['android', 'ios'], {'save':true, 'fetch':true});
+        }).then(function() {
+            // Check the platform add was successful.
+            delete require.cache[require.resolve(pkgJsonPath)];
+            pkgJson = require(pkgJsonPath);
+            expect(pkgJson.cordova.platforms).toBeDefined();
+            expect(pkgJson.cordova.platforms.indexOf('android')).toEqual(0);
+            expect(pkgJson.cordova.platforms.indexOf('ios')).toEqual(1);
+            expect(pkgJson.dependencies['cordova-android']).toBeDefined();
+            expect(pkgJson.dependencies['cordova-ios']).toBeDefined();
+        }).then(fullPlatformList) // Platform should still be in platform ls.
+        .then(function() {
+            // And now remove it with --save.
+            return cordova.raw.platform('rm', ['android', 'ios'], {'save':true, 'fetch':true});
+        }).then(function() {
+            // Delete any previous caches of require(package.json)
+            delete require.cache[require.resolve(pkgJsonPath)];
+            pkgJson = require(pkgJsonPath);
+            // Checking that the platform removed is in not in the platforms key
+            expect(pkgJson.cordova.platforms.indexOf('android')).toEqual(-1);
+            expect(pkgJson.cordova.platforms.indexOf('ios')).toEqual(-1);
+            expect(pkgJson.dependencies['cordova-android']).toBeUndefined();
+            expect(pkgJson.dependencies['cordova-ios']).toBeUndefined();
+        }).then(emptyPlatformList) // platform ls should be empty too.
+        .fail(function(err) {
+            expect(err).toBeUndefined();
+        }).fin(done);
+    }, 30000);
 });
 

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/4cd1be81/cordova-lib/spec-cordova/platform.spec.js
----------------------------------------------------------------------
diff --git a/cordova-lib/spec-cordova/platform.spec.js b/cordova-lib/spec-cordova/platform.spec.js
index 4a3b2f1..52b4362 100644
--- a/cordova-lib/spec-cordova/platform.spec.js
+++ b/cordova-lib/spec-cordova/platform.spec.js
@@ -6,9 +6,7 @@
     to you under the Apache License, Version 2.0 (the
     "License"); you may not use this file except in compliance
     with the License.  You may obtain a copy of the License at
-
     http://www.apache.org/licenses/LICENSE-2.0
-
     Unless required by applicable law or agreed to in writing,
     software distributed under the License is distributed on an
     "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -28,8 +26,6 @@ var helpers = require('./helpers'),
     cordova = require('../src/cordova/cordova'),
     plugman = require('../src/plugman/plugman'),
     rewire = require('rewire'),
-    prepare = require('../src/cordova/prepare'),
-    platforms = require('../src/platforms/platforms'),
     platform = rewire('../src/cordova/platform.js');
 
 var projectRoot = 'C:\\Projects\\cordova-projects\\move-tracker';
@@ -94,34 +90,6 @@ describe('platform end-to-end', function () {
             expect(installed[1].indexOf(helpers.testPlatform)).toBeGreaterThan(-1);
         });
     }
-    // Runs: list, add, list
-    function addPlugin(target, id, options) {
-        // Check there are no plugins yet.
-        return cordova.raw.plugin('list').then(function() {
-            expect(results).toMatch(/No plugins added/gi);
-        }).then(function() {
-            // Add a fake plugin from fixtures.
-            return cordova.raw.plugin('add', target, options);
-        }).then(function() {
-            expect(path.join(project, 'plugins', id, 'plugin.xml')).toExist();
-        }).then(function() {
-            return cordova.raw.plugin('ls');
-        }).then(function() {
-            expect(results).toContain(id);
-        });
-    }
-    // Runs: remove, list
-    function removePlugin(id) {
-        return cordova.raw.plugin('rm', id)
-        .then(function() {
-            // The whole dir should be gone.
-            expect(path.join(project, 'plugins', id)).not.toExist();
-        }).then(function() {
-            return cordova.raw.plugin('ls');
-        }).then(function() {
-            expect(results).toMatch(/No plugins added/gi);
-        });
-    }        
 
     // The flows we want to test are add, rm, list, and upgrade.
     // They should run the appropriate hooks.
@@ -134,7 +102,6 @@ describe('platform end-to-end', function () {
             // Add the testing platform.
             return cordova.raw.platform('add', [helpers.testPlatform]);
         }).then(function() {
-            console.log("!!!");
             // Check the platform add was successful.
             expect(path.join(project, 'platforms', helpers.testPlatform)).toExist();
             expect(path.join(project, 'platforms', helpers.testPlatform, 'cordova')).toExist();
@@ -150,6 +117,7 @@ describe('platform end-to-end', function () {
             // And now remove it.
             return cordova.raw.platform('rm', [helpers.testPlatform]);
         }).then(function() {
+            // It should be gone.
             expect(path.join(project, 'platforms', helpers.testPlatform)).not.toExist();
         }).then(emptyPlatformList) // platform ls should be empty too.
         .fail(function(err) {
@@ -385,7 +353,4 @@ describe('plugin add and rm end-to-end --fetch', function () {
         })
         .fin(done);
     }, 60000);
-});
-
-        // Runs: list, add, list
-    
\ No newline at end of file
+});
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/4cd1be81/cordova-lib/src/cordova/platform.js
----------------------------------------------------------------------
diff --git a/cordova-lib/src/cordova/platform.js b/cordova-lib/src/cordova/platform.js
index e34b4db..2b82e8a 100644
--- a/cordova-lib/src/cordova/platform.js
+++ b/cordova-lib/src/cordova/platform.js
@@ -83,16 +83,11 @@ function addHelper(cmd, hooksRunner, projectRoot, targets, opts) {
 
     return hooksRunner.fire('before_platform_' + cmd, opts)
     .then(function() {
-        var modifiedPkgJson = false;
-        var pkgJson;
-        var pkgJsonPath = path.join(projectRoot, 'package.json');
-        // If statement to see if pkgJsonPath exists in the filesystem
-        if(fs.existsSync(pkgJsonPath)) {
-            pkgJson = require(pkgJsonPath);
-        } else {
-            // Create package.json in cordova@7
-        }
+        
+        var platformsToSave = []; 
 
+        // If statement to see if pkgJsonPath exists in the filesystem
+        
         return promiseutil.Q_chainmap(targets, function(target) {
             // For each platform, download it and call its helper script.
             var parts = target.split('@');
@@ -130,6 +125,7 @@ function addHelper(cmd, hooksRunner, projectRoot, targets, opts) {
                 }
                 return downloadPlatform(projectRoot, platform, spec, opts);
             }).then(function(platDetails) {
+                delete require.cache[require.resolve(path.join(projectRoot, 'package.json'))];
                 platform = platDetails.platform;
                 var platformPath = path.join(projectRoot, 'platforms', platform);
                 var platformAlreadyAdded = fs.existsSync(platformPath);
@@ -226,7 +222,6 @@ function addHelper(cmd, hooksRunner, projectRoot, targets, opts) {
                 .then(function() {
                     var saveVersion = !spec || semver.validRange(spec, true);
 
-
                     // Save platform@spec into platforms.json, where 'spec' is a version or a soure location. If a
                     // source location was specified, we always save that. Otherwise we save the version that was
                     // actually installed.
@@ -245,30 +240,44 @@ function addHelper(cmd, hooksRunner, projectRoot, targets, opts) {
                         cfg.removeEngine(platform);
                         cfg.addEngine(platform, spec);
                         cfg.write();
-
-                        // If package.json exists, cordova key and platforms will be added to package.json if not
-                        // already there 
-                        if (pkgJson === undefined) {
-                            return;
-                        }
-                        if (pkgJson.cordova === undefined) {
-                            pkgJson.cordova = {};
-                        }
-                        if (pkgJson.cordova.platforms === undefined){
-                            pkgJson.cordova.platforms = [];
-                        }
-                        if (pkgJson.cordova.platforms.indexOf(platform) === -1) {
-                            events.emit('log','adding '+platform+' to cordova.platforms array in package.json');
-                            pkgJson.cordova.platforms.push(platform);
-                            modifiedPkgJson = true;
-                        } else {
-                            events.emit('verbose', platform + ' already added to platforms key');
-                        }
+                        
+                        //save to add to pacakge.json's cordova.platforms array in the next then
+                        platformsToSave.push(platform);
                     }
                 });
             });
-        }).then(function(){
+        }).then(function() {
+            var pkgJson;
+            var pkgJsonPath = path.join(projectRoot, 'package.json');
+            var modifiedPkgJson = false;
+
+            if(fs.existsSync(pkgJsonPath)) {
+                delete require.cache[require.resolve(pkgJsonPath)]; 
+                pkgJson = require(pkgJsonPath);
+            } else {
+                // Create package.json in cordova@7
+            }
+            if (pkgJson === undefined) {
+                return;
+            }
+            if (pkgJson.cordova === undefined) {
+                pkgJson.cordova = {};
+            }
+            if (pkgJson.cordova.platforms === undefined && platformsToSave.length) {
+                pkgJson.cordova.platforms = platformsToSave;
+                modifiedPkgJson = true;
+            } else {
+                platformsToSave.forEach(function(plat){
+                    if(pkgJson.cordova.platforms.indexOf(plat) === -1) {
+                        events.emit('verbose','adding '+plat+' to cordova.platforms array in package.json');
+                        pkgJson.cordova.platforms.push(plat);
+                        modifiedPkgJson = true;
+                    } 
+                });
+            }
+            //save to package.json
             if (modifiedPkgJson === true) {
+                pkgJson.cordova.platforms = pkgJson.cordova.platforms.sort();
                 fs.writeFileSync(pkgJsonPath, JSON.stringify(pkgJson, null, 4), 'utf8');
             }
         });
@@ -417,6 +426,7 @@ function remove(hooksRunner, projectRoot, targets, opts) {
         var pkgJsonPath = path.join(projectRoot,'package.json');
         // If statement to see if pkgJsonPath exists in the filesystem
         if(fs.existsSync(pkgJsonPath)) {
+            delete require.cache[require.resolve(pkgJsonPath)];
             pkgJson = require(pkgJsonPath);
         }
         if(opts.save || autosave){
@@ -452,7 +462,7 @@ function remove(hooksRunner, projectRoot, targets, opts) {
     }).then(function() {
         //Remove from node_modules if it exists and --fetch was used
         if(opts.fetch) {
-            targets.forEach(function(target) {
+            return promiseutil.Q_chainmap(targets, function(target) {
                 if(target in platforms) {
                     target = 'cordova-'+target;
                 }

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/4cd1be81/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 2ae8ec3..692c374 100644
--- a/cordova-lib/src/cordova/restore-util.js
+++ b/cordova-lib/src/cordova/restore-util.js
@@ -54,7 +54,6 @@ function installPlatformsFromConfigXML(platforms, opts) {
     var modifiedConfigXML = false;
     var modifiedPkgJsonPlugin = false;
     var modifiedConfigXMLPlugin = false;
-
     var targetPlatformsArray = [];
 
     if(fs.existsSync(pkgJsonPath)) {
@@ -225,7 +224,6 @@ function installPlatformsFromConfigXML(platforms, opts) {
 //returns a Promise
 function installPluginsFromConfigXML(args) {
     events.emit('verbose', 'Checking config.xml for saved plugins that haven\'t been added to the project');
-
     //Install plugins that are listed on config.xml
     var projectRoot = cordova_util.cdProjectRoot();
     var configPath = cordova_util.projectConfig(projectRoot);
@@ -233,14 +231,12 @@ function installPluginsFromConfigXML(args) {
     var plugins_dir = path.join(projectRoot, 'plugins');
     var pkgJsonPath = path.join(projectRoot,'package.json');
     var pkgJson;
-
     var pkgJsonArray = [];
     var comboPluginArray;
 
     // Get all configured plugins
-
-    var plugins = cfg.getPluginIdList();
-    if (0 === plugins.length) {
+    var pluginIdConfig = cfg.getPluginIdList();
+    if (0 === pluginIdConfig.length) {
         return Q('No plugins found in config.xml that haven\'t been added to the project');
     }
     // Check if path exists and require pkgJsonPath
@@ -250,78 +246,96 @@ function installPluginsFromConfigXML(args) {
     if (pkgJson.cordova === undefined) {
         pkgJson.cordova = {};
     }
-    // (In pkg.json), if there is a platforms array and not plugins array, create a new plugins array 
+    // (In pkg.json), if there is a platforms array and not plugins array, create a new pluginIdConfig array 
     // and add all plugins from config.xml to the new plugins array.
     if (cfg !== undefined && pkgJson !== undefined && pkgJson.cordova.platforms !== undefined && 
     pkgJson.cordova.plugins === undefined) {
         pkgJson.cordova.plugins = {};
-        plugins.forEach(function(foo) {
+        pluginIdConfig.forEach(function(foo) {
             pkgJson.cordova.plugins[foo] = {}
-        })
+        });
         fs.writeFileSync(pkgJsonPath, JSON.stringify(pkgJson, null, 4), 'utf8');
     }
-    // Created, but don't think this is necessary because there has to be at least one platform
-    // added for restore to run.
     // (In pkg.json), if there is no platforms array and no plugins array, create a new plugins array
     // and add all plugins from config.xml to the new plugins array.
     if (cfg !== undefined && pkgJson !== undefined && pkgJson.cordova.platforms === undefined && 
     pkgJson.cordova.plugins === undefined) {
         pkgJson.cordova.platforms = [];
         pkgJson.cordova.plugins = {};
-        plugins.forEach(function(foo) {
+        pluginIdConfig.forEach(function(foo) {
             pkgJson.cordova.plugins[foo] = {}
-        })
+        });
         fs.writeFileSync(pkgJsonPath, JSON.stringify(pkgJson, null, 4), 'utf8');
     }
 
     pkgJsonArray = Object.keys(pkgJson.cordova.plugins);
 
-    var pluginNames = plugins.map(function(elem) {
+    var pluginNames = pluginIdConfig.map(function(elem) {
         return elem.name;
     });
 
+    // Create a merged plugin data array (mergedPluginDataObj)
+    // and add all of the package.json plugins to mergedPluginDataObj
+    var mergedPluginDataObj = pkgJson.cordova.plugins;
+    var mergedPluginDataArray = pkgJsonArray;
+
+    // Check to see which plugins are initially the same in pkg.json and config.xml
+    // Merge identical plugins and their variables together first
+    for (var i = 0; i < mergedPluginDataArray.length; i++) {
+        if(pluginIdConfig.includes(mergedPluginDataArray[i])) {
+            var configPlugin = cfg.getPlugin(mergedPluginDataArray[i]);
+            var configPluginVariables = configPlugin.variables;
+            var pkgJsonPluginVariables = mergedPluginDataObj[mergedPluginDataArray[i]];
+            for(var key in configPluginVariables) {
+                // Handle conflicts, package.json wins
+                if(pkgJsonPluginVariables[key] === undefined) {
+                    pkgJsonPluginVariables[key] = configPluginVariables[key];
+                    mergedPluginDataObj[mergedPluginDataArray[i]][key] = configPluginVariables[key];
+                }
+            }
+        }
+    }
+    // Check to see if pkg.json plugin(id) and config plugin(id) match
+    if(mergedPluginDataArray.sort().toString() !== pluginIdConfig.sort().toString()) {
+        // If there is a config plugin that does NOT already exist in
+        // mergedPluginDataArray, add it and its variables
+        pluginIdConfig.forEach(function(item) {
+            if(mergedPluginDataArray.indexOf(item) < 0) {
+                mergedPluginDataArray.push(item);
+                var configXMLPlugin = cfg.getPlugin(item);
+                mergedPluginDataObj[item] = configXMLPlugin.variables;
+            }
+        });
+    }
+    // Write to pkg.Json
+    // TODO: toString comparision to see if they are the same and then write
+    pkgJson.cordova.plugins = mergedPluginDataObj;
+    fs.writeFileSync(pkgJsonPath, JSON.stringify(pkgJson, null, 4), 'utf8');
+
+    // Write config.xml
+    mergedPluginDataArray.forEach(function(plugID) {
+        cfg.removePlugin(plugID);
+        cfg.addPlugin({name:plugID}, mergedPluginDataObj[plugID]); 
+    });
+    cfg.write();
+
     // If config.xml and pkg.json exist and both already contain plugins, run cordova prepare
     // to check if these plugins are identical.
     if(cfg !== undefined && pkgJson.cordova.plugins !== undefined) {
-        if(pkgJsonArray.toString() === plugins.toString() && pkgJsonArray.length === plugins.length) {
+        if(pkgJsonArray.toString() === pluginIdConfig.toString() && pkgJsonArray.length === pluginIdConfig.length) {
             events.emit('warn', 'Config.xml and pkgJson plugins are the same. No pkg.json or config.xml modification.');
         }
 
-        if(pkgJsonArray.toString() !== plugins.toString() || pkgJsonArray.length !== plugins.length) {
+        if(pkgJsonArray.toString() !== pluginIdConfig.toString() || pkgJsonArray.length !== pluginIdConfig.length) {
            events.emit('warn', 'Config.xml and pkgJson plugins are different.');
             // Combining arrays and checking duplicates
 
             comboPluginArray = pkgJsonArray.slice();
-            plugins.forEach(function(item) {
+            pluginIdConfig.forEach(function(item) {
                 if(comboPluginArray.indexOf(item) < 0) {
                     comboPluginArray.push(item);
                 }
             });
-
-            // Update pkg.json if it's missing any plugins based on plugin.id 
-            if(comboPluginArray.sort().toString() !== pkgJsonArray.sort().toString() && pkgJsonArray.length > 0) {
-                events.emit('warn', 'Config.xml and package.json plugins are not the same. Updating package.json with most current list of plugins.');
-                comboPluginArray.forEach(function(item) {
-                    if(pkgJsonArray.indexOf(item) < 0) {
-                        pkgJsonArray.push(item);
-                        var pluginVar = cfg.getPlugin(item);
-                        var variables = pluginVar.variables;
-                        pkgJson.cordova.plugins[item] = variables;
-                    }
-                });
-                fs.writeFileSync(pkgJsonPath, JSON.stringify(pkgJson, null, 4), 'utf8');
-            }
-            // Update pkg.json if it's missing any plugins based on plugin.id 
-            if(comboPluginArray.toString() !== plugins.toString()) {
-                events.emit('warn', 'Config.xml and package.json plugins are not the same. Updating config.xml with most current list of plugins.');
-                comboPluginArray.forEach(function(item) {
-                    if(plugins.indexOf(item) < 0) {
-                        plugins.push(item); 
-                        cfg.addPlugin({name:item}, pkgJson.cordova.plugins[item]);
-                        cfg.write();
-                    }
-                });
-            }
         }
     }
     // Intermediate variable to store current installing plugin name
@@ -332,7 +346,7 @@ function installPluginsFromConfigXML(args) {
     // We need to wait for the plugin and its dependencies to be installed
     // before installing the next root plugin otherwise we can have common
     // plugin dependencies installed twice which throws a nasty error.
-    return promiseutil.Q_chainmap_graceful(plugins, function(featureId) {
+    return promiseutil.Q_chainmap_graceful(pluginIdConfig, function(featureId) {
         var pluginPath = path.join(plugins_dir, featureId);
         if (fs.existsSync(pluginPath)) {
             // Plugin already exists


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