You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cordova.apache.org by sg...@apache.org on 2014/09/26 23:20:05 UTC

[06/13] git commit: CB-6481 Addressed community review notes: Removed commonModules from Context Renamed Hooker and subclasses to HooksRunner and scriptsFinder Moved scriptsRunner code into HooksRunner

CB-6481 Addressed community review notes:
Removed commonModules from Context
Renamed Hooker and subclasses to HooksRunner and scriptsFinder
Moved scriptsRunner code into HooksRunner


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

Branch: refs/heads/master
Commit: 850f4502a9a283c36c8d23a5fd0187d45e6f2820
Parents: 35a350a
Author: daserge <da...@yandex.ru>
Authored: Tue Jul 22 15:14:03 2014 +0400
Committer: daserge <da...@yandex.ru>
Committed: Thu Sep 25 19:04:54 2014 +0400

----------------------------------------------------------------------
 cordova-lib/src/PluginInfo.js                   |   4 +-
 cordova-lib/src/configparser/ConfigParser.js    |   4 +-
 cordova-lib/src/cordova/build.js                |  10 +-
 cordova-lib/src/cordova/compile.js              |   9 +-
 cordova-lib/src/cordova/emulate.js              |   9 +-
 cordova-lib/src/cordova/hooker.js               | 172 --------------
 cordova-lib/src/cordova/lazy_load.js            |   8 +-
 .../src/cordova/metadata/windows_parser.js      |   7 +-
 cordova-lib/src/cordova/metadata/wp8_parser.js  |   7 +-
 cordova-lib/src/cordova/platform.js             |  41 ++--
 cordova-lib/src/cordova/plugin.js               |  33 ++-
 cordova-lib/src/cordova/prepare.js              |   9 +-
 cordova-lib/src/cordova/run.js                  |   9 +-
 cordova-lib/src/cordova/serve.js                |   9 +-
 cordova-lib/src/hooks/Context.js                |   7 +-
 cordova-lib/src/hooks/Hooker.js                 | 101 --------
 cordova-lib/src/hooks/HooksRunner.js            | 238 +++++++++++++++++++
 cordova-lib/src/hooks/ScriptsFinder.js          |   3 +-
 cordova-lib/src/hooks/ScriptsRunner.js          | 161 -------------
 cordova-lib/src/plugman/install.js              |  37 +--
 cordova-lib/src/plugman/uninstall.js            |  46 ++--
 21 files changed, 363 insertions(+), 561 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/850f4502/cordova-lib/src/PluginInfo.js
