Return-Path: X-Original-To: apmail-cordova-commits-archive@www.apache.org Delivered-To: apmail-cordova-commits-archive@www.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id DBE31DC35 for ; Thu, 16 May 2013 15:57:03 +0000 (UTC) Received: (qmail 10473 invoked by uid 500); 16 May 2013 15:57:02 -0000 Delivered-To: apmail-cordova-commits-archive@cordova.apache.org Received: (qmail 10360 invoked by uid 500); 16 May 2013 15:57:02 -0000 Mailing-List: contact commits-help@cordova.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@cordova.apache.org Delivered-To: mailing list commits@cordova.apache.org Received: (qmail 10001 invoked by uid 99); 16 May 2013 15:57:01 -0000 Received: from tyr.zones.apache.org (HELO tyr.zones.apache.org) (140.211.11.114) by apache.org (qpsmtpd/0.29) with ESMTP; Thu, 16 May 2013 15:57:01 +0000 Received: by tyr.zones.apache.org (Postfix, from userid 65534) id 1B41114BE8; Thu, 16 May 2013 15:57:01 +0000 (UTC) Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: filmaj@apache.org To: commits@cordova.apache.org Date: Thu, 16 May 2013 15:57:08 -0000 Message-Id: <5627e6db2384489dad4f74dfcfcc669d@git.apache.org> In-Reply-To: <8ceeae865bc04b108bf342995847fe65@git.apache.org> References: <8ceeae865bc04b108bf342995847fe65@git.apache.org> X-Mailer: ASF-Git Admin Mailer Subject: [09/20] git commit: updated/fixed install + uninstall specs. added specs to both for plugins with dependencies updated/fixed install + uninstall specs. added specs to both for plugins with dependencies Project: http://git-wip-us.apache.org/repos/asf/cordova-plugman/repo Commit: http://git-wip-us.apache.org/repos/asf/cordova-plugman/commit/bf56f3ed Tree: http://git-wip-us.apache.org/repos/asf/cordova-plugman/tree/bf56f3ed Diff: http://git-wip-us.apache.org/repos/asf/cordova-plugman/diff/bf56f3ed Branch: refs/heads/master Commit: bf56f3eddda3f88cb09bfd487a3c58d112c335e3 Parents: e05e51a Author: Fil Maj Authored: Wed May 15 12:59:07 2013 -0700 Committer: Fil Maj Committed: Thu May 16 08:55:42 2013 -0700 ---------------------------------------------------------------------- main.js | 4 +- spec/install.spec.js | 127 ++++++++++++++------------- spec/plugins/dependencies/A/plugin.xml | 60 +++++++++++++ spec/plugins/dependencies/B/plugin.xml | 60 +++++++++++++ spec/plugins/dependencies/C/plugin.xml | 57 ++++++++++++ spec/plugins/dependencies/D/plugin.xml | 57 ++++++++++++ spec/plugins/dependencies/E/plugin.xml | 57 ++++++++++++ spec/plugins/dependencies/README.md | 5 + spec/uninstall.spec.js | 92 +++++++++----------- src/install.js | 46 ++++++---- src/uninstall.js | 31 ++++--- src/util/action-stack.js | 24 +++-- 12 files changed, 462 insertions(+), 158 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/cordova-plugman/blob/bf56f3ed/main.js ---------------------------------------------------------------------- diff --git a/main.js b/main.js index 414cf18..8339061 100755 --- a/main.js +++ b/main.js @@ -63,7 +63,7 @@ else if (!cli_opts.platform || !cli_opts.project || !cli_opts.plugin) { printUsage(); } else if (cli_opts.uninstall) { - plugman.uninstall(cli_opts.platform, cli_opts.project, cli_opts.plugin, plugins_dir, {}, cli_opts.www, true /* is top level? */); + plugman.uninstall(cli_opts.platform, cli_opts.project, cli_opts.plugin, plugins_dir, {}, cli_opts.www); } else { var cli_variables = {} @@ -74,7 +74,7 @@ else { if (/^[\w-_]+$/.test(key)) cli_variables[key] = tokens.join('='); }); } - plugman.install(cli_opts.platform, cli_opts.project, cli_opts.plugin, plugins_dir, '.', cli_variables, cli_opts.www, true /* is top level? */); + plugman.install(cli_opts.platform, cli_opts.project, cli_opts.plugin, plugins_dir, '.', cli_variables, cli_opts.www); } function printUsage() { http://git-wip-us.apache.org/repos/asf/cordova-plugman/blob/bf56f3ed/spec/common.spec.js ---------------------------------------------------------------------- diff --git a/spec/common.spec.js b/spec/common.spec.js deleted file mode 100644 index e69de29..0000000 http://git-wip-us.apache.org/repos/asf/cordova-plugman/blob/bf56f3ed/spec/install.spec.js ---------------------------------------------------------------------- diff --git a/spec/install.spec.js b/spec/install.spec.js index c471747..34bc9e2 100644 --- a/spec/install.spec.js +++ b/spec/install.spec.js @@ -1,6 +1,6 @@ var install = require('../src/install'), - android = require('../src/platforms/android'), common = require('../src/platforms/common'), + actions = require('../src/util/action-stack'), //ios = require('../src/platforms/ios'), //blackberry = require('../src/platforms/blackberry'), config_changes = require('../src/util/config-changes'), @@ -11,7 +11,13 @@ var install = require('../src/install'), shell = require('shelljs'), temp = path.join(os.tmpdir(), 'plugman'), childbrowser = path.join(__dirname, 'plugins', 'ChildBrowser'), + dep_a = path.join(__dirname, 'plugins', 'dependencies', 'A'), + dep_b = path.join(__dirname, 'plugins', 'dependencies', 'B'), + dep_c = path.join(__dirname, 'plugins', 'dependencies', 'C'), + dep_d = path.join(__dirname, 'plugins', 'dependencies', 'D'), + dep_e = path.join(__dirname, 'plugins', 'dependencies', 'E'), dummyplugin = path.join(__dirname, 'plugins', 'DummyPlugin'), + dummy_id = 'com.phonegap.plugins.dummyplugin', variableplugin = path.join(__dirname, 'plugins', 'VariablePlugin'), faultyplugin = path.join(__dirname, 'plugins', 'FaultyPlugin'), android_one_project = path.join(__dirname, 'projects', 'android_one', '*'); @@ -24,26 +30,19 @@ describe('install', function() { beforeEach(function() { shell.mkdir('-p', temp); - shell.mkdir('-p', plugins_dir); shell.cp('-rf', android_one_project, temp); }); afterEach(function() { shell.rm('-rf', temp); }); - describe('success', function() { - var android_installer; - beforeEach(function() { - shell.cp('-rf', dummyplugin, plugins_dir); - android_installer = spyOn(android, 'install'); - }); it('should properly install assets', function() { var s = spyOn(common, 'copyFile').andCallThrough(); - install('android', temp, 'DummyPlugin', plugins_dir, {}); + install('android', temp, dummyplugin, plugins_dir, '.', {}); // making sure the right methods were called expect(s).toHaveBeenCalled(); - expect(s.calls.length).toEqual(2); + expect(s.calls.length).toEqual(3); expect(fs.existsSync(path.join(temp, 'assets', 'www', 'dummyplugin.js'))).toBe(true); expect(fs.existsSync(path.join(temp, 'assets', 'www', 'dummyplugin'))).toBe(true); @@ -57,14 +56,16 @@ describe('install', function() { var sRemoveFile = spyOn(common, 'removeFile').andCallThrough(); var sRemoveFileF = spyOn(common, 'removeFileF').andCallThrough(); - // messing the plugin - shell.rm('-rf', path.join(plugins_dir, 'dummyplugin', 'www', 'dummyplugin')); + // messing with the plugin + shell.mkdir('-p', plugins_dir); + shell.cp('-rf', dummyplugin, plugins_dir); + shell.rm('-rf', path.join(plugins_dir, 'DummyPlugin', 'www', 'dummyplugin')); expect(function() { - install('android', temp, 'DummyPlugin', plugins_dir, {}); + install('android', temp, 'DummyPlugin', plugins_dir, '.', {}); }).toThrow(); // making sure the right methods were called expect(sCopyFile).toHaveBeenCalled(); - expect(sCopyFile.calls.length).toEqual(2); + expect(sCopyFile.calls.length).toEqual(3); expect(sRemoveFile).toHaveBeenCalled(); expect(sRemoveFile.calls.length).toEqual(1); @@ -77,10 +78,10 @@ describe('install', function() { it('should properly install assets into a custom www dir', function() { var s = spyOn(common, 'copyFile').andCallThrough(); - install('android', temp, 'DummyPlugin', plugins_dir, {}, path.join(temp, 'staging')); + install('android', temp, dummyplugin, plugins_dir, '.', {}, path.join(temp, 'staging')); // making sure the right methods were called expect(s).toHaveBeenCalled(); - expect(s.calls.length).toEqual(2); + expect(s.calls.length).toEqual(3); expect(fs.existsSync(path.join(temp, 'staging', 'dummyplugin.js'))).toBe(true); expect(fs.existsSync(path.join(temp, 'staging', 'dummyplugin'))).toBe(true); @@ -96,13 +97,15 @@ describe('install', function() { var sRemoveFileF = spyOn(common, 'removeFileF').andCallThrough(); // messing the plugin + shell.mkdir('-p', plugins_dir); + shell.cp('-rf', dummyplugin, plugins_dir); shell.rm('-rf', path.join(plugins_dir, 'dummyplugin', 'www', 'dummyplugin')); expect(function() { - install('android', temp, 'DummyPlugin', plugins_dir, {}, path.join(temp, 'staging')); + install('android', temp, 'DummyPlugin', plugins_dir, '.', {}, path.join(temp, 'staging')); }).toThrow(); // making sure the right methods were called expect(sCopyFile).toHaveBeenCalled(); - expect(sCopyFile.calls.length).toEqual(2); + expect(sCopyFile.calls.length).toEqual(3); expect(sRemoveFile).toHaveBeenCalled(); expect(sRemoveFile.calls.length).toEqual(1); @@ -115,38 +118,56 @@ describe('install', function() { it('should call prepare after a successful install', function() { var s = spyOn(plugman, 'prepare'); - install('android', temp, 'DummyPlugin', plugins_dir, {}); - android_installer.mostRecentCall.args[5](); // fake the installer calling back successfully + install('android', temp, dummyplugin, plugins_dir, '.', {}); expect(s).toHaveBeenCalled(); }); it('should call fetch if provided plugin cannot be resolved locally', function() { var s = spyOn(plugman, 'fetch'); - install('android', temp, 'CLEANYOURSHORTS', plugins_dir, {}); + install('android', temp, 'CLEANYOURSHORTS', plugins_dir, '.', {}); expect(s).toHaveBeenCalled(); }); - it('should generate an array of transactions required to run an installation and pass into appropriate platform handler\'s install method', function() { - install('android', temp, 'DummyPlugin', plugins_dir, {}); - var transactions = android_installer.mostRecentCall.args[0]; - - expect(transactions.length).toEqual(1); - expect(transactions[0].tag).toBe('source-file'); - }); it('should call the config-changes module\'s add_installed_plugin_to_prepare_queue method', function() { - install('android', temp, 'DummyPlugin', plugins_dir, {}); var spy = spyOn(config_changes, 'add_installed_plugin_to_prepare_queue'); - android_installer.mostRecentCall.args[5](null); // fake out handler install callback - expect(spy).toHaveBeenCalledWith(plugins_dir, 'DummyPlugin', 'android', {}); + install('android', temp, dummyplugin, plugins_dir, '.', {}); + expect(spy).toHaveBeenCalledWith(plugins_dir, dummy_id, 'android', {}, true); + }); + it('should notify if plugin is already installed into project', function() { + expect(function() { + install('android', temp, dummyplugin, plugins_dir,'.', {}); + }).not.toThrow(); + var spy = spyOn(console, 'log'); + install('android', temp, dummyplugin, plugins_dir, '.', {}); + expect(spy).toHaveBeenCalledWith('Plugin "com.phonegap.plugins.dummyplugin" already installed, \'sall good.'); + }); + + describe('with dependencies', function() { + it('should process all dependent plugins', function() { + var spy = spyOn(actions.prototype, 'process').andCallThrough(); + shell.mkdir('-p', plugins_dir); + shell.cp('-rf', dep_a, plugins_dir); + shell.cp('-rf', dep_d, plugins_dir); + shell.cp('-rf', dep_c, plugins_dir); + install('android', temp, 'A', plugins_dir, '.', {}); + expect(spy.calls.length).toEqual(3); + }); + it('should fetch any dependent plugins if missing', function() { + var spy = spyOn(plugman, 'fetch'); + shell.mkdir('-p', plugins_dir); + shell.cp('-rf', dep_a, plugins_dir); + shell.cp('-rf', dep_c, plugins_dir); + install('android', temp, 'A', plugins_dir, '.', {}); + expect(spy).toHaveBeenCalled(); + }); }); }); describe('failure', function() { it('should throw if asset target already exists', function() { - shell.cp('-rf', dummyplugin, plugins_dir); var target = path.join(temp, 'assets', 'www', 'dummyplugin.js'); fs.writeFileSync(target, 'some bs', 'utf-8'); expect(function() { - install('android', temp, 'DummyPlugin', plugins_dir, {}); + install('android', temp, dummyplugin, plugins_dir, '.', {}); }).toThrow(); }); it('should throw if platform is unrecognized', function() { @@ -155,44 +176,28 @@ describe('install', function() { }).toThrow('atari not supported.'); }); it('should throw if variables are missing', function() { - shell.cp('-rf', variableplugin, plugins_dir); expect(function() { - install('android', temp, 'VariablePlugin', plugins_dir, {}); + install('android', temp, variableplugin, plugins_dir, '.', {}); }).toThrow('Variable(s) missing: API_KEY'); }); - it('should handle a failed install by passing completed transactions into appropriate handler\'s uninstall method', function() { - shell.cp('-rf', faultyplugin, plugins_dir); - var s = spyOn(android, 'uninstall'); - install('android', temp, 'FaultyPlugin', plugins_dir, {}); - - var executed_txs = s.mostRecentCall.args[0]; - expect(executed_txs.length).toEqual(0); - }); - it('should throw if plugin is already installed into project', function() { - // TODO: plugins and their version can be recognized using the platform.json file + it('should throw if a file required for installation cannot be found', function() { + shell.mkdir('-p', plugins_dir); shell.cp('-rf', dummyplugin, plugins_dir); + shell.rm(path.join(plugins_dir, 'DummyPlugin', 'src', 'android', 'DummyPlugin.java')); + expect(function() { - install('android', temp, 'DummyPlugin', plugins_dir, {}); - }).not.toThrow(); - expect(function() { - install('android', temp, 'DummyPlugin', plugins_dir, {}); + install('android', temp, 'DummyPlugin', plugins_dir, '.', {}); }).toThrow(); }); - it('should revert web assets if an install error occurs', function() { - var sRemoveFile = spyOn(common, 'removeFile').andCallThrough(); - var sRemoveFileF = spyOn(common, 'removeFileF').andCallThrough(); + it('should pass error into specified callback if a file required for installation cannot be found', function(done) { + shell.mkdir('-p', plugins_dir); shell.cp('-rf', dummyplugin, plugins_dir); shell.rm(path.join(plugins_dir, 'DummyPlugin', 'src', 'android', 'DummyPlugin.java')); - install('android', temp, 'DummyPlugin', plugins_dir, {}, undefined, function() {}); - - expect(sRemoveFile).toHaveBeenCalled(); - expect(sRemoveFile.calls.length).toEqual(2); - expect(sRemoveFileF).toHaveBeenCalled(); - expect(sRemoveFileF.calls.length).toEqual(1); - - expect(fs.existsSync(path.join(temp, 'assets', 'www', 'dummyplugin.js'))).toBe(false); - expect(fs.existsSync(path.join(temp, 'assets', 'www', 'dummyplugin'))).toBe(false); + install('android', temp, 'DummyPlugin', plugins_dir, '.', {}, null, function(err) { + expect(err).toBeDefined(); + done(); + }); }); }); }); http://git-wip-us.apache.org/repos/asf/cordova-plugman/blob/bf56f3ed/spec/plugins/dependencies/A/plugin.xml ---------------------------------------------------------------------- diff --git a/spec/plugins/dependencies/A/plugin.xml b/spec/plugins/dependencies/A/plugin.xml new file mode 100644 index 0000000..604f191 --- /dev/null +++ b/spec/plugins/dependencies/A/plugin.xml @@ -0,0 +1,60 @@ + + + + + + Plugin A + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + http://git-wip-us.apache.org/repos/asf/cordova-plugman/blob/bf56f3ed/spec/plugins/dependencies/A/src/android/A.java ---------------------------------------------------------------------- diff --git a/spec/plugins/dependencies/A/src/android/A.java b/spec/plugins/dependencies/A/src/android/A.java new file mode 100644 index 0000000..e69de29 http://git-wip-us.apache.org/repos/asf/cordova-plugman/blob/bf56f3ed/spec/plugins/dependencies/A/src/ios/APluginCommand.h ---------------------------------------------------------------------- diff --git a/spec/plugins/dependencies/A/src/ios/APluginCommand.h b/spec/plugins/dependencies/A/src/ios/APluginCommand.h new file mode 100644 index 0000000..e69de29 http://git-wip-us.apache.org/repos/asf/cordova-plugman/blob/bf56f3ed/spec/plugins/dependencies/A/src/ios/APluginCommand.m ---------------------------------------------------------------------- diff --git a/spec/plugins/dependencies/A/src/ios/APluginCommand.m b/spec/plugins/dependencies/A/src/ios/APluginCommand.m new file mode 100644 index 0000000..e69de29 http://git-wip-us.apache.org/repos/asf/cordova-plugman/blob/bf56f3ed/spec/plugins/dependencies/A/www/plugin-a.js ---------------------------------------------------------------------- diff --git a/spec/plugins/dependencies/A/www/plugin-a.js b/spec/plugins/dependencies/A/www/plugin-a.js new file mode 100644 index 0000000..e69de29 http://git-wip-us.apache.org/repos/asf/cordova-plugman/blob/bf56f3ed/spec/plugins/dependencies/B/plugin.xml ---------------------------------------------------------------------- diff --git a/spec/plugins/dependencies/B/plugin.xml b/spec/plugins/dependencies/B/plugin.xml new file mode 100644 index 0000000..6f92495 --- /dev/null +++ b/spec/plugins/dependencies/B/plugin.xml @@ -0,0 +1,60 @@ + + + + + + Plugin B + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + http://git-wip-us.apache.org/repos/asf/cordova-plugman/blob/bf56f3ed/spec/plugins/dependencies/B/src/android/B.java ---------------------------------------------------------------------- diff --git a/spec/plugins/dependencies/B/src/android/B.java b/spec/plugins/dependencies/B/src/android/B.java new file mode 100644 index 0000000..e69de29 http://git-wip-us.apache.org/repos/asf/cordova-plugman/blob/bf56f3ed/spec/plugins/dependencies/B/src/ios/BPluginCommand.h ---------------------------------------------------------------------- diff --git a/spec/plugins/dependencies/B/src/ios/BPluginCommand.h b/spec/plugins/dependencies/B/src/ios/BPluginCommand.h new file mode 100644 index 0000000..e69de29 http://git-wip-us.apache.org/repos/asf/cordova-plugman/blob/bf56f3ed/spec/plugins/dependencies/B/src/ios/BPluginCommand.m ---------------------------------------------------------------------- diff --git a/spec/plugins/dependencies/B/src/ios/BPluginCommand.m b/spec/plugins/dependencies/B/src/ios/BPluginCommand.m new file mode 100644 index 0000000..e69de29 http://git-wip-us.apache.org/repos/asf/cordova-plugman/blob/bf56f3ed/spec/plugins/dependencies/B/www/plugin-b.js ---------------------------------------------------------------------- diff --git a/spec/plugins/dependencies/B/www/plugin-b.js b/spec/plugins/dependencies/B/www/plugin-b.js new file mode 100644 index 0000000..e69de29 http://git-wip-us.apache.org/repos/asf/cordova-plugman/blob/bf56f3ed/spec/plugins/dependencies/C/plugin.xml ---------------------------------------------------------------------- diff --git a/spec/plugins/dependencies/C/plugin.xml b/spec/plugins/dependencies/C/plugin.xml new file mode 100644 index 0000000..5baf559 --- /dev/null +++ b/spec/plugins/dependencies/C/plugin.xml @@ -0,0 +1,57 @@ + + + + + + Plugin C + + + + + + + + + + + + + + + + + + + + + + + + + + + + http://git-wip-us.apache.org/repos/asf/cordova-plugman/blob/bf56f3ed/spec/plugins/dependencies/C/src/android/C.java ---------------------------------------------------------------------- diff --git a/spec/plugins/dependencies/C/src/android/C.java b/spec/plugins/dependencies/C/src/android/C.java new file mode 100644 index 0000000..e69de29 http://git-wip-us.apache.org/repos/asf/cordova-plugman/blob/bf56f3ed/spec/plugins/dependencies/C/src/ios/CPluginCommand.h ---------------------------------------------------------------------- diff --git a/spec/plugins/dependencies/C/src/ios/CPluginCommand.h b/spec/plugins/dependencies/C/src/ios/CPluginCommand.h new file mode 100644 index 0000000..e69de29 http://git-wip-us.apache.org/repos/asf/cordova-plugman/blob/bf56f3ed/spec/plugins/dependencies/C/src/ios/CPluginCommand.m ---------------------------------------------------------------------- diff --git a/spec/plugins/dependencies/C/src/ios/CPluginCommand.m b/spec/plugins/dependencies/C/src/ios/CPluginCommand.m new file mode 100644 index 0000000..e69de29 http://git-wip-us.apache.org/repos/asf/cordova-plugman/blob/bf56f3ed/spec/plugins/dependencies/C/www/plugin-c.js ---------------------------------------------------------------------- diff --git a/spec/plugins/dependencies/C/www/plugin-c.js b/spec/plugins/dependencies/C/www/plugin-c.js new file mode 100644 index 0000000..e69de29 http://git-wip-us.apache.org/repos/asf/cordova-plugman/blob/bf56f3ed/spec/plugins/dependencies/D/plugin.xml ---------------------------------------------------------------------- diff --git a/spec/plugins/dependencies/D/plugin.xml b/spec/plugins/dependencies/D/plugin.xml new file mode 100644 index 0000000..94449ef --- /dev/null +++ b/spec/plugins/dependencies/D/plugin.xml @@ -0,0 +1,57 @@ + + + + + + Plugin D + + + + + + + + + + + + + + + + + + + + + + + + + + + + http://git-wip-us.apache.org/repos/asf/cordova-plugman/blob/bf56f3ed/spec/plugins/dependencies/D/src/android/D.java ---------------------------------------------------------------------- diff --git a/spec/plugins/dependencies/D/src/android/D.java b/spec/plugins/dependencies/D/src/android/D.java new file mode 100644 index 0000000..e69de29 http://git-wip-us.apache.org/repos/asf/cordova-plugman/blob/bf56f3ed/spec/plugins/dependencies/D/src/ios/DPluginCommand.h ---------------------------------------------------------------------- diff --git a/spec/plugins/dependencies/D/src/ios/DPluginCommand.h b/spec/plugins/dependencies/D/src/ios/DPluginCommand.h new file mode 100644 index 0000000..e69de29 http://git-wip-us.apache.org/repos/asf/cordova-plugman/blob/bf56f3ed/spec/plugins/dependencies/D/src/ios/DPluginCommand.m ---------------------------------------------------------------------- diff --git a/spec/plugins/dependencies/D/src/ios/DPluginCommand.m b/spec/plugins/dependencies/D/src/ios/DPluginCommand.m new file mode 100644 index 0000000..e69de29 http://git-wip-us.apache.org/repos/asf/cordova-plugman/blob/bf56f3ed/spec/plugins/dependencies/D/www/plugin-d.js ---------------------------------------------------------------------- diff --git a/spec/plugins/dependencies/D/www/plugin-d.js b/spec/plugins/dependencies/D/www/plugin-d.js new file mode 100644 index 0000000..e69de29 http://git-wip-us.apache.org/repos/asf/cordova-plugman/blob/bf56f3ed/spec/plugins/dependencies/E/plugin.xml ---------------------------------------------------------------------- diff --git a/spec/plugins/dependencies/E/plugin.xml b/spec/plugins/dependencies/E/plugin.xml new file mode 100644 index 0000000..2564e96 --- /dev/null +++ b/spec/plugins/dependencies/E/plugin.xml @@ -0,0 +1,57 @@ + + + + + + Plugin E + + + + + + + + + + + + + + + + + + + + + + + + + + + + http://git-wip-us.apache.org/repos/asf/cordova-plugman/blob/bf56f3ed/spec/plugins/dependencies/E/src/android/E.java ---------------------------------------------------------------------- diff --git a/spec/plugins/dependencies/E/src/android/E.java b/spec/plugins/dependencies/E/src/android/E.java new file mode 100644 index 0000000..e69de29 http://git-wip-us.apache.org/repos/asf/cordova-plugman/blob/bf56f3ed/spec/plugins/dependencies/E/src/ios/EPluginCommand.h ---------------------------------------------------------------------- diff --git a/spec/plugins/dependencies/E/src/ios/EPluginCommand.h b/spec/plugins/dependencies/E/src/ios/EPluginCommand.h new file mode 100644 index 0000000..e69de29 http://git-wip-us.apache.org/repos/asf/cordova-plugman/blob/bf56f3ed/spec/plugins/dependencies/E/src/ios/EPluginCommand.m ---------------------------------------------------------------------- diff --git a/spec/plugins/dependencies/E/src/ios/EPluginCommand.m b/spec/plugins/dependencies/E/src/ios/EPluginCommand.m new file mode 100644 index 0000000..e69de29 http://git-wip-us.apache.org/repos/asf/cordova-plugman/blob/bf56f3ed/spec/plugins/dependencies/E/www/plugin-e.js ---------------------------------------------------------------------- diff --git a/spec/plugins/dependencies/E/www/plugin-e.js b/spec/plugins/dependencies/E/www/plugin-e.js new file mode 100644 index 0000000..e69de29 http://git-wip-us.apache.org/repos/asf/cordova-plugman/blob/bf56f3ed/spec/plugins/dependencies/README.md ---------------------------------------------------------------------- diff --git a/spec/plugins/dependencies/README.md b/spec/plugins/dependencies/README.md new file mode 100644 index 0000000..29cc70f --- /dev/null +++ b/spec/plugins/dependencies/README.md @@ -0,0 +1,5 @@ +Here's a general overview of how the plugins in this directory are dependent on each other: + + A B + / \ / \ + C '---D--' E http://git-wip-us.apache.org/repos/asf/cordova-plugman/blob/bf56f3ed/spec/uninstall.spec.js ---------------------------------------------------------------------- diff --git a/spec/uninstall.spec.js b/spec/uninstall.spec.js index c39812a..99d6026 100644 --- a/spec/uninstall.spec.js +++ b/spec/uninstall.spec.js @@ -1,6 +1,7 @@ var uninstall = require('../src/uninstall'), install = require('../src/install'), common = require('../src/platforms/common'), + actions = require('../src/util/action-stack'), android = require('../src/platforms/android'), ios = require('../src/platforms/ios'), blackberry = require('../src/platforms/blackberry'), @@ -14,41 +15,44 @@ var uninstall = require('../src/uninstall'), shell = require('shelljs'), temp = path.join(os.tmpdir(), 'plugman'), dummyplugin = path.join(__dirname, 'plugins', 'DummyPlugin'), + dummy_id = 'com.phonegap.plugins.dummyplugin', faultyplugin = path.join(__dirname, 'plugins', 'FaultyPlugin'), childbrowserplugin = path.join(__dirname, 'plugins', 'ChildBrowser'), + dep_a = path.join(__dirname, 'plugins', 'dependencies', 'A'), + dep_b = path.join(__dirname, 'plugins', 'dependencies', 'B'), + dep_c = path.join(__dirname, 'plugins', 'dependencies', 'C'), + dep_d = path.join(__dirname, 'plugins', 'dependencies', 'D'), + dep_e = path.join(__dirname, 'plugins', 'dependencies', 'E'), android_one_project = path.join(__dirname, 'projects', 'android_one', '*'), ios_project = path.join(__dirname, 'projects', 'ios-config-xml', '*'), plugins_dir = path.join(temp, 'cordova', 'plugins'); describe('uninstall', function() { var copied_plugin_path = path.join(temp,'ChildBrowser'); + var dummy_plugin_path = path.join(plugins_dir, dummy_id); beforeEach(function() { shell.mkdir('-p', temp); - shell.mkdir('-p', plugins_dir); shell.cp('-rf', android_one_project, temp); - shell.cp('-rf', dummyplugin, plugins_dir); }); afterEach(function() { shell.rm('-rf', temp); }); describe('success', function() { - var android_uninstaller; beforeEach(function() { - install('android', temp, 'DummyPlugin', plugins_dir, {}); - android_uninstaller = spyOn(android, 'uninstall'); + install('android', temp, dummyplugin, plugins_dir, '.', {}); }); it('should properly uninstall assets', function() { var s = spyOn(common, 'removeFile').andCallThrough(); var s2 = spyOn(common, 'removeFileF').andCallThrough(); // making sure the right methods were called - uninstall('android', temp, 'DummyPlugin', plugins_dir, {}); + uninstall('android', temp, dummy_id, plugins_dir, {}); expect(s).toHaveBeenCalled(); expect(s.calls.length).toEqual(2); expect(s2).toHaveBeenCalled(); - expect(s2.calls.length).toEqual(1); + expect(s2.calls.length).toEqual(2); expect(fs.existsSync(path.join(temp, 'assets', 'www', 'dummyplugin.js'))).toBe(false); expect(fs.existsSync(path.join(temp, 'assets', 'www', 'dummyplugin'))).toBe(false); @@ -61,28 +65,46 @@ describe('uninstall', function() { shell.rm('-rf', path.join(temp, 'assets', 'www', 'dummyplugin')); expect(function() { - uninstall('android', temp, 'DummyPlugin', plugins_dir, {}); + uninstall('android', temp, dummy_id, plugins_dir, {}); }).toThrow(); expect(sRemoveFile).toHaveBeenCalled(); expect(sRemoveFile.calls.length).toEqual(2); expect(sCopyFile).toHaveBeenCalled(); - expect(sCopyFile.calls.length).toEqual(1); + expect(sCopyFile.calls.length).toEqual(2); expect(fs.existsSync(path.join(temp, 'assets', 'www', 'dummyplugin.js'))).toBe(true); }); - it('should generate and pass uninstall transaction log to appropriate platform handler\'s uninstall', function() { - uninstall('android', temp, 'DummyPlugin', plugins_dir, {}); - var transactions = android_uninstaller.mostRecentCall.args[0]; - - expect(transactions.length).toEqual(1); - expect(transactions[0].tag).toBe('source-file'); - }); it('should call the config-changes module\'s add_uninstalled_plugin_to_prepare_queue method', function() { - uninstall('android', temp, 'DummyPlugin', plugins_dir, {}); var spy = spyOn(config_changes, 'add_uninstalled_plugin_to_prepare_queue'); - android_uninstaller.mostRecentCall.args[4](null); // fake out handler uninstall callback - expect(spy).toHaveBeenCalledWith(plugins_dir, 'DummyPlugin', 'android'); + uninstall('android', temp, dummy_id, plugins_dir, {}); + expect(spy).toHaveBeenCalledWith(plugins_dir, dummy_id, 'android', true); + }); + + describe('with dependencies', function() { + it('should uninstall any dependent plugins', function() { + shell.mkdir('-p', plugins_dir); + shell.cp('-rf', dep_a, plugins_dir); + shell.cp('-rf', dep_d, plugins_dir); + shell.cp('-rf', dep_c, plugins_dir); + install('android', temp, 'A', plugins_dir, '.', {}); + var spy = spyOn(actions.prototype, 'process').andCallThrough(); + uninstall('android', temp, 'A', plugins_dir, {}); + expect(spy.calls.length).toEqual(3); + }); + it('should not uninstall any dependent plugins that are required by other top-level plugins', function() { + shell.mkdir('-p', plugins_dir); + shell.cp('-rf', dep_a, plugins_dir); + shell.cp('-rf', dep_b, plugins_dir); + shell.cp('-rf', dep_d, plugins_dir); + shell.cp('-rf', dep_c, plugins_dir); + shell.cp('-rf', dep_e, plugins_dir); + install('android', temp, 'A', plugins_dir, '.', {}); + install('android', temp, 'B', plugins_dir, '.', {}); + var spy = spyOn(actions.prototype, 'process').andCallThrough(); + uninstall('android', temp, 'A', plugins_dir, {}); + expect(spy.calls.length).toEqual(2); + }); }); }); @@ -97,37 +119,5 @@ describe('uninstall', function() { uninstall('android', temp, 'SomePlugin', plugins_dir, {}); }).toThrow('Plugin "SomePlugin" not found. Already uninstalled?'); }); - // it('should handle a failed uninstall by passing completed transactions into appropriate handler\'s install method', function() { - // shell.rm('-rf', path.join(temp, '*')); - // shell.mkdir('-p', plugins_dir); - // - // shell.cp('-rf', ios_project, temp); - // shell.cp('-rf', childbrowserplugin, plugins_dir); - // install('ios', temp, 'ChildBrowser', plugins_dir, {}); - - // // make uninstall fail by removing a js asset - // shell.rm(path.join(temp, 'SampleApp', 'Plugins', 'ChildBrowserCommand.m')); - // var s = spyOn(ios, 'install'); - // uninstall('ios', temp, 'ChildBrowser', plugins_dir, {}); - // var executed_txs = s.mostRecentCall.args[0]; - // expect(executed_txs.length).toEqual(1); - // // It only ended up "uninstalling" one source file, so install reversion should pass in that source file to re-install - // expect(executed_txs[0].tag).toEqual('source-file'); - // }); - it('should revert assets when uninstall fails', function() { - install('android', temp, 'DummyPlugin', plugins_dir, {}); - - var s = spyOn(common, 'copyFile').andCallThrough(); - - shell.rm('-rf', path.join(temp, 'src', 'com', 'phonegap', 'plugins', 'dummyplugin')); - expect(function() { - uninstall('android', temp, 'DummyPlugin', plugins_dir, {}); - }).toThrow(); - expect(s).toHaveBeenCalled(); - expect(s.calls.length).toEqual(2); - - expect(fs.existsSync(path.join(temp, 'assets', 'www', 'dummyplugin.js'))).toBe(true); - expect(fs.existsSync(path.join(temp, 'assets', 'www', 'dummyplugin'))).toBe(true); - }); }); }); http://git-wip-us.apache.org/repos/asf/cordova-plugman/blob/bf56f3ed/src/install.js ---------------------------------------------------------------------- diff --git a/src/install.js b/src/install.js index 37a6dff..9a85e2c 100644 --- a/src/install.js +++ b/src/install.js @@ -6,7 +6,7 @@ var path = require('path'), action_stack = require('./util/action-stack'), platform_modules = require('./platforms'); -module.exports = function installPlugin(platform, project_dir, id, plugins_dir, subdir, cli_variables, www_dir, is_top_level, callback) { +module.exports = function installPlugin(platform, project_dir, id, plugins_dir, subdir, cli_variables, www_dir, callback) { if (!platform_modules[platform]) { var err = new Error(platform + " not supported."); if (callback) callback(err); @@ -14,6 +14,12 @@ module.exports = function installPlugin(platform, project_dir, id, plugins_dir, return; } + var current_stack = new action_stack(); + + possiblyFetch(current_stack, platform, project_dir, id, plugins_dir, subdir, cli_variables, www_dir, true, callback); +}; + +function possiblyFetch(actions, platform, project_dir, id, plugins_dir, subdir, cli_variables, www_dir, is_top_level, callback) { var plugin_dir = path.join(plugins_dir, id); // Check that the plugin has already been fetched. @@ -25,15 +31,15 @@ module.exports = function installPlugin(platform, project_dir, id, plugins_dir, callback(err); } else { // update ref to plugin_dir after successful fetch, via fetch callback - runInstall(platform, project_dir, plugin_dir, plugins_dir, cli_variables, www_dir, is_top_level, callback); + runInstall(actions, platform, project_dir, plugin_dir, plugins_dir, cli_variables, www_dir, is_top_level, callback); } }); } else { - runInstall(platform, project_dir, plugin_dir, plugins_dir, cli_variables, www_dir, is_top_level, callback); + runInstall(actions, platform, project_dir, plugin_dir, plugins_dir, cli_variables, www_dir, is_top_level, callback); } -}; +} -function runInstall(platform, project_dir, plugin_dir, plugins_dir, cli_variables, www_dir, is_top_level, callback) { +function runInstall(actions, platform, project_dir, plugin_dir, plugins_dir, cli_variables, www_dir, is_top_level, callback) { var xml_path = path.join(plugin_dir, 'plugin.xml') , xml_text = fs.readFileSync(xml_path, 'utf-8') , plugin_et = new et.ElementTree(et.XML(xml_text)) @@ -83,7 +89,7 @@ function runInstall(platform, project_dir, plugin_dir, plugins_dir, cli_variable var dependencies = plugin_et.findall('dependency'); if (dependencies && dependencies.length) { var end = n(dependencies.length, function() { - handleInstall(plugin_id, plugin_et, platform, project_dir, plugins_dir, plugin_basename, plugin_dir, filtered_variables, www_dir, is_top_level, callback); + handleInstall(actions, plugin_id, plugin_et, platform, project_dir, plugins_dir, plugin_basename, plugin_dir, filtered_variables, www_dir, is_top_level, callback); }); dependencies.forEach(function(dep) { var dep_plugin_id = dep.attrib.id; @@ -92,21 +98,21 @@ function runInstall(platform, project_dir, plugin_dir, plugins_dir, cli_variable if (dep_subdir) { dep_subdir = path.join.apply(null, dep_subdir.split('/')); } - - if (fs.existsSync(path.join(plugins_dir, dep_plugin_id))) { - console.log('Dependent plugin ' + dep.attrib.id + ' already fetched, using that version.'); - module.exports(platform, project_dir, dep_plugin_id, plugins_dir, dep_subdir, filtered_variables, www_dir, false, end); + var dep_plugin_dir = path.join(plugins_dir, dep_plugin_id); + if (fs.existsSync(dep_plugin_dir)) { + console.log('Dependent plugin ' + dep_plugin_id + ' already fetched, using that version.'); + runInstall(actions, platform, project_dir, dep_plugin_dir, plugins_dir, filtered_variables, www_dir, false, end); } else { - console.log('Dependent plugin ' + dep.attrib.id + ' not fetched, retrieving then installing.'); - module.exports(platform, project_dir, dep_url, plugins_dir, dep_subdir, filtered_variables, www_dir, false, end); + console.log('Dependent plugin ' + dep_plugin_id + ' not fetched, retrieving then installing.'); + possiblyFetch(actions, platform, project_dir, dep_url, plugins_dir, dep_subdir, filtered_variables, www_dir, false, end); } }); } else { - handleInstall(plugin_id, plugin_et, platform, project_dir, plugins_dir, plugin_basename, plugin_dir, filtered_variables, www_dir, is_top_level, callback); + handleInstall(actions, plugin_id, plugin_et, platform, project_dir, plugins_dir, plugin_basename, plugin_dir, filtered_variables, www_dir, is_top_level, callback); } } -function handleInstall(plugin_id, plugin_et, platform, project_dir, plugins_dir, plugin_basename, plugin_dir, filtered_variables, www_dir, is_top_level, callback) { +function handleInstall(actions, plugin_id, plugin_et, platform, project_dir, plugins_dir, plugin_basename, plugin_dir, filtered_variables, www_dir, is_top_level, callback) { var handler = platform_modules[platform]; www_dir = www_dir || handler.www_dir(project_dir); @@ -121,30 +127,30 @@ function handleInstall(plugin_id, plugin_et, platform, project_dir, plugins_dir, // queue up native stuff sourceFiles && sourceFiles.forEach(function(source) { - action_stack.push(action_stack.createAction(handler["source-file"].install, [source, plugin_dir, project_dir], handler["source-file"].uninstall, [source, project_dir])); + actions.push(actions.createAction(handler["source-file"].install, [source, plugin_dir, project_dir], handler["source-file"].uninstall, [source, project_dir])); }); headerFiles && headerFiles.forEach(function(header) { - action_stack.push(action_stack.createAction(handler["header-file"].install, [header, plugin_dir, project_dir], handler["header-file"].uninstall, [header, project_dir])); + actions.push(actions.createAction(handler["header-file"].install, [header, plugin_dir, project_dir], handler["header-file"].uninstall, [header, project_dir])); }); resourceFiles && resourceFiles.forEach(function(resource) { - action_stack.push(action_stack.createAction(handler["resource-file"].install, [resource, plugin_dir, project_dir], handler["resource-file"].uninstall, [resource, project_dir])); + actions.push(actions.createAction(handler["resource-file"].install, [resource, plugin_dir, project_dir], handler["resource-file"].uninstall, [resource, project_dir])); }); frameworks && frameworks.forEach(function(framework) { - action_stack.push(action_stack.createAction(handler["framework"].install, [framework, plugin_dir, project_dir], handler["framework"].uninstall, [framework, project_dir])); + actions.push(actions.createAction(handler["framework"].install, [framework, plugin_dir, project_dir], handler["framework"].uninstall, [framework, project_dir])); }); } // queue up asset installation var common = require('./platforms/common'); assets && assets.forEach(function(asset) { - action_stack.push(action_stack.createAction(common.asset.install, [asset, plugin_dir, www_dir], common.asset.uninstall, [asset, www_dir, plugin_id])); + actions.push(actions.createAction(common.asset.install, [asset, plugin_dir, www_dir], common.asset.uninstall, [asset, www_dir, plugin_id])); }); // run through the action stack - action_stack.process(platform, project_dir, function(err) { + actions.process(platform, project_dir, function(err) { if (err) { if (callback) callback(err); else throw err; http://git-wip-us.apache.org/repos/asf/cordova-plugman/blob/bf56f3ed/src/uninstall.js ---------------------------------------------------------------------- diff --git a/src/uninstall.js b/src/uninstall.js index 986e7c1..7528876 100644 --- a/src/uninstall.js +++ b/src/uninstall.js @@ -9,7 +9,7 @@ var path = require('path'), underscore = require('underscore'), platform_modules = require('./platforms'); -module.exports = function uninstallPlugin(platform, project_dir, id, plugins_dir, cli_variables, www_dir, is_top_level, callback) { +module.exports = function uninstallPlugin(platform, project_dir, id, plugins_dir, cli_variables, www_dir, callback) { if (!platform_modules[platform]) { var err = new Error(platform + " not supported."); if (callback) callback(err); @@ -20,16 +20,18 @@ module.exports = function uninstallPlugin(platform, project_dir, id, plugins_dir var plugin_dir = path.join(plugins_dir, id); if (!fs.existsSync(plugin_dir)) { - var err = new Error('Plugin "' + name + '" not found. Already uninstalled?'); + var err = new Error('Plugin "' + id + '" not found. Already uninstalled?'); if (callback) callback(err); else throw err; return; } - runUninstall(platform, project_dir, plugin_dir, plugins_dir, cli_variables, www_dir, is_top_level, callback); + var current_stack = new action_stack(); + + runUninstall(current_stack, platform, project_dir, plugin_dir, plugins_dir, cli_variables, www_dir, true, callback); }; -function runUninstall(platform, project_dir, plugin_dir, plugins_dir, cli_variables, www_dir, is_top_level, callback) { +function runUninstall(actions, platform, project_dir, plugin_dir, plugins_dir, cli_variables, www_dir, is_top_level, callback) { var xml_path = path.join(plugin_dir, 'plugin.xml') , xml_text = fs.readFileSync(xml_path, 'utf-8') , plugin_et = new et.ElementTree(et.XML(xml_text)) @@ -60,18 +62,19 @@ function runUninstall(platform, project_dir, plugin_dir, plugins_dir, cli_variab var danglers = underscore.difference.apply(null, diff_arr); if (dependents.length && danglers && danglers.length) { var end = n(danglers.length, function() { - handleUninstall(platform, plugin_id, plugin_et, project_dir, www_dir, plugins_dir, plugin_dir, is_top_level, callback); + handleUninstall(actions, platform, plugin_id, plugin_et, project_dir, www_dir, plugins_dir, plugin_dir, is_top_level, callback); }); danglers.forEach(function(dangler) { - module.exports(platform, project_dir, dangler, plugins_dir, cli_variables, www_dir, false /* TODO: should this "is_top_level" param be false for dependents? */, end); + var dependent_path = path.join(plugins_dir, dangler); + runUninstall(actions, platform, project_dir, dependent_path, plugins_dir, cli_variables, www_dir, false /* TODO: should this "is_top_level" param be false for dependents? */, end); }); } else { // this plugin can get axed by itself, gogo! - handleUninstall(platform, plugin_id, plugin_et, project_dir, www_dir, plugins_dir, plugin_dir, is_top_level, callback); + handleUninstall(actions, platform, plugin_id, plugin_et, project_dir, www_dir, plugins_dir, plugin_dir, is_top_level, callback); } } -function handleUninstall(platform, plugin_id, plugin_et, project_dir, www_dir, plugins_dir, plugin_dir, is_top_level, callback) { +function handleUninstall(actions, platform, plugin_id, plugin_et, project_dir, www_dir, plugins_dir, plugin_dir, is_top_level, callback) { var platform_modules = require('./platforms'); var handler = platform_modules[platform]; var platformTag = plugin_et.find('./platform[@name="'+platform+'"]'); @@ -87,30 +90,30 @@ function handleUninstall(platform, plugin_id, plugin_et, project_dir, www_dir, p // queue up native stuff sourceFiles && sourceFiles.forEach(function(source) { - action_stack.push(action_stack.createAction(handler["source-file"].uninstall, [source, project_dir], handler["source-file"].install, [source, plugin_dir, project_dir])); + actions.push(actions.createAction(handler["source-file"].uninstall, [source, project_dir], handler["source-file"].install, [source, plugin_dir, project_dir])); }); headerFiles && headerFiles.forEach(function(header) { - action_stack.push(action_stack.createAction(handler["header-file"].uninstall, [header, project_dir], handler["header-file"].install, [header, plugin_dir, project_dir])); + actions.push(actions.createAction(handler["header-file"].uninstall, [header, project_dir], handler["header-file"].install, [header, plugin_dir, project_dir])); }); resourceFiles && resourceFiles.forEach(function(resource) { - action_stack.push(action_stack.createAction(handler["resource-file"].uninstall, [resource, project_dir], handler["resource-file"].install, [resource, plugin_dir, project_dir])); + actions.push(actions.createAction(handler["resource-file"].uninstall, [resource, project_dir], handler["resource-file"].install, [resource, plugin_dir, project_dir])); }); frameworks && frameworks.forEach(function(framework) { - action_stack.push(action_stack.createAction(handler["framework"].uninstall, [framework, project_dir], handler["framework"].install, [framework, plugin_dir, project_dir])); + actions.push(actions.createAction(handler["framework"].uninstall, [framework, project_dir], handler["framework"].install, [framework, plugin_dir, project_dir])); }); } // queue up asset installation var common = require('./platforms/common'); assets && assets.forEach(function(asset) { - action_stack.push(action_stack.createAction(common.asset.uninstall, [asset, www_dir, plugin_id], common.asset.install, [asset, plugin_dir, www_dir])); + actions.push(actions.createAction(common.asset.uninstall, [asset, www_dir, plugin_id], common.asset.install, [asset, plugin_dir, www_dir])); }); // run through the action stack - action_stack.process(platform, project_dir, function(err) { + actions.process(platform, project_dir, function(err) { if (err) { if (callback) callback(err); else throw err; http://git-wip-us.apache.org/repos/asf/cordova-plugman/blob/bf56f3ed/src/util/action-stack.js ---------------------------------------------------------------------- diff --git a/src/util/action-stack.js b/src/util/action-stack.js index a76f33c..115c6b7 100644 --- a/src/util/action-stack.js +++ b/src/util/action-stack.js @@ -1,10 +1,12 @@ var ios = require('../platforms/ios'), fs = require('fs'); -var stack = []; -var completed = []; +function ActionStack() { + this.stack = []; + this.completed = []; +} -module.exports = { +ActionStack.prototype = { createAction:function(handler, action_params, reverter, revert_params) { return { handler:{ @@ -18,26 +20,26 @@ module.exports = { }; }, push:function(tx) { - stack.push(tx); + this.stack.push(tx); }, process:function(platform, project_dir, callback) { if (platform == 'ios') { // parse xcode project file once var project_files = ios.parseIOSProjectFiles(project_dir); } - while(stack.length) { - var action = stack.shift(); + while(this.stack.length) { + var action = this.stack.shift(); var handler = action.handler.run; var action_params = action.handler.params; if (platform == 'ios') action_params.push(project_files); try { handler.apply(null, action_params); } catch(e) { - var incomplete = stack.unshift(action); + var incomplete = this.stack.unshift(action); var issue = 'Uh oh!\n'; // revert completed tasks - while(completed.length) { - var undo = completed.shift(); + while(this.completed.length) { + var undo = this.completed.shift(); var revert = undo.reverter.run; var revert_params = undo.reverter.params; if (platform == 'ios') revert_params.push(project_files); @@ -52,7 +54,7 @@ module.exports = { else throw e; return; } - completed.push(action); + this.completed.push(action); } if (platform == 'ios') { // write out xcodeproj file @@ -61,3 +63,5 @@ module.exports = { if (callback) callback(); } }; + +module.exports = ActionStack;