You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cordova.apache.org by fi...@apache.org on 2012/11/28 19:16:24 UTC

[39/50] git commit: handling multiple platform and plugin add/removes.

handling multiple platform and plugin add/removes.


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

Branch: refs/heads/master
Commit: 0d4c2f9e2b7eb99c72fa5b73488dbb2a8cad50f0
Parents: 20667dc
Author: Fil Maj <ma...@gmail.com>
Authored: Mon Oct 8 01:03:47 2012 -0700
Committer: Fil Maj <ma...@gmail.com>
Committed: Mon Oct 8 01:03:47 2012 -0700

----------------------------------------------------------------------
 spec/platform.spec.js |   32 ++++++--
 spec/plugin.spec.js   |   38 +++++++--
 src/build.js          |    2 +-
 src/platform.js       |  103 +++++++++++++-----------
 src/plugin.js         |  192 +++++++++++++++++++++++---------------------
 5 files changed, 215 insertions(+), 152 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/0d4c2f9e/spec/platform.spec.js
----------------------------------------------------------------------
diff --git a/spec/platform.spec.js b/spec/platform.spec.js
index e84ed31..3dfd197 100644
--- a/spec/platform.spec.js
+++ b/spec/platform.spec.js
@@ -197,6 +197,17 @@ describe('platform command', function() {
                 expect(s).toHaveBeenCalled();
             });
         });
+        it('should handle multiple platforms', function() {
+            var cb = jasmine.createSpy();
+            runs(function() {
+                cordova.platform('add', ['android', 'ios'], cb);
+            });
+            waitsFor(function() { return cb.wasCalled; }, "platform add ios+android callback");
+            runs(function() {
+                expect(fs.existsSync(path.join(tempDir, 'platforms', 'android', 'AndroidManifest.xml'))).toBe(true);
+                expect(fs.existsSync(path.join(tempDir, 'platforms', 'ios', 'www'))).toBe(true);
+            });
+        });
     });
 
     var removing_tests = function(_invocation) {
@@ -212,22 +223,29 @@ describe('platform command', function() {
 
             it('should remove a supported and added platform', function() {
                 var cb = jasmine.createSpy();
-                var cbone = jasmine.createSpy();
 
                 runs(function() {
-                    cordova.platform('add', 'ios', cbone);
-                });
-                waitsFor(function() { return cbone.wasCalled; }, "ios create callback");
-                runs(function() {
-                    cordova.platform('add', 'android', cb);
+                    cordova.platform('add', ['android', 'ios'], cb);
                 });
-                waitsFor(function() { return cb.wasCalled; }, "android create callback");
+                waitsFor(function() { return cb.wasCalled; }, "android+ios platfomr add callback");
                 runs(function() {
                     cordova.platform(_invocation, 'android');
                     expect(cordova.platform('ls').length).toEqual(1);
                     expect(cordova.platform('ls')[0]).toEqual('ios');
                 });
             });
+            it('should be able to remove multiple platforms', function() {
+                var cb = jasmine.createSpy();
+
+                runs(function() {
+                    cordova.platform('add', ['android', 'ios'], cb);
+                });
+                waitsFor(function() { return cb.wasCalled; }, "android+ios platfomr add callback");
+                runs(function() {
+                    cordova.platform(_invocation, ['android','ios']);
+                    expect(cordova.platform('ls').length).toEqual(0);
+                });
+            });
         };
     };
     describe('`rm`', removing_tests('rm'));

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/0d4c2f9e/spec/plugin.spec.js
----------------------------------------------------------------------
diff --git a/spec/plugin.spec.js b/spec/plugin.spec.js
index 3c80671..07101fe 100644
--- a/spec/plugin.spec.js
+++ b/spec/plugin.spec.js
@@ -150,9 +150,16 @@ describe('plugin command', function() {
                     expect(fs.existsSync(path.join(tempDir, 'plugins', 'test'))).toBe(true);
                 });
             });