----------------------------------------------------------------------
diff --git a/cordova-lib/src/PluginInfo.js b/cordova-lib/src/PluginInfo.js
index 98e4fec..47fa293 100644
--- a/cordova-lib/src/PluginInfo.js
+++ b/cordova-lib/src/PluginInfo.js
@@ -206,11 +206,11 @@ function PluginInfo(dirname) {
     // <script type="before_build" src="scripts/beforeBuild.js" />
     self.getHookScripts = getHookScripts;
     function getHookScripts(hook, platforms) {
-        var scriptElements =  self._et.findall('./script');
+        var scriptElements =  self._et.findall('./hook');
 
         if(platforms) {
             platforms.forEach(function (platform) {
-                scriptElements = scriptElements.concat(self._et.findall('./platform[@name="' + platform + '"]/script'));
+                scriptElements = scriptElements.concat(self._et.findall('./platform[@name="' + platform + '"]/hook'));
             });
         }
 

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/850f4502/cordova-lib/src/configparser/ConfigParser.js
----------------------------------------------------------------------
diff --git a/cordova-lib/src/configparser/ConfigParser.js b/cordova-lib/src/configparser/ConfigParser.js
index e02c4e8..600ffdc 100644
--- a/cordova-lib/src/configparser/ConfigParser.js
+++ b/cordova-lib/src/configparser/ConfigParser.js
@@ -237,11 +237,11 @@ ConfigParser.prototype = {
      */
     getHookScripts: function(hook, platforms) {
         var self = this;
-        var scriptElements = self.doc.findall('./script');
+        var scriptElements = self.doc.findall('./hook');
 
         if(platforms) {
             platforms.forEach(function (platform) {
-                scriptElements = scriptElements.concat(self.doc.findall('./platform[@name="' + platform + '"]/script'));
+                scriptElements = scriptElements.concat(self.doc.findall('./platform[@name="' + platform + '"]/hook'));
             });
         }
 

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/850f4502/cordova-lib/src/cordova/build.js
----------------------------------------------------------------------
diff --git a/cordova-lib/src/cordova/build.js b/cordova-lib/src/cordova/build.js
index 1469c6b..8469b8a 100644
--- a/cordova-lib/src/cordova/build.js
+++ b/cordova-lib/src/cordova/build.js
@@ -22,7 +22,7 @@
 */
 
 var cordovaUtil      = require('./util'),
-    Hooker           = require('../hooks/Hooker');
+    HooksRunner           = require('../hooks/HooksRunner');
 
 // Returns a promise.
 module.exports = function build(options) {
@@ -38,16 +38,14 @@ module.exports = function build(options) {
 
     options = cordovaUtil.preProcessOptions(options);
 
-    var hookOptions = { projectRoot: projectRoot, cordova: options };
-
     // fire build hooks
-    var hooker = new Hooker(projectRoot);
-    return hooker.fire('before_build', hookOptions)
+    var hooksRunner = new HooksRunner(projectRoot);
+    return hooksRunner.fire('before_build', options)
     .then(function() {
         return require('./cordova').raw.prepare(options);
     }).then(function() {
         return require('./cordova').raw.compile(options);
     }).then(function() {
-        return hooker.fire('after_build', hookOptions);
+        return hooksRunner.fire('after_build', options);
     });
 };

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/850f4502/cordova-lib/src/cordova/compile.js
----------------------------------------------------------------------
diff --git a/cordova-lib/src/cordova/compile.js b/cordova-lib/src/cordova/compile.js
index 558b0c0..d878601 100644
--- a/cordova-lib/src/cordova/compile.js
+++ b/cordova-lib/src/cordova/compile.js
@@ -23,7 +23,7 @@
 
 var path              = require('path'),
     cordova_util      = require('./util'),
-    hooker            = require('./hooker'),
+    HooksRunner            = require('../hooks/HooksRunner'),
     superspawn        = require('./superspawn');
 
 // Returns a promise.
@@ -31,9 +31,8 @@ module.exports = function compile(options) {
     var projectRoot = cordova_util.cdProjectRoot();
     options = cordova_util.preProcessOptions(options);
 
-    // TODO: Replace with unified Hooker
-    var hooks = new hooker(projectRoot);
-    var ret = hooks.fire('before_compile', options);
+    var hooksRunner = new HooksRunner(projectRoot);
+    var ret = hooksRunner.fire('before_compile', options);
     options.platforms.forEach(function(platform) {
         ret = ret.then(function() {
             var cmd = path.join(projectRoot, 'platforms', platform, 'cordova', 'build');
@@ -41,7 +40,7 @@ module.exports = function compile(options) {
         });
     });
     ret = ret.then(function() {
-        return hooks.fire('after_compile', options);
+        return hooksRunner.fire('after_compile', options);
     });
     return ret;
 };

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/850f4502/cordova-lib/src/cordova/emulate.js
----------------------------------------------------------------------
diff --git a/cordova-lib/src/cordova/emulate.js b/cordova-lib/src/cordova/emulate.js
index 651a434..cc8b5aa 100644
--- a/cordova-lib/src/cordova/emulate.js
+++ b/cordova-lib/src/cordova/emulate.js
@@ -23,7 +23,7 @@
 
 var cordova_util      = require('./util'),
     path              = require('path'),
-    hooker            = require('./hooker'),
+    HooksRunner            = require('../hooks/HooksRunner'),
     superspawn        = require('./superspawn'),
     Q                 = require('q');
 
@@ -32,9 +32,8 @@ module.exports = function emulate(options) {
     var projectRoot = cordova_util.cdProjectRoot();
     options = cordova_util.preProcessOptions(options);
 
-    // TODO: Replace with unified Hooker
-    var hooks = new hooker(projectRoot);
-    return hooks.fire('before_emulate', options)
+    var hooksRunner = new HooksRunner(projectRoot);
+    return hooksRunner.fire('before_emulate', options)
     .then(function() {
         // Run a prepare first!
         return require('./cordova').raw.prepare(options.platforms);
@@ -47,6 +46,6 @@ module.exports = function emulate(options) {
             return superspawn.spawn(cmd, args, {stdio: 'inherit', printCommand: true});
         }));
     }).then(function() {
-        return hooks.fire('after_emulate', options);
+        return hooksRunner.fire('after_emulate', options);
     });
 };

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/850f4502/cordova-lib/src/cordova/hooker.js
----------------------------------------------------------------------
diff --git a/cordova-lib/src/cordova/hooker.js b/cordova-lib/src/cordova/hooker.js
deleted file mode 100644
index 1e6fbe4..0000000
--- a/cordova-lib/src/cordova/hooker.js
+++ /dev/null
@@ -1,172 +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.
-*/
-
-/* jshint node:true, bitwise:true, undef:true, trailing:true, quotmark:true,
-          indent:4, unused:vars, latedef:nofunc
-*/
-
-var util  = require('./util'),
-    fs    = require('fs'),
-    os    = require('os'),
-    events= require('../events'),
-    superspawn = require('./superspawn'),
-    CordovaError = require('../CordovaError'),
-    Q     = require('q'),
-    path  = require('path');
-
-module.exports = function hooker(root) {
-    var r = util.isCordova(root);
-    if (!r) throw new CordovaError('Not a Cordova project ("'+root+'"), can\'t use hooks.');
-    else this.root = r;
-};
-
-// Returns a promise.
-module.exports.fire = global_fire;
-function global_fire(hook, opts) {
-    opts = opts || {};
-    var handlers = events.listeners(hook);
-    return execute_handlers_serially(handlers, opts);
-}
-
-function compareNumbers(a, b) {
-    var intA = parseInt(a);
-    var intB = parseInt(b);
-    if ( isNaN(intA) ) {
-        a = a.toLowerCase();
-        b = b.toLowerCase ? b.toLowerCase() : b;
-        return a.localeCompare(b);
-    }
-    return intA == intB ? 0 : intA > intB ? 1 : -1;
-}
-
-module.exports.prototype = {
-    // Returns a promise.
-    fire:function fire(hook, opts) {
-        var root = this.root;
-        opts = opts || {};
-        opts.root = root;
-
-        function fireHooksInDir(dir) {
-            if (!(fs.existsSync(dir))) {
-                return Q();
-            } else {
-                var scripts = fs.readdirSync(dir).sort(compareNumbers).filter(function(s) {
-                    return s[0] != '.';
-                });
-                return execute_scripts_serially(scripts, root, dir, opts);
-            }
-        }
-        // Fire JS hook for the event
-        // These ones need to "serialize" events, that is, each handler attached to the event needs to finish processing (if it "opted in" to the callback) before the next one will fire.
-        var handlers = events.listeners(hook);
-        return execute_handlers_serially(handlers, opts)
-        .then(function() {
-            return fireHooksInDir(path.join(root, '.cordova', 'hooks', hook));
-        }).then(function() {
-            return fireHooksInDir(path.join(root, 'hooks', hook));
-        });
-    }
-};
-
-function extractSheBangInterpreter(fullpath) {
-    var hookFd = fs.openSync(fullpath, 'r');
-    var fileData, octetsRead, fileChunk;
-    try {
-        // this is a modern cluster size. no need to read less
-        fileData = new Buffer (4096);
-        octetsRead = fs.readSync(hookFd, fileData, 0, 4096, 0);
-        fileChunk = fileData.toString();
-    } finally {
-        fs.closeSync(hookFd);
-    }
-
-    var hookCmd, shMatch;
-    // Filter out /usr/bin/env so that "/usr/bin/env node" works like "node".
-    var shebangMatch = fileChunk.match(/^#!(?:\/usr\/bin\/env )?([^\r\n]+)/m);
-    if (octetsRead == 4096 && !fileChunk.match(/[\r\n]/))
-        events.emit('warn', 'shebang is too long for "' + fullpath + '"');
-    if (shebangMatch)
-        hookCmd = shebangMatch[1];
-    // Likewise, make /usr/bin/bash work like "bash".
-    if (hookCmd)
-        shMatch = hookCmd.match(/bin\/((?:ba)?sh)$/);
-    if (shMatch)
-        hookCmd = shMatch[1];
-    return hookCmd;
-}
-
-// Returns a promise.
-function execute_scripts_serially(scripts, root, dir, opts) {
-    opts = opts || {};
-    var isWindows = os.platform().slice(0, 3) === 'win';
-    if (scripts.length) {
-        var s = scripts.shift();
-        var fullpath = path.join(dir, s);
-        if (fs.statSync(fullpath).isDirectory()) {
-            events.emit('verbose', 'skipped directory "' + fullpath + '" within hook directory');
-            return execute_scripts_serially(scripts, root, dir, opts); // skip directories if they're in there.
-        } else {
-            var command = fullpath;
-            var args = [root];
-            if (os.platform().slice(0, 3) == 'win') {
-                // TODO: Make shebang sniffing a setting (not everyone will want this).
-                var interpreter = extractSheBangInterpreter(fullpath);
-                // we have shebang, so try to run this script using correct interpreter
-                if (interpreter) {
-                    args.unshift(command);
-                    command = interpreter;
-                }
-            }
-
-            var execOpts = {cwd: root, printCommand: opts.verbose, stdio: 'inherit'};
-            execOpts.env = {};
-            execOpts.env.CORDOVA_VERSION = require('../../package').version;
-            execOpts.env.CORDOVA_PLATFORMS = opts.platforms ? opts.platforms.join() : '';
-            execOpts.env.CORDOVA_PLUGINS = opts.plugins?opts.plugins.join():'';
-            execOpts.env.CORDOVA_HOOK = fullpath;
-            execOpts.env.CORDOVA_CMDLINE = process.argv.join(' ');
-
-            return superspawn.spawn(command, args, execOpts)
-            .catch(function(err) {
-                // Don't treat non-executable files as errors. They could be READMEs, or Windows-only scripts.
-                if (!isWindows && err.code == 'EACCES') {
-                    events.emit('verbose', 'skipped non-executable file: ' + fullpath);
-                } else {
-                    throw new CordovaError('Hook failed with error code ' + err.code + ': ' + fullpath);
-                }
-            }).then(function() {
-                return execute_scripts_serially(scripts, root, dir, opts);
-            });
-        }
-    } else {
-        return Q(); // Nothing to do.
-    }
-}
-
-// Returns a promise.
-function execute_handlers_serially(handlers, opts) {
-    if (handlers.length) {
-        // Chain the handlers in series.
-        return handlers.reduce(function(soFar, f) {
-            return soFar.then(function() { return f(opts); });
-        }, Q());
-    } else {
-        return Q(); // Nothing to do.
-    }
-}

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/850f4502/cordova-lib/src/cordova/lazy_load.js
----------------------------------------------------------------------
diff --git a/cordova-lib/src/cordova/lazy_load.js b/cordova-lib/src/cordova/lazy_load.js
index 943adc8..042d356 100644
--- a/cordova-lib/src/cordova/lazy_load.js
+++ b/cordova-lib/src/cordova/lazy_load.js
@@ -33,7 +33,7 @@ var path          = require('path'),
     events        = require('../events'),
     request       = require('request'),
     config        = require('./config'),
-    hooker        = require('./hooker'),
+    HooksRunner        = require('../hooks/HooksRunner'),
     zlib          = require('zlib'),
     tar           = require('tar'),
     URL           = require('url'),
@@ -186,8 +186,8 @@ function custom(platforms, platform) {
         lib_dir = path.join(url, subdir);
         return Q(lib_dir);
     }
-    // TODO: Replace with unified Hooker
-    return hooker.fire('before_library_download', {
+
+    return HooksRunner.fire('before_library_download', {
         platform:platform,
         url:url,
         id:id,
@@ -247,7 +247,7 @@ function custom(platforms, platform) {
                 shell.mkdir('-p', download_dir);
                 shell.mv('-f', path.join(entry, '*'), download_dir);
                 shell.rm('-rf', tmp_dir);
-                d.resolve(hooker.fire('after_library_download', {
+                d.resolve(HooksRunner.fire('after_library_download', {
                     platform:platform,
                     url:url,
                     id:id,

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/850f4502/cordova-lib/src/cordova/metadata/windows_parser.js
----------------------------------------------------------------------
diff --git a/cordova-lib/src/cordova/metadata/windows_parser.js b/cordova-lib/src/cordova/metadata/windows_parser.js
index 3e4a632..a18c19b 100644
--- a/cordova-lib/src/cordova/metadata/windows_parser.js
+++ b/cordova-lib/src/cordova/metadata/windows_parser.js
@@ -30,7 +30,7 @@ var fs            = require('fs'),
     ConfigParser  = require('../../configparser/ConfigParser'),
     CordovaError  = require('../../CordovaError'),
     xml           = require('../../util/xml-helpers'),
-    hooker        = require('../hooker');
+    HooksRunner        = require('../../hooks/HooksRunner');
 
 module.exports = function windows_parser(project) {
     try {
@@ -244,9 +244,8 @@ module.exports.prototype = {
         var that = this;
         var projectRoot = util.isCordova(process.cwd());
 
-        // TODO: Replace with unified Hooker
-        var hooks = new hooker(projectRoot);
-        return hooks.fire('pre_package', { wwwPath:this.www_dir(), platforms: [this.isOldProjectTemplate ? 'windows8' : 'windows'] })
+        var hooksRunner = new HooksRunner(projectRoot);
+        return hooksRunner.fire('pre_package', { wwwPath:this.www_dir(), platforms: [this.isOldProjectTemplate ? 'windows8' : 'windows'] })
         .then(function() {
             // overrides (merges) are handled in update_www()
             that.add_bom();

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/850f4502/cordova-lib/src/cordova/metadata/wp8_parser.js
----------------------------------------------------------------------
diff --git a/cordova-lib/src/cordova/metadata/wp8_parser.js b/cordova-lib/src/cordova/metadata/wp8_parser.js
index 9798a6e..0fe7c52 100644
--- a/cordova-lib/src/cordova/metadata/wp8_parser.js
+++ b/cordova-lib/src/cordova/metadata/wp8_parser.js
@@ -30,7 +30,7 @@ var fs            = require('fs'),
     ConfigParser  = require('../../configparser/ConfigParser'),
     CordovaError  = require('../../CordovaError'),
     xml           = require('../../util/xml-helpers'),
-    hooker        = require('../hooker');
+    HooksRunner        = require('../../hooks/HooksRunner');
 
 module.exports = function wp8_parser(project) {
     try {
@@ -209,9 +209,8 @@ module.exports.prototype = {
         var that = this;
         var projectRoot = util.isCordova(process.cwd());
 
-        // TODO: Replace with unified Hooker
-        var hooks = new hooker(projectRoot);
-        return hooks.fire('pre_package', { wwwPath:this.www_dir(), platforms: ['wp8']  })
+        var hooksRunner = new HooksRunner(projectRoot);
+        return hooksRunner.fire('pre_package', { wwwPath:this.www_dir(), platforms: ['wp8'] })
         .then(function() {
             util.deleteSvnFolders(that.www_dir());
         });

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/850f4502/cordova-lib/src/cordova/platform.js
----------------------------------------------------------------------
diff --git a/cordova-lib/src/cordova/platform.js b/cordova-lib/src/cordova/platform.js
index 7becd9e..5875fd9 100644
--- a/cordova-lib/src/cordova/platform.js
+++ b/cordova-lib/src/cordova/platform.js
@@ -30,7 +30,7 @@ var config            = require('./config'),
     fs                = require('fs'),
     os                = require('os'),
     path              = require('path'),
-    hooker            = require('./hooker'),
+    HooksRunner       = require('../hooks/HooksRunner'),
     events            = require('../events'),
     lazy_load         = require('./lazy_load'),
     CordovaError      = require('../CordovaError'),
@@ -46,7 +46,7 @@ for (var p in platforms) {
     module.exports[p] = platforms[p];
 }
 
-function add(hooks, projectRoot, targets, opts) {
+function add(hooksRunner, projectRoot, targets, opts) {
     var msg;
     if ( !targets || !targets.length ) {
         msg = 'No platform specified. Please specify a platform to add. ' +
@@ -73,7 +73,7 @@ function add(hooks, projectRoot, targets, opts) {
         shell.mkdir('-p', platformsDir);
     }
 
-    return hooks.fire('before_platform_add', opts)
+    return hooksRunner.fire('before_platform_add', opts)
     .then(function() {
         return promiseutil.Q_chainmap(targets, function(t) {
             // For each platform, download it and call its "create" script.
@@ -130,15 +130,15 @@ function add(hooks, projectRoot, targets, opts) {
         });
     })
     .then(function() {
-        return hooks.fire('after_platform_add', opts);
+        return hooksRunner.fire('after_platform_add', opts);
     });
 }
 
-function remove(hooks, projectRoot, targets, opts) {
+function remove(hooksRunner, projectRoot, targets, opts) {
     if (!targets || !targets.length) {
         return Q.reject(new CordovaError('No platform[s] specified. Please specify platform[s] to remove. See `'+cordova_util.binname+' platform list`.'));
     }
-    return hooks.fire('before_platform_rm', opts)
+    return hooksRunner.fire('before_platform_rm', opts)
     .then(function() {
         targets.forEach(function(target) {
             shell.rm('-rf', path.join(projectRoot, 'platforms', target));
@@ -146,11 +146,11 @@ function remove(hooks, projectRoot, targets, opts) {
             if (fs.existsSync(plugins_json)) shell.rm(plugins_json);
         });
     }).then(function() {
-        return hooks.fire('after_platform_rm', opts);
+        return hooksRunner.fire('after_platform_rm', opts);
     });
 }
 
-function update(hooks, projectRoot, targets, opts) {
+function update(hooksRunner, projectRoot, targets, opts) {
     // Shell out to the update script provided by the named platform.
     var msg;
     if ( !targets || !targets.length ) {
@@ -178,7 +178,7 @@ function update(hooks, projectRoot, targets, opts) {
     }
 
     // First, lazy_load the latest version.
-    return hooks.fire('before_platform_update', opts)
+    return hooksRunner.fire('before_platform_update', opts)
     .then(function() {
         return lazy_load.based_on_config(projectRoot, plat, opts);
     })
@@ -194,7 +194,7 @@ function update(hooks, projectRoot, targets, opts) {
     });
 }
 
-function check(hooks, projectRoot) {
+function check(hooksRunner, projectRoot) {
     var platformsText = [],
         platforms_on_fs = cordova_util.listPlatforms(projectRoot),
         scratch = path.join(os.tmpdir(), 'cordova-platform-check-' + Date.now()),
@@ -203,8 +203,7 @@ function check(hooks, projectRoot) {
     var result = Q.defer();
     cordova.raw.create(scratch)
     .then(function () {
-        // TODO: Replace with unified Hooker
-        var h = new hooker(scratch);
+        var h = new hooksRunner(scratch);
         // Acquire the version number of each platform we have installed, and output that too.
         Q.all(platforms_on_fs.map(function(p) {
             var d = Q.defer(),
@@ -287,9 +286,9 @@ function check(hooks, projectRoot) {
     return result.promise;
 }
 
-function list(hooks, projectRoot) {
+function list(hooksRunner, projectRoot) {
     var platforms_on_fs = cordova_util.listPlatforms(projectRoot);
-    return hooks.fire('before_platform_ls')
+    return hooksRunner.fire('before_platform_ls')
     .then(function() {
         // Acquire the version number of each platform we have installed, and output that too.
         return Q.all(platforms_on_fs.map(function(p) {
@@ -312,7 +311,7 @@ function list(hooks, projectRoot) {
 
         events.emit('results', results);
     }).then(function() {
-        return hooks.fire('after_platform_ls');
+        return hooksRunner.fire('after_platform_ls');
     });
 }
 
@@ -321,7 +320,7 @@ module.exports = platform;
 function platform(command, targets, opts) {
     var projectRoot = cordova_util.cdProjectRoot();
     var msg;
-    var hooks = new hooker(projectRoot);
+    var hooksRunner = new HooksRunner(projectRoot);
 
     if (arguments.length === 0) command = 'ls';
 
@@ -367,17 +366,17 @@ function platform(command, targets, opts) {
             if (idxWindows8 >=0) {
                 targets[idxWindows8] = 'windows';
             }
-            return add(hooks, projectRoot, targets, opts);
+            return add(hooksRunner, projectRoot, targets, opts);
         case 'rm':
         case 'remove':
-            return remove(hooks, projectRoot, targets, opts);
+            return remove(hooksRunner, projectRoot, targets, opts);
         case 'update':
         case 'up':
-            return update(hooks, projectRoot, targets, opts);
+            return update(hooksRunner, projectRoot, targets, opts);
         case 'check':
-            return check(hooks, projectRoot);
+            return check(hooksRunner, projectRoot);
         default:
-            return list(hooks, projectRoot);
+            return list(hooksRunner, projectRoot);
     }
 }
 

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/850f4502/cordova-lib/src/cordova/plugin.js
----------------------------------------------------------------------
diff --git a/cordova-lib/src/cordova/plugin.js b/cordova-lib/src/cordova/plugin.js
index f608a38..9d6b8ab 100644
--- a/cordova-lib/src/cordova/plugin.js
+++ b/cordova-lib/src/cordova/plugin.js
@@ -24,7 +24,7 @@
 var cordova_util  = require('./util'),
     path          = require('path'),
     semver        = require('semver'),
-    hooker        = require('./hooker'),
+    HooksRunner        = require('../hooks/HooksRunner'),
     config        = require('./config'),
     Q             = require('q'),
     CordovaError  = require('../CordovaError'),
@@ -59,8 +59,10 @@ module.exports = function plugin(command, targets, opts) {
     opts.options = opts.options || [];
     opts.plugins = [];
 
-    // TODO: Replace with unified Hooker
-    var hooks = new hooker(projectRoot);
+    // TODO: Otherwise HooksRunner will be Object instead of function when run from tests - investigate why
+    var HooksRunner = require('../hooks/HooksRunner');
+    var hooksRunner = new HooksRunner(projectRoot);
+
     var platformList = cordova_util.listPlatforms(projectRoot);
 
     // Massage plugin name(s) / path(s)
@@ -105,7 +107,8 @@ module.exports = function plugin(command, targets, opts) {
                 searchPath = undefined;
             }
 
-            return hooks.fire('before_plugin_add', opts)
+            opts.cordova = { plugins: cordova_util.findPlugins(path.join(projectRoot, 'plugins')) };
+            return hooksRunner.fire('before_plugin_add', opts)
             .then(function() {
                 return opts.plugins.reduce(function(soFar, target) {
                     var pluginsDir = path.join(projectRoot, 'plugins');
@@ -153,14 +156,17 @@ module.exports = function plugin(command, targets, opts) {
                     });
                 }, Q()); // end Q.all
             }).then(function() {
-                return hooks.fire('after_plugin_add', opts);
+                opts.cordova = { plugins: cordova_util.findPlugins(path.join(projectRoot, 'plugins')) };
+                return hooksRunner.fire('after_plugin_add', opts);
             });
         case 'rm':
         case 'remove':
             if (!targets || !targets.length) {
                 return Q.reject(new CordovaError('No plugin specified. Please specify a plugin to remove. See `'+cordova_util.binname+' plugin list`.'));
             }
-            return hooks.fire('before_plugin_rm', opts)
+
+            opts.cordova = { plugins: cordova_util.findPlugins(path.join(projectRoot, 'plugins')) };
+            return hooksRunner.fire('before_plugin_rm', opts)
             .then(function() {
                 return opts.plugins.reduce(function(soFar, target) {
                     // Check if we have the plugin.
@@ -194,10 +200,11 @@ module.exports = function plugin(command, targets, opts) {
                     });
                 }, Q());
             }).then(function() {
-                return hooks.fire('after_plugin_rm', opts);
+                opts.cordova = { plugins: cordova_util.findPlugins(path.join(projectRoot, 'plugins')) };
+                return hooksRunner.fire('after_plugin_rm', opts);
             });
         case 'search':
-            return hooks.fire('before_plugin_search')
+            return hooksRunner.fire('before_plugin_search')
             .then(function() {
                 var plugman = require('../plugman/plugman');
                 return plugman.raw.search(opts.plugins);
@@ -206,16 +213,16 @@ module.exports = function plugin(command, targets, opts) {
                     events.emit('results', plugins[plugin].name, '-', plugins[plugin].description || 'no description provided');
                 }
             }).then(function() {
-                return hooks.fire('after_plugin_search');
+                return hooksRunner.fire('after_plugin_search');
             });
         default:
-            return list(projectRoot, hooks);
+            return list(projectRoot, hooksRunner);
     }
 };
 
-function list(projectRoot, hooks) {
+function list(projectRoot, hooksRunner) {
     var pluginsList = [];
-    return hooks.fire('before_plugin_ls')
+    return hooksRunner.fire('before_plugin_ls')
     .then(function() {
         var pluginsDir = path.join(projectRoot, 'plugins');
         return PluginInfo.loadPluginsDir(pluginsDir);
@@ -258,7 +265,7 @@ function list(projectRoot, hooks) {
         events.emit('results', lines.join('\n'));
     })
     .then(function() {
-        return hooks.fire('after_plugin_ls');
+        return hooksRunner.fire('after_plugin_ls');
     })
     .then(function() {
         return pluginsList;

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/850f4502/cordova-lib/src/cordova/prepare.js
----------------------------------------------------------------------
diff --git a/cordova-lib/src/cordova/prepare.js b/cordova-lib/src/cordova/prepare.js
index 1906d78..7cc96cb 100644
--- a/cordova-lib/src/cordova/prepare.js
+++ b/cordova-lib/src/cordova/prepare.js
@@ -28,7 +28,7 @@ var cordova_util      = require('./util'),
     fs                = require('fs'),
     shell             = require('shelljs'),
     et                = require('elementtree'),
-    hooker            = require('./hooker'),
+    HooksRunner            = require('../hooks/HooksRunner'),
     events            = require('../events'),
     Q                 = require('q'),
     plugman           = require('../plugman/plugman');
@@ -56,9 +56,8 @@ function prepare(options) {
     });
     options.paths = paths;
 
-    // TODO: Replace with unified Hooker
-    var hooks = new hooker(projectRoot);
-    return hooks.fire('before_prepare', options)
+    var hooksRunner = new HooksRunner(projectRoot);
+    return hooksRunner.fire('before_prepare', options)
     .then(function() {
 
 
@@ -122,7 +121,7 @@ function prepare(options) {
 
             return parser.update_project(cfg);
         })).then(function() {
-            return hooks.fire('after_prepare', options);
+            return hooksRunner.fire('after_prepare', options);
         });
     });
 }

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/850f4502/cordova-lib/src/cordova/run.js
----------------------------------------------------------------------
diff --git a/cordova-lib/src/cordova/run.js b/cordova-lib/src/cordova/run.js
index abde56f..cb361fc 100644
--- a/cordova-lib/src/cordova/run.js
+++ b/cordova-lib/src/cordova/run.js
@@ -23,7 +23,7 @@
 
 var cordova_util      = require('./util'),
     path              = require('path'),
-    hooker            = require('./hooker'),
+    HooksRunner            = require('../hooks/HooksRunner'),
     superspawn        = require('./superspawn'),
     Q                 = require('q');
 
@@ -32,9 +32,8 @@ module.exports = function run(options) {
     var projectRoot = cordova_util.cdProjectRoot();
     options = cordova_util.preProcessOptions(options);
 
-    // TODO: Replace with unified Hooker
-    var hooks = new hooker(projectRoot);
-    return hooks.fire('before_run', options)
+    var hooksRunner = new HooksRunner(projectRoot);
+    return hooksRunner.fire('before_run', options)
     .then(function() {
         // Run a prepare first, then shell out to run
         return require('./cordova').raw.prepare(options);
@@ -45,6 +44,6 @@ module.exports = function run(options) {
             return superspawn.spawn(cmd, options.options, { printCommand: true, stdio: 'inherit' });
         }));
     }).then(function() {
-        return hooks.fire('after_run', options);
+        return hooksRunner.fire('after_run', options);
     });
 };

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/850f4502/cordova-lib/src/cordova/serve.js
----------------------------------------------------------------------
diff --git a/cordova-lib/src/cordova/serve.js b/cordova-lib/src/cordova/serve.js
index 2d88d7b..30ae0b3 100644
--- a/cordova-lib/src/cordova/serve.js
+++ b/cordova-lib/src/cordova/serve.js
@@ -27,7 +27,7 @@ var cordova_util = require('./util'),
     shell = require('shelljs'),
     platforms     = require('./platforms'),
     ConfigParser = require('../configparser/ConfigParser'),
-    hooker        = require('./hooker'),
+    HooksRunner        = require('../hooks/HooksRunner'),
     Q = require('q'),
     fs = require('fs'),
     http = require('http'),
@@ -247,15 +247,14 @@ module.exports = function server(port) {
     var projectRoot = cordova_util.cdProjectRoot();
     port = +port || 8000;
 
-    // TODO: Replace with unified Hooker
-    var hooks = new hooker(projectRoot);
-    hooks.fire('before_serve')
+    var hooksRunner = new HooksRunner(projectRoot);
+    hooksRunner.fire('before_serve')
     .then(function() {
         // Run a prepare first!
         return require('./cordova').raw.prepare([]);
     }).then(function() {
         var server = launchServer(projectRoot, port);
-        hooks.fire('after_serve').then(function () {
+        hooksRunner.fire('after_serve').then(function () {
             d.resolve(server);
         });
     });

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/850f4502/cordova-lib/src/hooks/Context.js
----------------------------------------------------------------------
diff --git a/cordova-lib/src/hooks/Context.js b/cordova-lib/src/hooks/Context.js
index 936c9c1..b299597 100644
--- a/cordova-lib/src/hooks/Context.js
+++ b/cordova-lib/src/hooks/Context.js
@@ -33,12 +33,7 @@ function Context(hook, opts) {
     this.hook = hook;
     this.opts = opts;
     this.cmdLine =  process.argv.join(' ');
-    this.commonModules = {
-        Q: Q, fs: fs, path: path, os: os,
-        events: events, plugin: require('../cordova/plugin'),
-        util: require('util'),
-        cordovaUtil: require('../cordova/util')
-    };
+    this.cordova = require('../cordova/cordova');
 }
 
 /**

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/850f4502/cordova-lib/src/hooks/Hooker.js
----------------------------------------------------------------------
diff --git a/cordova-lib/src/hooks/Hooker.js b/cordova-lib/src/hooks/Hooker.js
deleted file mode 100644
index 7d50e76..0000000
--- a/cordova-lib/src/hooks/Hooker.js
+++ /dev/null
@@ -1,101 +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 util  = require('../cordova/util'),
-    events = require('../events'),
-    Q = require('q'),
-    plugin  = require('../cordova/plugin'),
-    ScriptsFinder = require('./ScriptsFinder'),
-    ScriptsRunner = require('./ScriptsRunner'),
-    Context = require('./Context');
-
-/**
- * Tries to create a hooker for passed project root.
- * @constructor
- */
-function Hooker(projectRoot) {
-    if (!util.isCordova(projectRoot)) {
-        throw new Error('Not a Cordova project ("' + projectRoot + '"), can\'t use hooks.');
-    }
-}
-
-/**
- * Fires all event handlers and scripts for a passed hook type.
- * Returns a promise.
- */
-Hooker.prototype.fire = function fire(hook, opts) {
-    // args check
-    if (!hook) {
-        throw new Error('hook type is not specified');
-    }
-    // execute hook event listeners first
-    return this.prepareOptions(opts).then(function(){
-        var handlers = events.listeners(hook);
-        return executeHandlersSerially(handlers, opts);
-    // then execute hook script files
-    }).then(function() {
-        var scripts = ScriptsFinder.getHookScripts(hook, opts);
-        var context = new Context(hook, opts);
-        return ScriptsRunner.runScriptsSerially(scripts, context);
-    });
-};
-
-/**
- * Set all unset options.
- * Returns a promise.
- */
-Hooker.prototype.prepareOptions = function(opts) {
-    return setPluginsProperty(opts).then(function() {
-        setCordovaVersionProperty(opts);
-    });
-};
-
-/**
- * Sets hook options cordova.plugins list if it was not set.
- * Returns a promise.
- */
-function setPluginsProperty(opts) {
-    if(!opts.cordova.plugins) {
-        return plugin().then(function(plugins) {
-            opts.cordova.plugins = plugins;
-            return Q();
-        });
-    }
-    return Q();
-}
-
-/**
- * Sets hook options cordova.version if it was not set.
- */
-function setCordovaVersionProperty(opts) {
-    opts.cordova.version = opts.cordova.version || require('../../package').version;
-}
-
-// Returns a promise.
-function executeHandlersSerially(handlers, opts) {
-    if (handlers.length) {
-        // Chain the handlers in series.
-        return handlers.reduce(function(soFar, f) {
-            return soFar.then(function() { return f(opts); });
-        }, Q());
-    } else {
-        return Q(); // Nothing to do.
-    }
-}
-
-module.exports = Hooker;
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/850f4502/cordova-lib/src/hooks/HooksRunner.js
----------------------------------------------------------------------
diff --git a/cordova-lib/src/hooks/HooksRunner.js b/cordova-lib/src/hooks/HooksRunner.js
new file mode 100644
index 0000000..0f11da0
--- /dev/null
+++ b/cordova-lib/src/hooks/HooksRunner.js
@@ -0,0 +1,238 @@
+/**
+ 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 cordovaUtil  = require('../cordova/util'),
+    events = require('../events'),
+    Q = require('q'),
+    scriptsFinder = require('./scriptsFinder'),
+    Context = require('./Context'),
+    CordovaError = require('../CordovaError'),
+    path = require('path'),
+    fs = require('fs'),
+    os = require('os'),
+    superspawn = require('../cordova/superspawn');
+
+var isWindows = os.platform().slice(0, 3) === 'win';
+
+/**
+ * Tries to create a HooksRunner for passed project root.
+ * @constructor
+ */
+function HooksRunner(projectRoot) {
+    var root = cordovaUtil.isCordova(projectRoot);
+    if (!root) throw new CordovaError('Not a Cordova project ("' + projectRoot + '"), can\'t use hooks.');
+    else this.projectRoot = root;
+}
+
+/**
+ * Fires all event handlers and scripts for a passed hook type.
+ * Returns a promise.
+ */
+HooksRunner.prototype.fire = function fire(hook, opts) {
+    // args check
+    if (!hook) {
+        throw new Error('hook type is not specified');
+    }
+    opts = this.prepareOptions(opts);
+
+    // execute hook event listeners first
+    return executeEventHandlersSerially(hook, opts).then(function() {
+        // then execute hook script files
+        var scripts = scriptsFinder.getHookScripts(hook, opts);
+        var context = new Context(hook, opts);
+        return runScriptsSerially(scripts, context);
+    });
+};
+
+/**
+ * Refines passed options so that all required parameters are set.
+ * Returns a promise.
+ */
+HooksRunner.prototype.prepareOptions = function(opts) {
+    opts = opts || {};
+    opts.projectRoot = this.projectRoot;
+    opts.cordova = opts.cordova || {};
+    opts.cordova.platforms = opts.cordova.platforms || opts.platforms || cordovaUtil.listPlatforms(opts.projectRoot);
+    opts.cordova.plugins = opts.cordova.plugins || opts.plugins || cordovaUtil.findPlugins(path.join(opts.projectRoot, 'plugins'));
+    opts.cordova.version = opts.cordova.version || require('../../package').version;
+
+    return opts;
+};
+
+module.exports = HooksRunner;
+
+/**
+ * Executes hook event handlers serially. Doesn't require a HooksRunner to be constructed.
+ * Returns a promise.
+ */
+module.exports.fire = globalFire;
+function globalFire(hook, opts) {
+    opts = opts || {};
+    return executeEventHandlersSerially(hook, opts);
+}
+
+// Returns a promise.
+function executeEventHandlersSerially(hook, opts) {
+    var handlers = events.listeners(hook);
+    if (handlers.length) {
+        // Chain the handlers in series.
+        return handlers.reduce(function(soFar, f) {
+            return soFar.then(function() { return f(opts); });
+        }, Q());
+    } else {
+        return Q(); // Nothing to do.
+    }
+}
+
+/**
+ * Serially fires scripts either via Q(require(pathToScript)(context)) or via child_process.spawn.
+ * Returns promise.
+ */
+function runScriptsSerially (scripts, context) {
+    var deferral = new Q.defer();
+
+    function executePendingScript() {
+        try {
+            if (scripts.length === 0) {
+                deferral.resolve();
+                return;
+            }
+            var nextScript = scripts[0];
+            scripts.shift();
+
+            runScript(nextScript, context).then(executePendingScript, function(err){
+                deferral.reject(err);
+            });
+        } catch (ex) {
+            deferral.reject(ex);
+        }
+    }
+    executePendingScript();
+    return deferral.promise;
+};
+
+/**
+ * Async runs single script file.
+ */
+function runScript(script, context) {
+    if (typeof script.useModuleLoader == 'undefined') {
+        // if it is not explicitly defined whether we should use modeule loader or not
+        // we assume we should use module loader for .js files
+        script.useModuleLoader = path.extname(script.path).toLowerCase() == '.js';
+    }
+    if(script.useModuleLoader) {
+        return runScriptViaModuleLoader(script, context);
+    } else {
+        return runScriptViaChildProcessSpawn(script, context);
+    }
+}
+
+/**
+ * Runs script using require.
+ * Returns a promise. */
+function runScriptViaModuleLoader(script, context) {
+    if(!fs.existsSync(script.fullPath)) {
+        events.emit('warn', "Script file does't exist and will be skipped: " + script.fullPath);
+        return Q();
+    }
+    var scriptFn = require(script.fullPath);
+    context.scriptLocation = script.fullPath;
+    context.opts.plugin = script.plugin;
+
+    // We can't run script if it is a plain Node script - it will run its commands when we require it.
+    // This is not a desired case as we want to pass context, but added for compatibility.
+    if (scriptFn instanceof Function) {
+        // If hook is async it can return promise instance and we will handle it.
+        return Q(scriptFn(context));
+    } else {
+        return Q();
+    }
+}
+
+/**
+ * Runs script using child_process spawn method.
+ * Returns a promise. */
+function runScriptViaChildProcessSpawn(script, context) {
+    var opts = context.opts;
+    var command = script.fullPath;
+    var args = [opts.projectRoot];
+
+    if (fs.statSync(script.fullPath).isDirectory()) {
+        events.emit('verbose', 'skipped directory "' + script.fullPath + '" within hook directory');
+        return Q();
+    }
+
+    if (isWindows) {
+        // TODO: Make shebang sniffing a setting (not everyone will want this).
+        var interpreter = extractSheBangInterpreter(script.fullPath);
+        // we have shebang, so try to run this script using correct interpreter
+        if (interpreter) {
+            args.unshift(command);
+            command = interpreter;
+        }
+    }
+
+    var execOpts = {cwd: opts.projectRoot, printCommand: true, stdio: 'inherit'};
+    execOpts.env = {};
+    execOpts.env.CORDOVA_VERSION = require('../../package').version;
+    execOpts.env.CORDOVA_PLATFORMS = opts.platforms ? opts.platforms.join() : '';
+    execOpts.env.CORDOVA_PLUGINS = opts.plugins ? opts.plugins.join() : '';
+    execOpts.env.CORDOVA_HOOK = script.fullPath;
+    execOpts.env.CORDOVA_CMDLINE = process.argv.join(' ');
+
+    return superspawn.spawn(command, args, execOpts)
+        .catch(function(err) {
+            // Don't treat non-executable files as errors. They could be READMEs, or Windows-only scripts.
+            if (!isWindows && err.code == 'EACCES') {
+                events.emit('verbose', 'skipped non-executable file: ' + script.fullPath);
+            } else {
+                throw new Error('Hook failed with error code ' + err.code + ': ' + script.fullPath);
+            }
+        });
+}
+
+/**
+ * Extracts shebang interpreter from script' source. */
+function extractSheBangInterpreter(fullpath) {
+    var fileChunk;
+    var octetsRead;
+    var fileData;
+    var hookFd = fs.openSync(fullpath, "r");
+    try {
+        // this is a modern cluster size. no need to read less
+        fileData = new Buffer(4096);
+        octetsRead = fs.readSync(hookFd, fileData, 0, 4096, 0);
+        fileChunk = fileData.toString();
+    } finally {
+        fs.closeSync(hookFd);
+    }
+
+    var hookCmd, shMatch;
+    // Filter out /usr/bin/env so that "/usr/bin/env node" works like "node".
+    var shebangMatch = fileChunk.match(/^#!(?:\/usr\/bin\/env )?([^\r\n]+)/m);
+    if (octetsRead == 4096 && !fileChunk.match(/[\r\n]/))
+        events.emit('warn', 'shebang is too long for "' + fullpath + '"');
+    if (shebangMatch)
+        hookCmd = shebangMatch[1];
+    // Likewise, make /usr/bin/bash work like "bash".
+    if (hookCmd)
+        shMatch = hookCmd.match(/bin\/((?:ba)?sh)$/);
+    if (shMatch)
+        hookCmd = shMatch[1];
+    return hookCmd;
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/850f4502/cordova-lib/src/hooks/ScriptsFinder.js
----------------------------------------------------------------------
diff --git a/cordova-lib/src/hooks/ScriptsFinder.js b/cordova-lib/src/hooks/ScriptsFinder.js
index f9659de..3345af1 100644
--- a/cordova-lib/src/hooks/ScriptsFinder.js
+++ b/cordova-lib/src/hooks/ScriptsFinder.js
@@ -24,8 +24,7 @@ var path = require('path'),
     Q = require('q'),
     plugin  = require('../cordova/plugin'),
     PluginInfo = require('../PluginInfo'),
-    ConfigParser = require('../configparser/ConfigParser'),
-    Context = require('./Context');
+    ConfigParser = require('../configparser/ConfigParser');
 
 /**
  * Implements logic to retrieve hook script files defined in special folders and configuration

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/850f4502/cordova-lib/src/hooks/ScriptsRunner.js
----------------------------------------------------------------------
diff --git a/cordova-lib/src/hooks/ScriptsRunner.js b/cordova-lib/src/hooks/ScriptsRunner.js
deleted file mode 100644
index 918b56d..0000000
--- a/cordova-lib/src/hooks/ScriptsRunner.js
+++ /dev/null
@@ -1,161 +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 Q = require('q'),
-    fs = require('fs'),
-    os = require('os'),
-    path = require('path'),
-    superspawn = require('../cordova/superspawn'),
-    Context = require('./Context');
-
-var isWindows = os.platform().slice(0, 3) === 'win';
-
-module.exports = {
-    /**
-     * Serially fires scripts either via Q(require(pathToScript)(context)) or via child_process.spawn.
-     * Returns promise.
-     */
-    runScriptsSerially: function(scripts, context) {
-        var deferral = new Q.defer();
-
-        function executePendingScript() {
-            try {
-                if (scripts.length === 0) {
-                    deferral.resolve();
-                    return;
-                }
-                var nextScript = scripts[0];
-                scripts.shift();
-
-                runScript(nextScript, context).then(executePendingScript, function(err){
-                    deferral.reject(err);
-                });
-            } catch (ex) {
-                deferral.reject(ex);
-            }
-        }
-        executePendingScript();
-        return deferral.promise;
-    }
-};
-
-/**
- * Async runs single script file.
- */
-function runScript(script, context) {
-    if (typeof script.useModuleLoader == 'undefined') {
-        // if it is not explicitly defined whether we should use modeule loader or not
-        // we assume we should use module loader for .js files
-        script.useModuleLoader = path.extname(script.path).toLowerCase() == '.js';
-    }
-    if(script.useModuleLoader) {
-        return runScriptViaModuleLoader(script, context);
-    } else {
-        return runScriptViaChildProcessSpawn(script, context);
-    }
-}
-
-/**
- * Runs script using require.
- * Returns a promise. */
-function runScriptViaModuleLoader(script, context) {
-    if(!fs.existsSync(script.fullPath)) {
-        events.emit('warn', "Script file does't exist and will be skipped: " + script.fullPath);
-        return Q();
-    }
-    var scriptFn = require(script.fullPath);
-    context.scriptLocation = script.fullPath;
-    context.opts.plugin = script.plugin;
-
-    // We can't run script if it is a plain Node script - it will run its commands when we require it.
-    // This is not a desired case as we want to pass context, but added for compatibility.
-    if (scriptFn instanceof Function) {
-        // If hook is async it can return promise instance and we will handle it.
-        return Q(scriptFn(context));
-    } else {
-        return Q();
-    }
-}
-
-/**
- * Runs script using child_process spawn method.
- * Returns a promise. */
-function runScriptViaChildProcessSpawn(script, context) {
-    var opts = context.opts;
-    var command = script.fullPath;
-    var args = [opts.projectRoot];
-    if (isWindows) {
-        // TODO: Make shebang sniffing a setting (not everyone will want this).
-        var interpreter = extractSheBangInterpreter(script.fullPath);
-        // we have shebang, so try to run this script using correct interpreter
-        if (interpreter) {
-            args.unshift(command);
-            command = interpreter;
-        }
-    }
-
-    var execOpts = {cwd: opts.projectRoot, printCommand: true, stdio: 'inherit'};
-    execOpts.env = {};
-    execOpts.env.CORDOVA_VERSION = require('../../package').version;
-    execOpts.env.CORDOVA_PLATFORMS = opts.cordova.platforms ? opts.cordova.platforms.join() : '';
-    execOpts.env.CORDOVA_PLUGINS = opts.cordova.plugins ? opts.cordova.plugins.join() : '';
-    execOpts.env.CORDOVA_HOOK = script.fullPath;
-    execOpts.env.CORDOVA_CMDLINE = process.argv.join(' ');
-
-    return superspawn.spawn(command, args, execOpts)
-        .catch(function(err) {
-            // Don't treat non-executable files as errors. They could be READMEs, or Windows-only scripts.
-            if (!isWindows && err.code == 'EACCES') {
-                events.emit('verbose', 'skipped non-executable file: ' + script.fullPath);
-            } else {
-                throw new Error('Hook failed with error code ' + err.code + ': ' + script.fullPath);
-            }
-        });
-}
-
-/**
- * Extracts shebang interpreter from script' source. */
-function extractSheBangInterpreter(fullpath) {
-    var fileChunk;
-    var octetsRead;
-    var fileData;
-    var hookFd = fs.openSync(fullpath, "r");
-    try {
-        // this is a modern cluster size. no need to read less
-        fileData = new Buffer(4096);
-        octetsRead = fs.readSync(hookFd, fileData, 0, 4096, 0);
-        fileChunk = fileData.toString();
-    } finally {
-        fs.closeSync(hookFd);
-    }
-
-    var hookCmd, shMatch;
-    // Filter out /usr/bin/env so that "/usr/bin/env node" works like "node".
-    var shebangMatch = fileChunk.match(/^#!(?:\/usr\/bin\/env )?([^\r\n]+)/m);
-    if (octetsRead == 4096 && !fileChunk.match(/[\r\n]/))
-        events.emit('warn', 'shebang is too long for "' + fullpath + '"');
-    if (shebangMatch)
-        hookCmd = shebangMatch[1];
-    // Likewise, make /usr/bin/bash work like "bash".
-    if (hookCmd)
-        shMatch = hookCmd.match(/bin\/((?:ba)?sh)$/);
-    if (shMatch)
-        hookCmd = shMatch[1];
-    return hookCmd;
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/850f4502/cordova-lib/src/plugman/install.js
----------------------------------------------------------------------
diff --git a/cordova-lib/src/plugman/install.js b/cordova-lib/src/plugman/install.js
index 4823b68..e11c30b 100644
--- a/cordova-lib/src/plugman/install.js
+++ b/cordova-lib/src/plugman/install.js
@@ -38,7 +38,7 @@ var path = require('path'),
     shell   = require('shelljs'),
     events = require('../events'),
     plugman = require('./plugman'),
-    Hooker = require('../hooks/Hooker'),
+    HooksRunner = require('../hooks/HooksRunner'),
     isWindows = (os.platform().substr(0,3) === 'win'),
     cordovaUtil = require('../cordova/util');
 
@@ -323,25 +323,28 @@ function runInstall(actions, platform, project_dir, plugin_dir, plugins_dir, opt
 
             var projectRoot = cordovaUtil.isCordova();
 
-            // using unified hooker
-            var hookOptions = {
-                projectRoot: projectRoot,
-                cordova: { platforms: [ platform ], plugins: options.plugins },
-                plugin: {
-                    id: pluginInfo.id,
-                    pluginInfo: pluginInfo,
-                    platform: install.platform,
-                    dir: install.top_plugin_dir
-                }
-            };
+            if(projectRoot) {
+                // using unified hooksRunner
+                var hookOptions = {
+                    cordova: { platforms: [ platform ] },
+                    plugin: {
+                        id: pluginInfo.id,
+                        pluginInfo: pluginInfo,
+                        platform: install.platform,
+                        dir: install.top_plugin_dir
+                    }
+                };
 
-            var hooker = new Hooker(projectRoot);
+                var hooksRunner = new HooksRunner(projectRoot);
 
-            hooker.fire('before_plugin_install', hookOptions).then(function() {
+                hooksRunner.fire('before_plugin_install', hookOptions).then(function() {
+                    return handleInstall(actions, pluginInfo, platform, project_dir, plugins_dir, install_plugin_dir, filtered_variables, options);
+                }).then(function(){
+                    return hooksRunner.fire('after_plugin_install', hookOptions);
+                });
+            } else {
                 return handleInstall(actions, pluginInfo, platform, project_dir, plugins_dir, install_plugin_dir, filtered_variables, options);
-            }).then(function(){
-                return hooker.fire('after_plugin_install', hookOptions);
-            });
+            }
         }
     ).fail(
         function (error) {

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/850f4502/cordova-lib/src/plugman/uninstall.js
----------------------------------------------------------------------
diff --git a/cordova-lib/src/plugman/uninstall.js b/cordova-lib/src/plugman/uninstall.js
index 0a48fa2..82db79d 100644
--- a/cordova-lib/src/plugman/uninstall.js
+++ b/cordova-lib/src/plugman/uninstall.js
@@ -36,7 +36,7 @@ var path = require('path'),
     platform_modules = require('./platforms'),
     plugman = require('./plugman'),
     promiseutil = require('../util/promise-util'),
-    Hooker = require('../hooks/Hooker'),
+    HooksRunner = require('../hooks/HooksRunner'),
     PluginInfo = require('../PluginInfo'),
     cordovaUtil      = require('../cordova/util');
 
@@ -240,29 +240,33 @@ function runUninstallPlatform(actions, platform, project_dir, plugin_dir, plugin
     }
 
     var projectRoot = cordovaUtil.isCordova();
-    var pluginInfo = new PluginInfo.PluginInfo(plugin_dir);
-
-    // using unified hooker
-    var hookerOptions = {
-        projectRoot: projectRoot,
-        cordova: { platforms: [ platform ], plugins: options.plugins },
-        plugin: {
-            id: pluginInfo.id,
-            pluginInfo: pluginInfo,
-            platform: platform,
-            dir: plugin_dir
-        }
-    };
 
-    var hooker = new Hooker(projectRoot);
+    if(projectRoot) {
+        var pluginInfo = new PluginInfo.PluginInfo(plugin_dir);
+
+        // using unified hooksRunner
+        var hooksRunnerOptions = {
+            cordova: { platforms: [ platform ] },
+            plugin: {
+                id: pluginInfo.id,
+                pluginInfo: pluginInfo,
+                platform: platform,
+                dir: plugin_dir
+            }
+        };
+
+        var hooksRunner = new HooksRunner(projectRoot);
 
-    return promise.then(function() {
-        return hooker.fire('before_plugin_uninstall', hookerOptions);
-    }).then(function() {
+        return promise.then(function() {
+            return hooksRunner.fire('before_plugin_uninstall', hooksRunnerOptions);
+        }).then(function() {
+            return handleUninstall(actions, platform, plugin_id, plugin_et, project_dir, options.www_dir, plugins_dir, plugin_dir, options.is_top_level, options);
+        });
+    } else {
+        // TODO: Need review here - this condition added for plugman install.spec.js and uninstall.spec.js passing -
+        // where should we get projectRoot - via going up from project_dir?
         return handleUninstall(actions, platform, plugin_id, plugin_et, project_dir, options.www_dir, plugins_dir, plugin_dir, options.is_top_level, options);
-    }).then(function(){
-        return hooker.fire('after_plugin_uninstall', hookerOptions);
-    });
+    }
 }
 
 // Returns a promise.