-            describe('on Android', function() {
-                it('should properly change any imports of ".R" to match the app\'s package name', function() {
-                    
+            it('should be able to handle adding multiple plugins', function() {
+                cordova.platform('add', 'android');
+                var cb = jasmine.createSpy();
+                runs(function() {
+                    cordova.plugin('add', [testPlugin, androidPlugin], cb);
+                });
+                waitsFor(function() { return cb.wasCalled; }, 'test+android plugin add');
+                runs(function() {
+                    expect(fs.existsSync(path.join(tempDir, 'plugins', 'test'))).toBe(true);
+                    expect(fs.existsSync(path.join(tempDir, 'plugins', 'android'))).toBe(true);
                 });
             });
         });
@@ -171,7 +178,7 @@ describe('plugin command', function() {
             describe('failure', function() {
                 it('should throw if your app has no platforms added', function() {
                     expect(function() {
-                        cordova.plugin('rm', testPlugin);
+                        cordova.plugin(_invocation, testPlugin);
                     }).toThrow('You need at least one platform added to your app. Use `cordova platform add <platform>`.');
                 });
                 it('should throw if plugin is not added to project', function() {
@@ -182,7 +189,7 @@ describe('plugin command', function() {
                     waitsFor(function() { return cb.wasCalled; }, 'ios platform add');
                     runs(function() {
                         expect(function() {
-                            cordova.plugin('rm', 'test', function() {});
+                            cordova.plugin(_invocation, 'test', function() {});
                         }).toThrow('Plugin "test" not added to project.');
                     });
                 });
@@ -201,7 +208,7 @@ describe('plugin command', function() {
                     });
                     waitsFor(function() { return pluginCb.wasCalled; }, 'test plugin add');
                     runs(function() {
-                        cordova.plugin('rm', 'test', removeCb);
+                        cordova.plugin(_invocation, 'test', removeCb);
                     });
                     waitsFor(function() { return removeCb.wasCalled; }, 'test plugin remove');
                     runs(function() {
@@ -221,13 +228,30 @@ describe('plugin command', function() {
                     });
                     waitsFor(function() { return pluginCb.wasCalled; }, 'test plugin add');
                     runs(function() {
-                        cordova.plugin('rm', 'test', removeCb);
+                        cordova.plugin(_invocation, 'test', removeCb);
                     });
                     waitsFor(function() { return removeCb.wasCalled; }, 'test plugin remove');
                     runs(function() {
                         expect(fs.existsSync(path.join(tempDir, 'plugins', 'test'))).toBe(false);
                     });
                 });
+                it('should be able to handle removing multiple plugins', function() {
+                    cordova.platform('add', 'android');
+                    var cb = jasmine.createSpy();
+                    var cbtwo = jasmine.createSpy();
+                    runs(function() {
+                        cordova.plugin('add', [testPlugin, androidPlugin], cb);
+                    });
+                    waitsFor(function() { return cb.wasCalled; }, 'test+android plugin add');
+                    runs(function() {
+                        cordova.plugin(_invocation, [testPlugin, androidPlugin], cbtwo);
+                    });
+                    waitsFor(function() { return cbtwo.wasCalled; }, 'test+android plugin rm');
+                    runs(function() {
+                        expect(fs.existsSync(path.join(tempDir, 'plugins', 'test'))).toBe(false);
+                        expect(fs.existsSync(path.join(tempDir, 'plugins', 'android'))).toBe(false);
+                    });
+                });
             });
         };
     };

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/0d4c2f9e/src/build.js
----------------------------------------------------------------------
diff --git a/src/build.js b/src/build.js
index a0396b6..0b78c5d 100644
--- a/src/build.js
+++ b/src/build.js
@@ -56,7 +56,7 @@ module.exports = function build (platforms, callback) {
 
     var hooks = new hooker(projectRoot);
     if (!(hooks.fire('before_build'))) {
-        throw 'before_build hooks exited with non-zero code. Aborting build.';
+        throw 'before_build hooks exited with non-zero code. Aborting.';
     }
 
     var end = n(platforms.length, function() {

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/0d4c2f9e/src/platform.js
----------------------------------------------------------------------
diff --git a/src/platform.js b/src/platform.js
index d4bef45..4a7fa2a 100644
--- a/src/platform.js
+++ b/src/platform.js
@@ -7,9 +7,10 @@ var config_parser = require('./config_parser'),
     blackberry_parser= require('./metadata/blackberry_parser'),
     ios_parser    = require('./metadata/ios_parser'),
     hooker        = require('./hooker'),
+    n             = require('ncallbacks'),
     shell         = require('shelljs');
 
-module.exports = function platform(command, target, callback) {
+module.exports = function platform(command, targets, callback) {
     var projectRoot = cordova_util.isCordova(process.cwd());
 
     if (!projectRoot) {
@@ -19,6 +20,12 @@ module.exports = function platform(command, target, callback) {
     var hooks = new hooker(projectRoot);
 
     if (arguments.length === 0) command = 'ls';
+    if (targets) {
+        if (!(targets instanceof Array)) targets = [targets];
+        var end = n(targets.length, function() {
+            if (callback) callback();
+        });
+    }
 
     var xml = path.join(projectRoot, 'www', 'config.xml');
     var cfg = new config_parser(xml);
@@ -32,60 +39,64 @@ module.exports = function platform(command, target, callback) {
             return fs.readdirSync(path.join(projectRoot, 'platforms'));
             break;
         case 'add':
-            hooks.fire('before_platform_add');
-            var output = path.join(projectRoot, 'platforms', target);
+            targets.forEach(function(target) {
+                hooks.fire('before_platform_add');
+                var output = path.join(projectRoot, 'platforms', target);
 
-            // If the Cordova library for this platform is missing, get it.
-            if (!cordova_util.havePlatformLib(target)) {
-                cordova_util.getPlatformLib(target);
-            }
+                // If the Cordova library for this platform is missing, get it.
+                if (!cordova_util.havePlatformLib(target)) {
+                    cordova_util.getPlatformLib(target);
+                }
 
-            // Create a platform app using the ./bin/create scripts that exist in each repo.
-            // TODO: eventually refactor to allow multiple versions to be created.
-            // Check if output directory already exists.
-            if (fs.existsSync(output)) {
-                throw new Error('Platform "' + target + '" already exists' );
-            }
+                // Create a platform app using the ./bin/create scripts that exist in each repo.
+                // TODO: eventually refactor to allow multiple versions to be created.
+                // Check if output directory already exists.
+                if (fs.existsSync(output)) {
+                    throw new Error('Platform "' + target + '" already exists' );
+                }
 
-            // Run platform's create script
-            var bin = path.join(__dirname, '..', 'lib', cordova_util.underlyingLib(target), 'bin', 'create');
-            var pkg = cfg.packageName().replace(/[^\w.]/g,'_');
-            var name = cfg.name().replace(/\W/g,'_');
-            var command = util.format('"%s" "%s" "%s" "%s"', bin, output, (cordova_util.underlyingLib(target)=='blackberry'?name:pkg), name);
+                // Run platform's create script
+                var bin = path.join(__dirname, '..', 'lib', cordova_util.underlyingLib(target), 'bin', 'create');
+                var pkg = cfg.packageName().replace(/[^\w.]/g,'_');
+                var name = cfg.name().replace(/\W/g,'_');
+                var command = util.format('"%s" "%s" "%s" "%s"', bin, output, (cordova_util.underlyingLib(target)=='blackberry'?name:pkg), name);
 
-            var create = shell.exec(command, {silent:true});
-            if (create.code > 0) {
-                throw new Error('An error occured during creation of ' + target + ' sub-project. ' + create.output);
-            }
+                var create = shell.exec(command, {silent:true});
+                if (create.code > 0) {
+                    throw new Error('An error occured during creation of ' + target + ' sub-project. ' + create.output);
+                }
 
-            switch(cordova_util.underlyingLib(target)) {
-                case 'android':
-                    var android = new android_parser(output);
-                    android.update_project(cfg);
-                    hooks.fire('after_platform_add');
-                    if (callback) callback();
-                    break;
-                case 'ios':
-                    var ios = new ios_parser(output);
-                    ios.update_project(cfg, function() {
-                        hooks.fire('after_platform_add');
-                        if (callback) callback();
-                    });
-                    break;
-                case 'blackberry':
-                    var bb = new blackberry_parser(output);
-                    bb.update_project(cfg, function() {
+                switch(cordova_util.underlyingLib(target)) {
+                    case 'android':
+                        var android = new android_parser(output);
+                        android.update_project(cfg);
                         hooks.fire('after_platform_add');
-                        if (callback) callback();
-                    });
-                    break;
-            }
+                        end();
+                        break;
+                    case 'ios':
+                        var ios = new ios_parser(output);
+                        ios.update_project(cfg, function() {
+                            hooks.fire('after_platform_add');
+                            end();
+                        });
+                        break;
+                    case 'blackberry':
+                        var bb = new blackberry_parser(output);
+                        bb.update_project(cfg, function() {
+                            hooks.fire('after_platform_add');
+                            end();
+                        });
+                        break;
+                }
+            });
             break;
         case 'rm':
         case 'remove':
-            hooks.fire('before_platform_rm');
-            shell.rm('-rf', path.join(projectRoot, 'platforms', target));
-            hooks.fire('after_platform_rm');
+            targets.forEach(function(target) {
+                hooks.fire('before_platform_rm');
+                shell.rm('-rf', path.join(projectRoot, 'platforms', target));
+                hooks.fire('after_platform_rm');
+            });
             break;
         default:
             throw ('Unrecognized command "' + command + '". Use either `add`, `remove`, or `list`.');

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/0d4c2f9e/src/plugin.js
----------------------------------------------------------------------
diff --git a/src/plugin.js b/src/plugin.js
index f4c7d73..692a4eb 100644
--- a/src/plugin.js
+++ b/src/plugin.js
@@ -10,7 +10,7 @@ var cordova_util  = require('./util'),
     plugin_parser = require('./plugin_parser'),
     ls            = fs.readdirSync;
 
-module.exports = function plugin(command, target, callback) {
+module.exports = function plugin(command, targets, callback) {
     var projectRoot = cordova_util.isCordova(process.cwd());
 
     if (!projectRoot) {
@@ -25,15 +25,19 @@ module.exports = function plugin(command, target, callback) {
     // Grab config info for the project
     var xml = path.join(projectWww, 'config.xml');
     var cfg = new config_parser(xml);
-    var platforms = platform('ls');
+    var platforms = ls(path.join(projectRoot, 'platforms'));
 
-    // Massage plugin name / path
-    var pluginPath, plugins, targetName;
+    // Massage plugin name(s) / path(s)
+    var pluginPath, plugins, names = [];
     pluginPath = path.join(projectRoot, 'plugins');
     plugins = ls(pluginPath);
-    if (target) { 
-        targetName = target.substr(target.lastIndexOf('/') + 1);
-        if (targetName[targetName.length-1] == '/') targetName = targetName.substr(0, targetName.length-1);
+    if (targets) { 
+        if (!(targets instanceof Array)) targets = [targets];
+        targets.forEach(function(target) {
+            var targetName = target.substr(target.lastIndexOf('/') + 1);
+            if (targetName[targetName.length-1] == '/') targetName = targetName.substr(0, targetName.length-1);
+            names.push(targetName);
+        });
     }
 
     switch(command) {
@@ -50,115 +54,121 @@ module.exports = function plugin(command, target, callback) {
             if (platforms.length === 0) {
                 throw 'You need at least one platform added to your app. Use `cordova platform add <platform>`.';
             }
-            // Check if we already have the plugin.
-            // TODO edge case: if a new platform is added, then you want
-            // to re-add the plugin to the new platform.
-            if (plugins.indexOf(targetName) > -1) {
-                throw 'Plugin "' + targetName + '" already added to project.';
-            }
-            
-            // Check if the plugin has a plugin.xml in the root of the
-            // specified dir.
-            var pluginContents = ls(target);
-            if (pluginContents.indexOf('plugin.xml') == -1) {
-                throw 'Plugin "' + targetName + '" does not have a plugin.xml in the root. Plugin must support the Cordova Plugin Specification: https://github.com/alunny/cordova-plugin-spec';
-            }
-
-            // Check if there is at least one match between plugin
-            // supported platforms and app platforms
-            var pluginXml = new plugin_parser(path.join(target, 'plugin.xml'));
-            var intersection = pluginXml.platforms.filter(function(e) {
-                if (platforms.indexOf(e) == -1) return false;
-                else return true;
-            });
-            if (intersection.length === 0) {
-                throw 'Plugin "' + targetName + '" does not support any of your application\'s platforms. Plugin platforms: ' + pluginXml.platforms.join(', ') + '; your application\'s platforms: ' + platforms.join(', ');
-            }
-
-            hooks.fire('before_plugin_add');
-
-            var pluginWww = path.join(target, 'www');
-            var wwwContents = ls(pluginWww);
-            var cli = path.join(__dirname, '..', 'node_modules', 'pluginstall', 'cli.js');
-
-            // Iterate over all matchin app-plugin platforms in the project and install the
-            // plugin.
-            intersection.forEach(function(platform) {
-                var cmd = util.format('%s %s "%s" "%s"', cli, platform, path.join(projectRoot, 'platforms', platform), target);
-                var plugin_cli = shell.exec(cmd, {silent:true});
-                if (plugin_cli.code > 0) throw 'An error occured during plugin installation for ' + platform + '. ' + cli.output;
-            });
-            
-            // Add the plugin web assets to the www folder as well
-            // TODO: assumption that web assets go under www folder
-            // inside plugin dir; instead should read plugin.xml
-            wwwContents.forEach(function(asset) {
-                asset = path.resolve(path.join(pluginWww, asset));
-                var info = fs.lstatSync(asset);
-                var name = asset.substr(asset.lastIndexOf('/')+1);
-                var wwwPath = path.join(projectWww, name);
-                if (info.isDirectory()) {
-                    shell.cp('-r', asset, projectWww);
-                } else {
-                    fs.writeFileSync(wwwPath, fs.readFileSync(asset));
+            targets.forEach(function(target, index) {
+                var pluginContents = ls(target);
+                var targetName = names[index];
+                // Check if we already have the plugin.
+                // TODO edge case: if a new platform is added, then you want
+                // to re-add the plugin to the new platform.
+                if (plugins.indexOf(targetName) > -1) {
+                    throw 'Plugin "' + targetName + '" already added to project.';
+                }
+                // Check if the plugin has a plugin.xml in the root of the
+                // specified dir.
+                if (pluginContents.indexOf('plugin.xml') == -1) {
+                    throw 'Plugin "' + targetName + '" does not have a plugin.xml in the root. Plugin must support the Cordova Plugin Specification: https://github.com/alunny/cordova-plugin-spec';
                 }
-            });
-
-            // Finally copy the plugin into the project
-            shell.cp('-r', target, pluginPath);
-
-            hooks.fire('after_plugin_add');
-            if (callback) callback();
-            break;
-        case 'rm':
-        case 'remove':
-            if (platforms.length === 0) {
-                throw 'You need at least one platform added to your app. Use `cordova platform add <platform>`.';
-            }
-            // Check if we have the plugin.
-            if (plugins.indexOf(targetName) > -1) {
-                hooks.fire('before_plugin_rm');
-                var pluginWww = path.join(pluginPath, target, 'www');
-                var wwwContents = ls(pluginWww);
-                var cli = path.join(__dirname, '..', 'node_modules', 'pluginstall', 'cli.js');
 
                 // Check if there is at least one match between plugin
                 // supported platforms and app platforms
-                var pluginXml = new plugin_parser(path.join(pluginPath, target, 'plugin.xml'));
+                var pluginXml = new plugin_parser(path.join(target, 'plugin.xml'));
                 var intersection = pluginXml.platforms.filter(function(e) {
                     if (platforms.indexOf(e) == -1) return false;
                     else return true;
                 });
+                if (intersection.length === 0) {
+                    throw 'Plugin "' + targetName + '" does not support any of your application\'s platforms. Plugin platforms: ' + pluginXml.platforms.join(', ') + '; your application\'s platforms: ' + platforms.join(', ');
+                }
+
+                hooks.fire('before_plugin_add');
 
-                // Iterate over all matchin app-plugin platforms in the project and uninstall the
+                var pluginWww = path.join(target, 'www');
+                var wwwContents = ls(pluginWww);
+                var cli = path.join(__dirname, '..', 'node_modules', 'pluginstall', 'cli.js');
+
+                // Iterate over all matchin app-plugin platforms in the project and install the
                 // plugin.
                 intersection.forEach(function(platform) {
-                    var cmd = util.format('%s -d %s "%s" "%s"', cli, platform, path.join(projectRoot, 'platforms', platform), path.join(pluginPath, target));
+                    var cmd = util.format('%s %s "%s" "%s"', cli, platform, path.join(projectRoot, 'platforms', platform), target);
                     var plugin_cli = shell.exec(cmd, {silent:true});
-                    if (plugin_cli.code > 0) throw 'An error occured during plugin uninstallation for ' + platform + '. ' + cli.output;
+                    if (plugin_cli.code > 0) throw 'An error occured during plugin installation for ' + platform + '. ' + cli.output;
                 });
                 
-                // Remove the plugin web assets to the www folder as well
+                // Add the plugin web assets to the www folder as well
                 // TODO: assumption that web assets go under www folder
                 // inside plugin dir; instead should read plugin.xml
                 wwwContents.forEach(function(asset) {
-                    asset = path.resolve(path.join(projectWww, asset));
+                    asset = path.resolve(path.join(pluginWww, asset));
                     var info = fs.lstatSync(asset);
+                    var name = asset.substr(asset.lastIndexOf('/')+1);
+                    var wwwPath = path.join(projectWww, name);
                     if (info.isDirectory()) {
-                        shell.rm('-rf', asset);
+                        shell.cp('-r', asset, projectWww);
                     } else {
-                        fs.unlinkSync(asset);
+                        fs.writeFileSync(wwwPath, fs.readFileSync(asset));
                     }
                 });
 
-                // Finally remove the plugin dir from plugins/
-                shell.rm('-rf', path.join(pluginPath, target));
+                // Finally copy the plugin into the project
+                shell.cp('-r', target, pluginPath);
 
-                hooks.fire('after_plugin_rm');
-                if (callback) callback();
-            } else {
-                throw 'Plugin "' + targetName + '" not added to project.';
+                hooks.fire('after_plugin_add');
+            });
+            if (callback) callback();
+            break;
+        case 'rm':
+        case 'remove':
+            if (platforms.length === 0) {
+                throw 'You need at least one platform added to your app. Use `cordova platform add <platform>`.';
             }
+            targets.forEach(function(target, index) {
+                var targetName = names[index];
+                // Check if we have the plugin.
+                if (plugins.indexOf(targetName) > -1) {
+                    var targetPath = path.join(pluginPath, targetName);
+                    hooks.fire('before_plugin_rm');
+                    var pluginWww = path.join(targetPath, 'www');
+                    var wwwContents = ls(pluginWww);
+                    var cli = path.join(__dirname, '..', 'node_modules', 'pluginstall', 'cli.js');
+
+                    // Check if there is at least one match between plugin
+                    // supported platforms and app platforms
+                    var pluginXml = new plugin_parser(path.join(targetPath, 'plugin.xml'));
+                    var intersection = pluginXml.platforms.filter(function(e) {
+                        if (platforms.indexOf(e) == -1) return false;
+                        else return true;
+                    });
+
+                    // Iterate over all matchin app-plugin platforms in the project and uninstall the
+                    // plugin.
+                    intersection.forEach(function(platform) {
+                        var cmd = util.format('%s -d %s "%s" "%s"', cli, platform, path.join(projectRoot, 'platforms', platform), targetPath);
+                        var plugin_cli = shell.exec(cmd, {silent:true});
+                        if (plugin_cli.code > 0) throw 'An error occured during plugin uninstallation for ' + platform + '. ' + cli.output;
+                    });
+                    
+                    // Remove the plugin web assets to the www folder as well
+                    // TODO: assumption that web assets go under www folder
+                    // inside plugin dir; instead should read plugin.xml
+                    wwwContents.forEach(function(asset) {
+                        asset = path.resolve(path.join(projectWww, asset));
+                        var info = fs.lstatSync(asset);
+                        if (info.isDirectory()) {
+                            shell.rm('-rf', asset);
+                        } else {
+                            fs.unlinkSync(asset);
+                        }
+                    });
+
+                    // Finally remove the plugin dir from plugins/
+                    shell.rm('-rf', targetPath);
+
+                    hooks.fire('after_plugin_rm');
+                } else {
+                    throw 'Plugin "' + targetName + '" not added to project.';
+                }
+            });
+            if (callback) callback();
             break;
         default:
             throw 'Unrecognized command "' + command + '". Use either `add`, `remove`, or `list`.';