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:00 UTC

[01/13] git commit: CB-6481 Replaced CordovaError throwings with Error per @kamrik review Extracted prepareOptions Hooker method

Repository: cordova-lib
Updated Branches:
  refs/heads/master 8abfaf18c -> 57f454b28


CB-6481 Replaced CordovaError throwings with Error per @kamrik review
Extracted prepareOptions Hooker method


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

Branch: refs/heads/master
Commit: 35a350adecc6daa04af42c9ef42f318ca862383f
Parents: 4f0e74f
Author: daserge <da...@yandex.ru>
Authored: Tue Jul 15 14:51:15 2014 +0400
Committer: daserge <da...@yandex.ru>
Committed: Thu Sep 25 18:59:08 2014 +0400

----------------------------------------------------------------------
 cordova-lib/src/hooks/Hooker.js        | 21 ++++++++++++++-------
 cordova-lib/src/hooks/ScriptsFinder.js |  7 +++----
 cordova-lib/src/hooks/ScriptsRunner.js |  3 +--
 3 files changed, 18 insertions(+), 13 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/35a350ad/cordova-lib/src/hooks/Hooker.js
----------------------------------------------------------------------
diff --git a/cordova-lib/src/hooks/Hooker.js b/cordova-lib/src/hooks/Hooker.js
index 9951e20..7d50e76 100644
--- a/cordova-lib/src/hooks/Hooker.js
+++ b/cordova-lib/src/hooks/Hooker.js
@@ -22,8 +22,7 @@ var util  = require('../cordova/util'),
     plugin  = require('../cordova/plugin'),
     ScriptsFinder = require('./ScriptsFinder'),
     ScriptsRunner = require('./ScriptsRunner'),
-    Context = require('./Context'),
-    CordovaError = require('../CordovaError');
+    Context = require('./Context');
 
 /**
  * Tries to create a hooker for passed project root.
@@ -31,7 +30,7 @@ var util  = require('../cordova/util'),
  */
 function Hooker(projectRoot) {
     if (!util.isCordova(projectRoot)) {
-        throw new CordovaError('Not a Cordova project ("' + projectRoot + '"), can\'t use hooks.');
+        throw new Error('Not a Cordova project ("' + projectRoot + '"), can\'t use hooks.');
     }
 }
 
@@ -42,12 +41,10 @@ function Hooker(projectRoot) {
 Hooker.prototype.fire = function fire(hook, opts) {
     // args check
     if (!hook) {
-        throw new CordovaError('hook type is not specified');
+        throw new Error('hook type is not specified');
     }
     // execute hook event listeners first
-    return setPluginsProperty(opts).then(function(){
-        setCordovaVersionProperty(opts);
-
+    return this.prepareOptions(opts).then(function(){
         var handlers = events.listeners(hook);
         return executeHandlersSerially(handlers, opts);
     // then execute hook script files
@@ -59,6 +56,16 @@ Hooker.prototype.fire = function fire(hook, opts) {
 };
 
 /**
+ * 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.
  */

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/35a350ad/cordova-lib/src/hooks/ScriptsFinder.js
----------------------------------------------------------------------
diff --git a/cordova-lib/src/hooks/ScriptsFinder.js b/cordova-lib/src/hooks/ScriptsFinder.js
index 5fb9ed2..f9659de 100644
--- a/cordova-lib/src/hooks/ScriptsFinder.js
+++ b/cordova-lib/src/hooks/ScriptsFinder.js
@@ -25,7 +25,6 @@ var path = require('path'),
     plugin  = require('../cordova/plugin'),
     PluginInfo = require('../PluginInfo'),
     ConfigParser = require('../configparser/ConfigParser'),
-    CordovaError = require('../CordovaError'),
     Context = require('./Context');
 
 /**
@@ -39,7 +38,7 @@ module.exports  = {
     getHookScripts: function(hook, opts) {
         // args check
         if (!hook) {
-            throw new CordovaError('hook type is not specified');
+            throw new Error('hook type is not specified');
         }
         return getApplicationHookScripts(hook, opts)
             .concat(getPluginsHookScripts(hook, opts));
@@ -53,7 +52,7 @@ module.exports  = {
 function getApplicationHookScripts(hook, opts) {
     // args check
     if (!hook) {
-        throw new CordovaError('hook type is not specified');
+        throw new Error('hook type is not specified');
     }
     return getApplicationHookScriptsFromDir(path.join(opts.projectRoot, '.cordova', 'hooks', hook))
         .concat(getApplicationHookScriptsFromDir(path.join(opts.projectRoot, 'hooks', hook)))
@@ -66,7 +65,7 @@ function getApplicationHookScripts(hook, opts) {
 function getPluginsHookScripts(hook, opts) {
     // args check
     if (!hook) {
-        throw new CordovaError('hook type is not specified');
+        throw new Error('hook type is not specified');
     }
 
     // In case before_plugin_install, after_plugin_install, before_plugin_uninstall hooks we receive opts.plugin and

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/35a350ad/cordova-lib/src/hooks/ScriptsRunner.js
----------------------------------------------------------------------
diff --git a/cordova-lib/src/hooks/ScriptsRunner.js b/cordova-lib/src/hooks/ScriptsRunner.js
index c7ff70d..918b56d 100644
--- a/cordova-lib/src/hooks/ScriptsRunner.js
+++ b/cordova-lib/src/hooks/ScriptsRunner.js
@@ -22,7 +22,6 @@ var Q = require('q'),
     os = require('os'),
     path = require('path'),
     superspawn = require('../cordova/superspawn'),
-    CordovaError = require('../CordovaError'),
     Context = require('./Context');
 
 var isWindows = os.platform().slice(0, 3) === 'win';
@@ -125,7 +124,7 @@ function runScriptViaChildProcessSpawn(script, context) {
             if (!isWindows && err.code == 'EACCES') {
                 events.emit('verbose', 'skipped non-executable file: ' + script.fullPath);
             } else {
-                throw new CordovaError('Hook failed with error code ' + err.code + ': ' + script.fullPath);
+                throw new Error('Hook failed with error code ' + err.code + ': ' + script.fullPath);
             }
         });
 }


[10/13] git commit: CB-6481 Context opts should copy not reference

Posted by sg...@apache.org.
CB-6481 Context opts should copy not reference


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

Branch: refs/heads/master
Commit: b74d87d8ef1f2f5a7c967e50cdb3d177119833bc
Parents: 1b5ce69
Author: Carlos Santana <cs...@gmail.com>
Authored: Fri Aug 8 09:30:06 2014 -0400
Committer: daserge <da...@yandex.ru>
Committed: Thu Sep 25 19:06:15 2014 +0400

----------------------------------------------------------------------
 cordova-lib/src/hooks/Context.js | 14 ++++++++++++--
 1 file changed, 12 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/b74d87d8/cordova-lib/src/hooks/Context.js
----------------------------------------------------------------------
diff --git a/cordova-lib/src/hooks/Context.js b/cordova-lib/src/hooks/Context.js
index b299597..889e283 100644
--- a/cordova-lib/src/hooks/Context.js
+++ b/cordova-lib/src/hooks/Context.js
@@ -30,12 +30,22 @@ var Q = require('q'),
  * @param {Object} opts Hook options
  * @returns {Object} */
 function Context(hook, opts) {
+    var prop;
     this.hook = hook;
-    this.opts = opts;
+
+    //create new object, to avoid affecting input opts in other places
+    //For example context.opts.plugin = Object is done, then it affects by reference
+    this.opts = {};
+    for (prop in opts) {
+    if (opts.hasOwnProperty(prop)) {
+        this.opts[prop] = opts[prop];
+      }
+    }
     this.cmdLine =  process.argv.join(' ');
     this.cordova = require('../cordova/cordova');
 }
 
+
 /**
  * Returns a required module
  * @param {String} path Module path
@@ -44,4 +54,4 @@ Context.prototype.requireCordovaModule = function (path) {
     return require(path);
 };
 
-module.exports = Context;
\ No newline at end of file
+module.exports = Context;


[11/13] git commit: CB-6481 Fixed tests - removed output

Posted by sg...@apache.org.
CB-6481 Fixed tests - removed output

Avoided tests output - mocked hooker fire in windows8 and wp8 tests
Added pwd check missing case to isCordova
Removed exception swallowing in case config.xml is not found in hooks/scriptFinder


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

Branch: refs/heads/master
Commit: 1b5ce69b93833145f14772213600c0e516ccff64
Parents: a316933
Author: daserge <da...@yandex.ru>
Authored: Fri Aug 1 17:09:34 2014 +0400
Committer: daserge <da...@yandex.ru>
Committed: Thu Sep 25 19:06:15 2014 +0400

----------------------------------------------------------------------
 .idea/encodings.xml                             |   5 +
 .idea/misc.xml                                  |   5 +
 .idea/modules.xml                               |   7 +
 .idea/scopes/scope_settings.xml                 |   5 +
 .idea/vcs.xml                                   |   7 +
 .idea/workspace.xml                             | 131 +++++++++++++++++++
 .../projWithHooks/.cordova/hooks/fail/fail.js   |   2 +-
 .../metadata/windows8_parser.spec.js            |   6 +-
 .../spec-cordova/metadata/wp8_parser.spec.js    |   6 +-
 cordova-lib/src/cordova/util.js                 |   2 +-
 cordova-lib/src/hooks/scriptsFinder.js          |  10 +-
 11 files changed, 171 insertions(+), 15 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/1b5ce69b/.idea/encodings.xml
----------------------------------------------------------------------
diff --git a/.idea/encodings.xml b/.idea/encodings.xml
new file mode 100644
index 0000000..e206d70
--- /dev/null
+++ b/.idea/encodings.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="Encoding" useUTFGuessing="true" native2AsciiForPropertiesFiles="false" />
+</project>
+

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/1b5ce69b/.idea/misc.xml
----------------------------------------------------------------------
diff --git a/.idea/misc.xml b/.idea/misc.xml
new file mode 100644
index 0000000..1162f43
--- /dev/null
+++ b/.idea/misc.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="ProjectRootManager" version="2" />
+</project>
+

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/1b5ce69b/.idea/modules.xml
----------------------------------------------------------------------
diff --git a/.idea/modules.xml b/.idea/modules.xml
new file mode 100644
index 0000000..684f749
--- /dev/null
+++ b/.idea/modules.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="ProjectModuleManager">
+    <modules />
+  </component>
+</project>
+

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/1b5ce69b/.idea/scopes/scope_settings.xml
----------------------------------------------------------------------
diff --git a/.idea/scopes/scope_settings.xml b/.idea/scopes/scope_settings.xml
new file mode 100644
index 0000000..922003b
--- /dev/null
+++ b/.idea/scopes/scope_settings.xml
@@ -0,0 +1,5 @@
+<component name="DependencyValidationManager">
+  <state>
+    <option name="SKIP_IMPORT_STATEMENTS" value="false" />
+  </state>
+</component>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/1b5ce69b/.idea/vcs.xml
----------------------------------------------------------------------
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 0000000..c80f219
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="VcsDirectoryMappings">
+    <mapping directory="$PROJECT_DIR$" vcs="Git" />
+  </component>
+</project>
+

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/1b5ce69b/.idea/workspace.xml
----------------------------------------------------------------------
diff --git a/.idea/workspace.xml b/.idea/workspace.xml
new file mode 100644
index 0000000..ea84f4e
--- /dev/null
+++ b/.idea/workspace.xml
@@ -0,0 +1,131 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="ChangeListManager">
+    <list default="true" id="3463b0e6-70cf-4c4e-9c11-14dcdc7db6a1" name="Default" comment="" />
+    <ignored path="cordova-lib.iws" />
+    <ignored path=".idea/workspace.xml" />
+    <option name="TRACKING_ENABLED" value="true" />
+    <option name="SHOW_DIALOG" value="false" />
+    <option name="HIGHLIGHT_CONFLICTS" value="true" />
+    <option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
+    <option name="LAST_RESOLUTION" value="IGNORE" />
+  </component>
+  <component name="ChangesViewManager" flattened_view="true" show_ignored="false" />
+  <component name="CreatePatchCommitExecutor">
+    <option name="PATCH_PATH" value="" />
+  </component>
+  <component name="DaemonCodeAnalyzer">
+    <disable_hints />
+  </component>
+  <component name="ExecutionTargetManager" SELECTED_TARGET="default_target" />
+  <component name="FavoritesManager">
+    <favorites_list name="cordova-lib" />
+  </component>
+  <component name="Git.Settings">
+    <option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" />
+  </component>
+  <component name="ProjectFrameBounds">
+    <option name="x" value="-8" />
+    <option name="y" value="-8" />
+    <option name="width" value="1936" />
+    <option name="height" value="1056" />
+  </component>
+  <component name="ProjectLevelVcsManager" settingsEditedManually="false">
+    <OptionsSetting value="true" id="Add" />
+    <OptionsSetting value="true" id="Remove" />
+    <OptionsSetting value="true" id="Checkout" />
+    <OptionsSetting value="true" id="Update" />
+    <OptionsSetting value="true" id="Status" />
+    <OptionsSetting value="true" id="Edit" />
+    <ConfirmationsSetting value="0" id="Add" />
+    <ConfirmationsSetting value="0" id="Remove" />
+  </component>
+  <component name="ProjectReloadState">
+    <option name="STATE" value="0" />
+  </component>
+  <component name="ProjectView">
+    <navigator currentView="ProjectPane" proportions="" version="1">
+      <flattenPackages />
+      <showMembers />
+      <showModules />
+      <showLibraryContents />
+      <hideEmptyPackages />
+      <abbreviatePackageNames />
+      <autoscrollToSource />
+      <autoscrollFromSource />
+      <sortByType />
+    </navigator>
+    <panes>
+      <pane id="Scope" />
+      <pane id="ProjectPane">
+        <subPane>
+          <PATH>
+            <PATH_ELEMENT>
+              <option name="myItemId" value="cordova-lib" />
+              <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.ProjectViewProjectNode" />
+            </PATH_ELEMENT>
+          </PATH>
+        </subPane>
+      </pane>
+    </panes>
+  </component>
+  <component name="PropertiesComponent">
+    <property name="last_opened_file_path" value="$PROJECT_DIR$/cordova-lib" />
+    <property name="WebServerToolWindowFactoryState" value="false" />
+  </component>
+  <component name="RunManager">
+    <list size="0" />
+  </component>
+  <component name="ShelveChangesManager" show_recycled="false" />
+  <component name="TaskManager">
+    <task active="true" id="Default" summary="Default task">
+      <changelist id="3463b0e6-70cf-4c4e-9c11-14dcdc7db6a1" name="Default" comment="" />
+      <created>1409739905639</created>
+      <updated>1409739905639</updated>
+    </task>
+    <servers />
+  </component>
+  <component name="ToolWindowManager">
+    <frame x="-8" y="-8" width="1936" height="1056" extended-state="6" />
+    <editor active="false" />
+    <layout>
+      <window_info id="Changes" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.33" sideWeight="0.5" order="-1" side_tool="false" content_ui="tabs" />
+      <window_info id="Terminal" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.33" sideWeight="0.5" order="-1" side_tool="false" content_ui="tabs" />
+      <window_info id="TODO" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.33" sideWeight="0.5" order="6" side_tool="false" content_ui="tabs" />
+      <window_info id="Structure" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.25" sideWeight="0.5" order="1" side_tool="false" content_ui="tabs" />
+      <window_info id="Project" active="true" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="true" weight="0.24960506" sideWeight="0.5" order="0" side_tool="false" content_ui="combo" />
+      <window_info id="Debug" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.4" sideWeight="0.5" order="3" side_tool="false" content_ui="tabs" />
+      <window_info id="Favorites" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.33" sideWeight="0.5" order="-1" side_tool="true" content_ui="tabs" />
+      <window_info id="Event Log" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.33" sideWeight="0.5" order="-1" side_tool="true" content_ui="tabs" />
+      <window_info id="Run" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.33" sideWeight="0.5" order="2" side_tool="false" content_ui="tabs" />
+      <window_info id="Version Control" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.33" sideWeight="0.5" order="-1" side_tool="false" content_ui="tabs" />
+      <window_info id="Cvs" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.25" sideWeight="0.5" order="4" side_tool="false" content_ui="tabs" />
+      <window_info id="Message" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.33" sideWeight="0.5" order="0" side_tool="false" content_ui="tabs" />
+      <window_info id="Ant Build" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.25" sideWeight="0.5" order="1" side_tool="false" content_ui="tabs" />
+      <window_info id="Find" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.33" sideWeight="0.5" order="1" side_tool="false" content_ui="tabs" />
+      <window_info id="Commander" active="false" anchor="right" auto_hide="false" internal_type="SLIDING" type="SLIDING" visible="false" weight="0.4" sideWeight="0.5" order="0" side_tool="false" content_ui="tabs" />
+      <window_info id="Hierarchy" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.25" sideWeight="0.5" order="2" side_tool="false" content_ui="combo" />
+      <window_info id="Inspection" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.4" sideWeight="0.5" order="5" side_tool="false" content_ui="tabs" />
+    </layout>
+  </component>
+  <component name="Vcs.Log.UiProperties">
+    <option name="RECENTLY_FILTERED_USER_GROUPS">
+      <collection />
+    </option>
+    <option name="RECENTLY_FILTERED_BRANCH_GROUPS">
+      <collection />
+    </option>
+  </component>
+  <component name="VcsContentAnnotationSettings">
+    <option name="myLimit" value="2678400000" />
+  </component>
+  <component name="VcsManagerConfiguration">
+    <option name="myTodoPanelSettings">
+      <TodoPanelSettings />
+    </option>
+  </component>
+  <component name="XDebuggerManager">
+    <breakpoint-manager />
+  </component>
+</project>
+

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/1b5ce69b/cordova-lib/spec-cordova/fixtures/projWithHooks/.cordova/hooks/fail/fail.js
----------------------------------------------------------------------
diff --git a/cordova-lib/spec-cordova/fixtures/projWithHooks/.cordova/hooks/fail/fail.js b/cordova-lib/spec-cordova/fixtures/projWithHooks/.cordova/hooks/fail/fail.js
index d2d790b..7e8ff52 100644
--- a/cordova-lib/spec-cordova/fixtures/projWithHooks/.cordova/hooks/fail/fail.js
+++ b/cordova-lib/spec-cordova/fixtures/projWithHooks/.cordova/hooks/fail/fail.js
@@ -1,2 +1,2 @@
 #!/usr/bin/env node
-throw Error('test error');
\ No newline at end of file
+process.exit(1);
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/1b5ce69b/cordova-lib/spec-cordova/metadata/windows8_parser.spec.js
----------------------------------------------------------------------
diff --git a/cordova-lib/spec-cordova/metadata/windows8_parser.spec.js b/cordova-lib/spec-cordova/metadata/windows8_parser.spec.js
index 2d9c3f3..b7279b0 100644
--- a/cordova-lib/spec-cordova/metadata/windows8_parser.spec.js
+++ b/cordova-lib/spec-cordova/metadata/windows8_parser.spec.js
@@ -28,7 +28,8 @@ var platforms = require('../../src/cordova/platforms'),
     fs = require('fs'),
     config = require('../../src/cordova/config'),
     ConfigParser = require('../../src/configparser/ConfigParser'),
-    cordova = require('../../src/cordova/cordova');
+    cordova = require('../../src/cordova/cordova'),
+    HooksRunner = require('../../src/hooks/HooksRunner');
 
 // Create a real config object before mocking out everything.
 var cfg = new ConfigParser(path.join(__dirname, '..', 'test-config.xml'));
@@ -143,13 +144,14 @@ describe('windows8 project parser', function() {
             });
         });
         describe('update_project method', function() {
-            var config, www, overrides, svn;
+            var config, www, overrides, svn, fire;
             beforeEach(function() {
                 config = spyOn(parser, 'update_from_config');
                 www = spyOn(parser, 'update_www');
                 shellls = spyOn(shell, 'ls').andReturn([]);
                 svn = spyOn(util, 'deleteSvnFolders');
                 exists.andReturn(false);
+                fire = spyOn(HooksRunner.prototype, 'fire').andReturn(Q());
             });
             it('should call update_from_config', function() {
                 parser.update_project();

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/1b5ce69b/cordova-lib/spec-cordova/metadata/wp8_parser.spec.js
----------------------------------------------------------------------
diff --git a/cordova-lib/spec-cordova/metadata/wp8_parser.spec.js b/cordova-lib/spec-cordova/metadata/wp8_parser.spec.js
index dd85d26..aac5858 100644
--- a/cordova-lib/spec-cordova/metadata/wp8_parser.spec.js
+++ b/cordova-lib/spec-cordova/metadata/wp8_parser.spec.js
@@ -29,7 +29,8 @@ var platforms = require('../../src/cordova/platforms'),
     config = require('../../src/cordova/config'),
     ConfigParser = require('../../src/configparser/ConfigParser'),
     CordovaError = require('../../src/CordovaError'),
-    cordova = require('../../src/cordova/cordova');
+    cordova = require('../../src/cordova/cordova'),
+    HooksRunner = require('../../src/hooks/HooksRunner');
 
 // Create a real config object before mocking out everything.
 var cfg = new ConfigParser(path.join(__dirname, '..', 'test-config.xml'));
@@ -158,12 +159,13 @@ describe('wp8 project parser', function() {
             });
         });
         describe('update_project method', function() {
-            var config, www, overrides, svn;
+            var config, www, overrides, svn, fire;
             beforeEach(function() {
                 config = spyOn(p, 'update_from_config');
                 www = spyOn(p, 'update_www');
                 svn = spyOn(util, 'deleteSvnFolders');
                 exists.andReturn(false);
+                fire = spyOn(HooksRunner.prototype, 'fire').andReturn(Q());
             });
             it('should call update_from_config', function(done) {
                 wrapper(p.update_project(), done, function() {

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/1b5ce69b/cordova-lib/src/cordova/util.js
----------------------------------------------------------------------
diff --git a/cordova-lib/src/cordova/util.js b/cordova-lib/src/cordova/util.js
index 86dff6d..89b0ef3 100644
--- a/cordova-lib/src/cordova/util.js
+++ b/cordova-lib/src/cordova/util.js
@@ -74,7 +74,7 @@ function isCordova(dir) {
         // Prefer PWD over cwd so that symlinked dirs within your PWD work correctly (CB-5687).
         var pwd = process.env.PWD;
         var cwd = process.cwd();
-        if (pwd && pwd != cwd) {
+        if (pwd && pwd != cwd && pwd != 'undefined') {
             return this.isCordova(pwd) || this.isCordova(cwd);
         }
         return this.isCordova(cwd);

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/1b5ce69b/cordova-lib/src/hooks/scriptsFinder.js
----------------------------------------------------------------------
diff --git a/cordova-lib/src/hooks/scriptsFinder.js b/cordova-lib/src/hooks/scriptsFinder.js
index 9abbb8e..3345af1 100644
--- a/cordova-lib/src/hooks/scriptsFinder.js
+++ b/cordova-lib/src/hooks/scriptsFinder.js
@@ -107,15 +107,7 @@ function getApplicationHookScriptsFromDir(dir) {
  */
 function getScriptsFromConfigXml(hook, opts) {
     var configPath = cordovaUtil.projectConfig(opts.projectRoot);
-    var configXml;
-
-    try {
-        configXml = new ConfigParser(configPath);
-    } catch(ex) {
-        events.emit('err', 'scriptsFinder could not load config.xml: ' + ex.message);
-        console.log('scriptsFinder could not load config.xml: ' + ex.message);
-        return [];
-    }
+    var configXml = new ConfigParser(configPath);
 
     return configXml.getHookScripts(hook, opts.cordova.platforms).map(function(scriptElement) {
         return {


[08/13] git commit: CB-6481 Updated tests

Posted by sg...@apache.org.
CB-6481 Updated tests


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

Branch: refs/heads/master
Commit: eed41399786ae2ab93ff2b7a0cd3bae1f4ff721a
Parents: d8c586a
Author: daserge <da...@yandex.ru>
Authored: Tue Jul 22 15:14:53 2014 +0400
Committer: daserge <da...@yandex.ru>
Committed: Thu Sep 25 19:04:55 2014 +0400

----------------------------------------------------------------------
 cordova-lib/spec-cordova/HooksRunner.spec.js    | 613 +++++++++++++++++++
 cordova-lib/spec-cordova/build.spec.js          |   4 +-
 cordova-lib/spec-cordova/compile.spec.js        |   4 +-
 cordova-lib/spec-cordova/emulate.spec.js        |   4 +-
 .../plugins/com.plugin.withhooks/plugin.xml     |   7 +
 .../pluginOnePlatform_bat.xml                   |  19 +
 .../pluginOnePlatform_sh.xml                    |  19 +
 .../pluginOnlyNonPlatformScripts_bat.xml        |  14 +
 .../pluginOnlyNonPlatformScripts_sh.xml         |  14 +
 .../pluginTwoPlatforms_bat.xml                  |  24 +
 .../pluginTwoPlatforms_sh.xml                   |  24 +
 .../scripts/android/androidBeforeBuild.js       |   4 +
 .../scripts/android/androidBeforeInstall.js     |   4 +
 .../scripts/beforeBuild.bat                     |   2 +
 .../com.plugin.withhooks/scripts/beforeBuild.js |   4 +
 .../com.plugin.withhooks/scripts/beforeBuild.sh |   1 +
 .../scripts/beforeInstall.bat                   |   2 +
 .../scripts/beforeInstall.sh                    |   1 +
 .../scripts/beforeInstall01.js                  |   4 +
 .../scripts/beforeInstall2.js                   |   4 +
 .../scripts/beforeUninstall.js                  |   4 +
 .../scripts/windows/windowsBeforeBuild.js       |   4 +
 .../scripts/windows/windowsBeforeInstall.js     |   4 +
 .../fixtures/projWithHooks/.cordova/config.json |  22 +
 .../hooks/before_build/hookScriptDot03.js       |   4 +
 .../hooks/before_build/hookScriptDot1.js        |   4 +
 .../projWithHooks/.cordova/hooks/fail/fail.js   |   2 +
 .../hooks/before_build/hookScriptDot2.bat       |   2 +
 .../_bat/hooks/before_build/hookScript01.bat    |   2 +
 .../_bat/hooks/before_build/hookScript02.bat    |   2 +
 .../_bat/hooks/before_build/hookScript3.bat     |   2 +
 .../hooks/before_build/hookScriptDot2.sh        |   1 +
 .../_sh/hooks/before_build/hookScript01.sh      |   1 +
 .../_sh/hooks/before_build/hookScript02.sh      |   1 +
 .../_sh/hooks/before_build/hookScript3.sh       |   1 +
 .../fixtures/projWithHooks/config.xml           |  12 +
 .../projWithHooks/configOnePlatform_bat.xml     |  22 +
 .../projWithHooks/configOnePlatform_sh.xml      |  22 +
 .../configOnlyNonPlatformScripts_bat.xml        |  16 +
 .../configOnlyNonPlatformScripts_sh.xml         |  16 +
 .../projWithHooks/configTwoPlatforms_bat.xml    |  28 +
 .../projWithHooks/configTwoPlatforms_sh.xml     |  28 +
 .../hooks/before_build/hookScript10.js          |   4 +
 .../fixtures/projWithHooks/merges/.gitignore    |   0
 .../fixtures/projWithHooks/plugins/.gitignore   |   0
 .../scripts/android/appAndroidBeforeBuild.bat   |   2 +
 .../scripts/android/appAndroidBeforeBuild.js    |   4 +
 .../scripts/android/appAndroidBeforeBuild.sh    |   1 +
 .../android/appAndroidBeforePluginInstall.js    |   4 +
 .../projWithHooks/scripts/appBeforeBuild02.js   |   4 +
 .../projWithHooks/scripts/appBeforeBuild1.bat   |   2 +
 .../projWithHooks/scripts/appBeforeBuild1.sh    |   1 +
 .../scripts/appBeforePluginInstall.js           |   4 +
 .../projWithHooks/scripts/orderLogger.js        |  12 +
 .../scripts/windows/appWindowsBeforeBuild.bat   |   2 +
 .../scripts/windows/appWindowsBeforeBuild.js    |   4 +
 .../scripts/windows/appWindowsBeforeBuild.sh    |   1 +
 .../windows/appWindowsBeforePluginInstall.js    |   4 +
 .../fixtures/projWithHooks/www/config.xml       |  14 +
 .../fixtures/projWithHooks/www/css/index.css    | 115 ++++
 .../fixtures/projWithHooks/www/img/logo.png     | Bin 0 -> 21814 bytes
 .../fixtures/projWithHooks/www/index.html       |  43 ++
 .../fixtures/projWithHooks/www/js/index.js      |  49 ++
 .../fixtures/projWithHooks/www/spec.html        |  68 ++
 cordova-lib/spec-cordova/hooker.spec.js         | 261 --------
 cordova-lib/spec-cordova/lazy_load.spec.js      |   4 +-
 cordova-lib/spec-cordova/prepare.spec.js        |   4 +-
 cordova-lib/spec-cordova/run.spec.js            |   4 +-
 cordova-lib/spec-cordova/serve.spec.js          |   1 -
 69 files changed, 1310 insertions(+), 274 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/eed41399/cordova-lib/spec-cordova/HooksRunner.spec.js
----------------------------------------------------------------------
diff --git a/cordova-lib/spec-cordova/HooksRunner.spec.js b/cordova-lib/spec-cordova/HooksRunner.spec.js
new file mode 100644
index 0000000..1e89808
--- /dev/null
+++ b/cordova-lib/spec-cordova/HooksRunner.spec.js
@@ -0,0 +1,613 @@
+/**
+ 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 cordova = require('../src/cordova/cordova'),
+    HooksRunner = require('../src/hooks/HooksRunner'),
+    shell  = require('shelljs'),
+    path   = require('path'),
+    fs     = require('fs'),
+    os     = require('os'),
+    Q      = require('q'),
+    child_process = require('child_process'),
+    helpers = require('./helpers'),
+    PluginInfo = require('../src/PluginInfo'),
+    superspawn = require('../src/cordova/superspawn'),
+    config = require('../src/cordova/config');
+
+var platform = os.platform();
+var tmpDir = helpers.tmpDir('hooks_test');
+var project = path.join(tmpDir, 'project');
+var dotCordova = path.join(project, '.cordova');
+var hooksDir = path.join(project, 'hooks');
+var hooksDirDot = path.join(project, '.cordova', 'hooks');
+var scriptsDir = path.join(project, 'scripts');
+var ext = platform.match(/(win32|win64)/)?'bat':'sh';
+var testPluginFixturePath = path.join(__dirname, 'fixtures', 'plugins', 'com.plugin.withhooks');
+
+var cordovaUtil = require('../src/cordova/util');
+
+
+// copy fixture
+shell.rm('-rf', project);
+shell.mkdir('-p', project);
+shell.cp('-R', path.join(__dirname, 'fixtures', 'projWithHooks', '*'), project);
+
+shell.mkdir('-p', dotCordova);
+shell.cp('-R', path.join(__dirname, 'fixtures', 'projWithHooks', '.cordova'), project);
+
+// copy sh/bat scripts
+if(ext === 'bat') {
+    shell.cp('-R', path.join(__dirname, 'fixtures', 'projWithHooks', '_bat', '*'), project);
+    shell.cp('-R', path.join(__dirname, 'fixtures', 'projWithHooks', '_bat', '.cordova'), project);
+} else {
+    shell.cp('-R', path.join(__dirname, 'fixtures', 'projWithHooks', '_sh', '*'), project);
+    shell.cp('-R', path.join(__dirname, 'fixtures', 'projWithHooks', '_sh', '.cordova'), project);
+}
+
+shell.chmod('-R', 'ug+x', hooksDir);
+shell.chmod('-R', 'ug+x', hooksDirDot);
+shell.chmod('-R', 'ug+x', scriptsDir);
+
+jasmine.getEnv().defaultTimeoutInterval = 3000;
+process.chdir(project);
+
+
+describe('HooksRunner', function() {
+    var hooksRunner;
+    var hookOptions;
+    var testPluginInstalledPath;
+    var projectRoot;
+    var fire;
+
+    it('should throw if provided directory is not a cordova project', function() {
+        expect(function() {
+            new HooksRunner(tmpDir);
+        }).toThrow();
+    });
+
+    it('should not throw if provided directory is a cordova project', function() {
+        expect(function () {
+            new HooksRunner(project);
+        }).not.toThrow();
+    });
+
+    it('should init test fixtures', function(done) {
+        hooksRunner = new HooksRunner(project);
+
+        // Now we load the config.json in the newly created project and edit the target platform's lib entry
+        // to point at the fixture version. This is necessary so that cordova.prepare can find cordova.js there.
+        var c = config.read(project);
+        c.lib[helpers.testPlatform].url = path.join(__dirname, 'fixtures', 'platforms', helpers.testPlatform + '-lib');
+        config.write(project, c);
+
+        // The config.json in the fixture project points at fake "local" paths.
+        // Since it's not a URL, the lazy-loader will just return the junk path.
+        spyOn(superspawn, 'spawn').andCallFake(function(cmd, args) {
+            if (cmd.match(/create\b/)) {
+                // This is a call to the bin/create script, so do the copy ourselves.
+                shell.cp('-R', path.join(__dirname, 'fixtures', 'platforms', 'android'), path.join(project, 'platforms'));
+            } else if(cmd.match(/version\b/)) {
+                return Q('3.3.0');
+            } else if(cmd.match(/update\b/)) {
+                fs.writeFileSync(path.join(project, 'platforms', helpers.testPlatform, 'updated'), 'I was updated!', 'utf-8');
+            }
+            return Q();
+        });
+
+
+        // Add the testing platform.
+        cordova.raw.platform('add', [helpers.testPlatform]).fail(function (err) {
+            expect(err).toBeUndefined();
+        }).then(function () {
+            // Add the testing plugin
+            projectRoot = cordovaUtil.isCordova();
+
+            var options = {
+                verbose: false,
+                platforms: [],
+                options: []
+            };
+
+            options = cordovaUtil.preProcessOptions(options);
+
+            hookOptions = { projectRoot: project, cordova: options };
+
+            cordova.raw.plugin('add', testPluginFixturePath).fail(function (err) {
+                expect(err).toBeUndefined();
+            }).then(function () {
+                testPluginInstalledPath = path.join(projectRoot, 'plugins', 'com.plugin.withhooks');
+                shell.chmod('-R', 'ug+x', path.join(testPluginInstalledPath, 'scripts'));
+                done();
+            });
+        });
+    });
+
+    describe('fire method', function() {
+        beforeEach(function() {
+            projectRoot = cordovaUtil.isCordova();
+
+            var options = {
+                verbose: false,
+                platforms: [],
+                options: []
+            };
+
+            options = cordovaUtil.preProcessOptions(options);
+            hookOptions = { projectRoot: project, cordova: options };
+
+            var hooksOrderFile = path.join(projectRoot, 'hooks_order.txt');
+            removeFileIfExists(hooksOrderFile);
+
+            fire = spyOn(HooksRunner.prototype, 'fire').andCallThrough();
+        });
+
+        // helper methods
+        function hooksOrderFileContents(hooksOrderFile) {
+            var order = fs.readFileSync(hooksOrderFile, 'ascii').replace(/\W/gm, ' ');
+
+            var orderArrOriginal = order.split(' ').slice(0);
+
+            function splitNumbers(mixedString) {
+                var re = /\w+/g, match, params = [];
+
+                while (match = re.exec(mixedString)) {
+                    params.push(match[0]);
+                }
+                return params;
+            }
+
+            return splitNumbers(orderArrOriginal).map(function(str) { return parseInt(str, 10); });
+        }
+
+        function hooksOrderFileIsOrdered(hooksOrderFile) {
+            var splitArrOriginal = hooksOrderFileContents(hooksOrderFile);
+            var splitArrSorted = splitArrOriginal.slice(0).sort(function(a, b) { return a - b; });
+
+            return JSON.stringify(splitArrOriginal) === JSON.stringify(splitArrSorted);
+        }
+
+        function backupAppConfig(projectRoot) {
+            shell.cp('-f', path.join(projectRoot, 'config.xml'), path.join(projectRoot, 'configOrig.xml'));
+        }
+
+        function restoreAppConfig(projectRoot) {
+            shell.cp('-f', path.join(projectRoot, 'configOrig.xml'), path.join(projectRoot, 'config.xml'));
+            shell.rm('-rf', path.join(projectRoot, 'configOrig.xml'));
+        }
+
+        function switchToOnlyNonPlatformScriptsAppConfig(projectRoot) {
+            backupAppConfig(projectRoot);
+            shell.cp('-f', path.join(projectRoot, 'configOnlyNonPlatformScripts_' + ext + '.xml'), path.join(projectRoot, 'config.xml'));
+        }
+
+        function switchToOnePlatformScriptsAppConfig(projectRoot) {
+            backupAppConfig(projectRoot);
+            shell.cp('-f', path.join(projectRoot, 'configOnePlatform_' + ext + '.xml'), path.join(projectRoot, 'config.xml'));
+        }
+
+        function switchToTwoPlatformsScriptsAppConfig(projectRoot) {
+            backupAppConfig(projectRoot);
+            shell.cp('-f', path.join(projectRoot, 'configTwoPlatforms_' + ext + '.xml'), path.join(projectRoot, 'config.xml'));
+        }
+
+        function backupPluginConfig() {
+            shell.cp('-f', path.join(testPluginInstalledPath, 'plugin.xml'), path.join(testPluginInstalledPath, 'pluginOrig.xml'));
+        }
+
+        function restorePluginConfig() {
+            shell.cp('-f', path.join(testPluginInstalledPath, 'pluginOrig.xml'), path.join(testPluginInstalledPath, 'plugin.xml'));
+            shell.rm('-rf', path.join(testPluginInstalledPath, 'pluginOrig.xml'));
+        }
+
+        function switchToOnlyNonPlatformScriptsPluginConfig(projectRoot) {
+            backupPluginConfig();
+            shell.cp('-f', path.join(testPluginInstalledPath, 'pluginOnlyNonPlatformScripts_' + ext + '.xml'), path.join(testPluginInstalledPath, 'plugin.xml'));
+        }
+
+        function switchToOnePlatformScriptsPluginConfig(projectRoot) {
+            backupPluginConfig();
+            shell.cp('-f', path.join(testPluginInstalledPath, 'pluginOnePlatform_' + ext + '.xml'), path.join(testPluginInstalledPath, 'plugin.xml'));
+        }
+
+        function switchToTwoPlatformsScriptsPluginConfig(projectRoot) {
+            backupPluginConfig();
+            shell.cp('-f', path.join(testPluginInstalledPath, 'pluginTwoPlatforms_' + ext + '.xml'), path.join(testPluginInstalledPath, 'plugin.xml'));
+        }
+
+        function removeFileIfExists(file) {
+            if (fs.existsSync(file)) {
+                fs.unlinkSync(file);
+            }
+        }
+
+        describe('application hooks', function() {
+            it('should execute hook scripts serially', function (done) {
+                var test_event = 'before_build';
+                var projectRoot = cordovaUtil.isCordova();
+                var hooksOrderFile = path.join(projectRoot, 'hooks_order.txt');
+
+                return hooksRunner.fire(test_event, hookOptions).then(function() {
+                    expect(hooksOrderFile).toExist();
+
+                    expect(hooksOrderFileIsOrdered(hooksOrderFile)).toBe(true);
+                }).fail(function (err) {
+                    expect(err).toBeUndefined();
+                }).then(function () {
+                    done();
+                });
+            });
+
+            it('should execute hook scripts serially from .cordova/hooks/hook_type and hooks/hook_type directories', function (done) {
+                var test_event = 'before_build';
+                var projectRoot = cordovaUtil.isCordova();
+                var hooksOrderFile = path.join(projectRoot, 'hooks_order.txt');
+
+                // using empty platforms list to test only hooks/ directories
+                hookOptions.cordova.platforms = [];
+
+                return hooksRunner.fire(test_event, hookOptions).then(function () {
+                    expect(hooksOrderFile).toExist();
+
+                    expect(hooksOrderFileIsOrdered(hooksOrderFile)).toBe(true);
+                }).fail(function (err) {
+                    expect(err).toBeUndefined();
+                }).then(function () {
+                    done();
+                });
+            });
+
+            it('should execute hook scripts serially from config.xml', function (done) {
+                var test_event = 'before_build';
+                var projectRoot = cordovaUtil.isCordova();
+                var hooksOrderFile = path.join(projectRoot, 'hooks_order.txt');
+
+                switchToOnlyNonPlatformScriptsAppConfig(projectRoot);
+
+                return hooksRunner.fire(test_event, hookOptions).then(function () {
+                    expect(hooksOrderFile).toExist();
+
+                    expect(hooksOrderFileIsOrdered(hooksOrderFile)).toBe(true);
+                }).fail(function (err) {
+                    expect(err).toBeUndefined();
+                }).then(function () {
+                    restoreAppConfig(projectRoot);
+                    done();
+                });
+            });
+
+            it('should execute hook scripts serially from config.xml including platform scripts', function (done) {
+                var test_event = 'before_build';
+                var projectRoot = cordovaUtil.isCordova();
+                var hooksOrderFile = path.join(projectRoot, 'hooks_order.txt');
+
+                switchToOnePlatformScriptsAppConfig(projectRoot);
+
+                return hooksRunner.fire(test_event, hookOptions).then(function () {
+                    expect(hooksOrderFile).toExist();
+
+                    expect(hooksOrderFileIsOrdered(hooksOrderFile)).toBe(true);
+                }).fail(function (err) {
+                    expect(err).toBeUndefined();
+                }).then(function () {
+                    restoreAppConfig(projectRoot);
+                    done();
+                });
+            });
+
+            it('should filter hook scripts from config.xml by platform', function (done) {
+                var test_event = 'before_build';
+                var projectRoot = cordovaUtil.isCordova();
+                var hooksOrderFile = path.join(projectRoot, 'hooks_order.txt');
+
+                switchToTwoPlatformsScriptsAppConfig(projectRoot);
+
+                hookOptions.cordova.platforms = ['android'];
+
+                return hooksRunner.fire(test_event, hookOptions).then(function () {
+                    expect(hooksOrderFile).toExist();
+
+                    expect(hooksOrderFileIsOrdered(hooksOrderFile)).toBe(true);
+
+                    var baseScriptResults = [1, 2, 3, 4, 5, 6, 7, 8, 9];
+                    var androidPlatformScriptsResults = [14, 15];
+
+                    expect(JSON.stringify(hooksOrderFileContents(hooksOrderFile)) ===
+                        JSON.stringify(baseScriptResults.slice(0).concat(androidPlatformScriptsResults))).toBe(true);
+                }).fail(function (err) {
+                    expect(err).toBeUndefined();
+                }).then(function () {
+                    restoreAppConfig(projectRoot);
+                    done();
+                });
+            });
+        });
+
+        describe('plugin hooks', function() {
+            it('should execute hook scripts serially from plugin.xml', function (done) {
+                var test_event = 'before_build';
+                var projectRoot = cordovaUtil.isCordova();
+                var hooksOrderFile = path.join(projectRoot, 'hooks_order.txt');
+
+                switchToOnlyNonPlatformScriptsPluginConfig();
+
+                return hooksRunner.fire(test_event, hookOptions).then(function () {
+                    expect(hooksOrderFile).toExist();
+
+                    expect(hooksOrderFileIsOrdered(hooksOrderFile)).toBe(true);
+                }).fail(function (err) {
+                    expect(err).toBeUndefined();
+                }).then(function () {
+                    restorePluginConfig(projectRoot);
+                    done();
+                });
+            });
+
+            it('should execute hook scripts serially from plugin.xml including platform scripts', function (done) {
+                var test_event = 'before_build';
+                var projectRoot = cordovaUtil.isCordova();
+                var hooksOrderFile = path.join(projectRoot, 'hooks_order.txt');
+
+                switchToOnePlatformScriptsPluginConfig();
+
+                return hooksRunner.fire(test_event, hookOptions).then(function () {
+                    expect(hooksOrderFile).toExist();
+
+                    expect(hooksOrderFileIsOrdered(hooksOrderFile)).toBe(true);
+                }).fail(function (err) {
+                    expect(err).toBeUndefined();
+                }).then(function () {
+                    restorePluginConfig(projectRoot);
+                    done();
+                });
+            });
+
+            it('should filter hook scripts from plugin.xml by platform', function (done) {
+                var test_event = 'before_build';
+                var projectRoot = cordovaUtil.isCordova();
+                var hooksOrderFile = path.join(projectRoot, 'hooks_order.txt');
+
+                switchToTwoPlatformsScriptsPluginConfig(projectRoot);
+
+                hookOptions.cordova.platforms = ['android'];
+
+                return hooksRunner.fire(test_event, hookOptions).then(function () {
+                    expect(hooksOrderFile).toExist();
+
+                    expect(hooksOrderFileIsOrdered(hooksOrderFile)).toBe(true);
+
+                    var baseScriptResults = [1, 2, 3, 4, 5, 6, 7, 21, 22];
+                    var androidPlatformScriptsResults = [26];
+
+                    expect(JSON.stringify(hooksOrderFileContents(hooksOrderFile)) ===
+                        JSON.stringify(baseScriptResults.slice(0).concat(androidPlatformScriptsResults))).toBe(true);
+                }).fail(function (err) {
+                    expect(err).toBeUndefined();
+                }).then(function () {
+                    restorePluginConfig(projectRoot);
+                    done();
+                });
+            });
+
+            it('should run before_plugin_uninstall, before_plugin_install, after_plugin_install hooks for a plugin being installed with correct opts.plugin context', function (done) {
+                var test_event = 'before_plugin_install';
+                var projectRoot = cordovaUtil.isCordova();
+
+                // remove plugin
+                cordova.raw.plugin('rm', 'com.plugin.withhooks').fail(function (err) {
+                    expect(err).toBeUndefined();
+                }).then(function () {
+                    cordova.raw.plugin('add', testPluginFixturePath).fail(function (err) {
+                        expect(err).toBeUndefined();
+                    }).then(function () {
+                        testPluginInstalledPath = path.join(projectRoot, 'plugins', 'com.plugin.withhooks');
+                        shell.chmod('-R', 'ug+x', path.join(testPluginInstalledPath, 'scripts'));
+
+                        var pluginInfo = new PluginInfo.PluginInfo(testPluginInstalledPath);
+
+                        var cordovaVersion = require('../package').version;
+
+                        var androidPluginOpts = {
+                            cordova: {
+                                platforms: [ 'android' ],
+                                plugins: ['com.plugin.withhooks'],
+                                version: cordovaVersion
+                            },
+                            plugin: {
+                                id: 'com.plugin.withhooks',
+                                pluginInfo: pluginInfo,
+                                platform: 'android',
+                                dir: testPluginInstalledPath
+                            },
+                            projectRoot: projectRoot
+                        };
+                        // Delete unique ids to allow comparing PluginInfo
+                        delete androidPluginOpts.plugin.pluginInfo._et;
+
+                        fire.calls.forEach(function(call) {
+                            if(call.args[1] && call.args[1].plugin) {
+                                // Delete unique ids to allow comparing PluginInfo
+                                delete call.args[1].plugin.pluginInfo._et;
+                            }
+
+                            if(call.args[0] == 'before_plugin_uninstall' || call.args[0] == 'before_plugin_install'
+                                || call.args[0] == 'after_plugin_install') {
+                                if(call.args[1] && call.args[1].plugin) {
+                                    if(call.args[1].plugin.platform == 'android') {
+                                        expect(JSON.stringify(androidPluginOpts)
+                                            === JSON.stringify(call.args[1])).toBe(true);
+                                    }
+                                }
+                            }
+                        });
+                    }).fail(function (err) {
+                        expect(err).toBeUndefined();
+                    }).fin(done);
+                });
+            });
+        });
+
+        describe('module-level hooks (event handlers)', function() {
+            var handler = jasmine.createSpy().andReturn(Q());
+            var test_event = 'before_build';
+
+            afterEach(function () {
+                cordova.removeAllListeners(test_event);
+                handler.reset();
+            });
+
+            it('should fire handlers using cordova.on', function(done) {
+                cordova.on(test_event, handler);
+                hooksRunner.fire(test_event, hookOptions).then(function () {
+                    expect(handler).toHaveBeenCalled();
+                }).fail(function (err) {
+                    expect(err).not.toBeDefined();
+                }).fin(done);
+            });
+
+            it('should pass the project root folder as parameter into the module-level handlers', function (done) {
+                cordova.on(test_event, handler);
+                hooksRunner.fire(test_event, hookOptions).then(function () {
+                    expect(handler).toHaveBeenCalledWith(hookOptions);
+                }).fail(function (err) {
+                    console.log(err);
+                    expect(err).not.toBeDefined();
+                }).fin(done);
+            });
+
+            it('should be able to stop listening to events using cordova.off', function(done) {
+                cordova.on(test_event, handler);
+                cordova.off(test_event, handler);
+                hooksRunner.fire(test_event, hookOptions).then(function () {
+                    expect(handler).not.toHaveBeenCalled();
+                }).fail(function (err) {
+                    console.log(err);
+                    expect(err).toBeUndefined();
+                }).fin(done);
+            });
+
+            it('should execute event listeners serially', function(done) {
+                var h1_fired = false;
+                var h1 = function() {
+                    expect(h2_fired).toBe(false);
+                    // Delay 100 ms here to check that h2 is not executed until after
+                    // the promise returned by h1 is resolved.
+                    var q = Q.delay(100).then(function() {
+                        h1_fired = true;
+                    });
+                    return q;
+                };
+                var h2_fired = false;
+                var h2 = function() {
+                    h2_fired = true;
+                    expect(h1_fired).toBe(true);
+                    return Q();
+                };
+
+                cordova.on(test_event, h1);
+                cordova.on(test_event, h2);
+
+                return hooksRunner.fire(test_event, hookOptions).then(function() {
+                    expect(h1_fired).toBe(true);
+                    expect(h2_fired).toBe(true);
+                }).fail(function(err) {
+                    expect(err).toBeUndefined();
+                }).then(function() {
+                    cordova.removeAllListeners(test_event);
+                    done();
+                });
+            });
+
+            it('should allow for hook to opt into asynchronous execution and block further hooks from firing using the done callback', function(done) {
+                var h1_fired = false;
+                var h1 = function () {
+                    h1_fired = true;
+                    expect(h2_fired).toBe(false);
+                    return Q();
+                };
+                var h2_fired = false;
+                var h2 = function () {
+                    h2_fired = true;
+                    expect(h1_fired).toBe(true);
+                    return Q();
+                };
+
+                cordova.on(test_event, h1);
+                cordova.on(test_event, h2);
+                hooksRunner.fire(test_event, hookOptions).then(function() {
+                    expect(h1_fired).toBe(true);
+                    expect(h2_fired).toBe(true);
+                    done();
+                });
+            });
+
+            it('should pass data object that fire calls into async handlers', function(done) {
+                var async = function (opts) {
+                    expect(opts).toEqual(hookOptions);
+                    return Q();
+                };
+                cordova.on(test_event, async);
+                hooksRunner.fire(test_event, hookOptions).then(function () {
+                    done();
+                });
+            });
+
+            it('should pass data object that fire calls into sync handlers', function(done) {
+                var async = function (opts) {
+                    expect(opts).toEqual(hookOptions);
+                };
+                cordova.on(test_event, async);
+                hooksRunner.fire(test_event, hookOptions).fin(done);
+            });
+
+            it('should error if any script exits with non-zero code', function(done) {
+                hooksRunner.fire('fail', hookOptions).then(function () {
+                    expect('the call').toBe('a failure');
+                }, function (err) {
+                    expect(err).toBeDefined();
+                }).fin(done);
+            });
+        });
+
+        it('should not error if the hook is unrecognized', function(done) {
+            hooksRunner.fire('CLEAN YOUR SHORTS GODDAMNIT LIKE A BIG BOY!', hookOptions).fail(function (err) {
+                expect('Call with unrecognized hook ').toBe('successful.\n' + err);
+            }).fin(done);
+        });
+    });
+});
+
+describe('cleanup', function() {
+// Cleanup. Must be the last spec. Is there a better place for final cleanup in Jasmine?
+    it('should not fail during cleanup', function () {
+        process.chdir(path.join(__dirname, '..'));  // Non e2e tests assume CWD is repo root.
+        if (ext == 'sh') {
+            shell.rm('-rf', tmpDir);
+        } else { // Windows:
+            // For some mysterious reason, both shell.rm and RMDIR /S /Q won't
+            // delete the dir on Windows, but they do remove the files leaving
+            // only folders. But the dir is removed just fine by
+            // shell.rm('-rf', tmpDir) at the top of this file with the next
+            // invocation of this test. The benefit of RMDIR /S /Q is that it
+            // doesn't print warnings like shell.rmdir() that look like this:
+            // rm: could not remove directory (code ENOTEMPTY): C:\Users\...
+            var cmd = 'RMDIR /S /Q ' + tmpDir;
+            child_process.exec(cmd);
+        }
+    });
+});
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/eed41399/cordova-lib/spec-cordova/build.spec.js
----------------------------------------------------------------------
diff --git a/cordova-lib/spec-cordova/build.spec.js b/cordova-lib/spec-cordova/build.spec.js
index 28127de..9528942 100644
--- a/cordova-lib/spec-cordova/build.spec.js
+++ b/cordova-lib/spec-cordova/build.spec.js
@@ -21,7 +21,7 @@ var cordova = require('../src/cordova/cordova'),
     shell = require('shelljs'),
     path = require('path'),
     fs = require('fs'),
-    hooker = require('../src/cordova/hooker'),
+    HooksRunner = require('../src/hooks/HooksRunner'),
     Q = require('q'),
     util = require('../src/cordova/util');
 
@@ -49,7 +49,7 @@ describe('build command', function() {
         is_cordova = spyOn(util, 'isCordova').andReturn(project_dir);
         cd_project_root = spyOn(util, 'cdProjectRoot').andReturn(project_dir);
         list_platforms = spyOn(util, 'listPlatforms').andReturn(supported_platforms);
-        fire = spyOn(hooker.prototype, 'fire').andReturn(Q());
+        fire = spyOn(HooksRunner.prototype, 'fire').andReturn(Q());
         prepare_spy = spyOn(cordova.raw, 'prepare').andReturn(Q());
         compile_spy = spyOn(cordova.raw, 'compile').andReturn(Q());
     });

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/eed41399/cordova-lib/spec-cordova/compile.spec.js
----------------------------------------------------------------------
diff --git a/cordova-lib/spec-cordova/compile.spec.js b/cordova-lib/spec-cordova/compile.spec.js
index a1dadb3..f78d0c2 100644
--- a/cordova-lib/spec-cordova/compile.spec.js
+++ b/cordova-lib/spec-cordova/compile.spec.js
@@ -20,7 +20,7 @@ var cordova = require('../src/cordova/cordova'),
     platforms = require('../src/cordova/platforms'),
     path = require('path'),
     fs = require('fs'),
-    hooker = require('../src/cordova/hooker'),
+    HooksRunner = require('../src/hooks/HooksRunner'),
     superspawn = require('../src/cordova/superspawn'),
     util = require('../src/cordova/util'),
     Q = require('q'),
@@ -45,7 +45,7 @@ describe('compile command', function() {
         is_cordova = spyOn(util, 'isCordova').andReturn(project_dir);
         cd_project_root = spyOn(util, 'cdProjectRoot').andReturn(project_dir);
         list_platforms = spyOn(util, 'listPlatforms').andReturn(supported_platforms);
-        fire = spyOn(hooker.prototype, 'fire').andReturn(Q());
+        fire = spyOn(HooksRunner.prototype, 'fire').andReturn(Q());
         spyOn(superspawn, 'spawn').andCallFake(function() { return Q() });
     });
     describe('failure', function() {

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/eed41399/cordova-lib/spec-cordova/emulate.spec.js
----------------------------------------------------------------------
diff --git a/cordova-lib/spec-cordova/emulate.spec.js b/cordova-lib/spec-cordova/emulate.spec.js
index 10f0d86..f770400 100644
--- a/cordova-lib/spec-cordova/emulate.spec.js
+++ b/cordova-lib/spec-cordova/emulate.spec.js
@@ -21,7 +21,7 @@ var cordova = require('../src/cordova/cordova'),
     superspawn = require('../src/cordova/superspawn'),
     path = require('path'),
     fs = require('fs'),
-    hooker = require('../src/cordova/hooker'),
+    HooksRunner = require('../src/hooks/HooksRunner'),
     Q = require('q'),
     util = require('../src/cordova/util'),
     os = require('os');
@@ -45,7 +45,7 @@ describe('emulate command', function() {
         is_cordova = spyOn(util, 'isCordova').andReturn(project_dir);
         cd_project_root = spyOn(util, 'cdProjectRoot').andReturn(project_dir);
         list_platforms = spyOn(util, 'listPlatforms').andReturn(supported_platforms);
-        fire = spyOn(hooker.prototype, 'fire').andReturn(Q());
+        fire = spyOn(HooksRunner.prototype, 'fire').andReturn(Q());
         prepare_spy = spyOn(cordova.raw, 'prepare').andReturn(Q());
         spyOn(superspawn, 'spawn').andCallFake(Q);
     });

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/eed41399/cordova-lib/spec-cordova/fixtures/plugins/com.plugin.withhooks/plugin.xml
----------------------------------------------------------------------
diff --git a/cordova-lib/spec-cordova/fixtures/plugins/com.plugin.withhooks/plugin.xml b/cordova-lib/spec-cordova/fixtures/plugins/com.plugin.withhooks/plugin.xml
new file mode 100644
index 0000000..8e80560
--- /dev/null
+++ b/cordova-lib/spec-cordova/fixtures/plugins/com.plugin.withhooks/plugin.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<plugin xmlns="http://apache.org/cordova/ns/plugins/1.0"
+        xmlns:android="http://schemas.android.com/apk/res/android"
+        id="com.plugin.withhooks"
+        version="0.0.1">
+    <name>Plugin with hooks</name>
+</plugin>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/eed41399/cordova-lib/spec-cordova/fixtures/plugins/com.plugin.withhooks/pluginOnePlatform_bat.xml
----------------------------------------------------------------------
diff --git a/cordova-lib/spec-cordova/fixtures/plugins/com.plugin.withhooks/pluginOnePlatform_bat.xml b/cordova-lib/spec-cordova/fixtures/plugins/com.plugin.withhooks/pluginOnePlatform_bat.xml
new file mode 100644
index 0000000..e1d6a0c
--- /dev/null
+++ b/cordova-lib/spec-cordova/fixtures/plugins/com.plugin.withhooks/pluginOnePlatform_bat.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<plugin xmlns="http://apache.org/cordova/ns/plugins/1.0"
+        xmlns:android="http://schemas.android.com/apk/res/android"
+        id="com.plugin.withhooks"
+        version="0.0.1">
+    <name>Plugin with hooks</name>
+
+    <hook type="before_plugin_install" src="scripts/beforeInstall01.js" />
+    <hook type="before_plugin_install" src="scripts/beforeInstall2.js" />
+    <hook type="before_plugin_install" src="scripts/beforeInstall.bat" />
+    <hook type="before_plugin_uninstall" src="scripts/beforeUninstall.js" />
+    <hook type="before_build" src="scripts/beforeBuild.js" />
+    <hook type="before_build" src="scripts/beforeBuild.bat" />
+
+    <platform name="android">
+        <hook type="before_plugin_install" src="scripts/android/androidBeforeInstall.js" />
+        <hook type="before_build" src="scripts/android/androidBeforeBuild.js" />
+    </platform>
+</plugin>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/eed41399/cordova-lib/spec-cordova/fixtures/plugins/com.plugin.withhooks/pluginOnePlatform_sh.xml
----------------------------------------------------------------------
diff --git a/cordova-lib/spec-cordova/fixtures/plugins/com.plugin.withhooks/pluginOnePlatform_sh.xml b/cordova-lib/spec-cordova/fixtures/plugins/com.plugin.withhooks/pluginOnePlatform_sh.xml
new file mode 100644
index 0000000..fef675a
--- /dev/null
+++ b/cordova-lib/spec-cordova/fixtures/plugins/com.plugin.withhooks/pluginOnePlatform_sh.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<plugin xmlns="http://apache.org/cordova/ns/plugins/1.0"
+        xmlns:android="http://schemas.android.com/apk/res/android"
+        id="com.plugin.withhooks"
+        version="0.0.1">
+    <name>Plugin with hooks</name>
+
+    <hook type="before_plugin_install" src="scripts/beforeInstall01.js" />
+    <hook type="before_plugin_install" src="scripts/beforeInstall2.js" />
+    <hook type="before_plugin_install" src="scripts/beforeInstall.sh" />
+    <hook type="before_plugin_uninstall" src="scripts/beforeUninstall.js" />
+    <hook type="before_build" src="scripts/beforeBuild.js" />
+    <hook type="before_build" src="scripts/beforeBuild.sh" />
+
+    <platform name="android">
+        <hook type="before_plugin_install" src="scripts/android/androidBeforeInstall.js" />
+        <hook type="before_build" src="scripts/android/androidBeforeBuild.js" />
+    </platform>
+</plugin>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/eed41399/cordova-lib/spec-cordova/fixtures/plugins/com.plugin.withhooks/pluginOnlyNonPlatformScripts_bat.xml
----------------------------------------------------------------------
diff --git a/cordova-lib/spec-cordova/fixtures/plugins/com.plugin.withhooks/pluginOnlyNonPlatformScripts_bat.xml b/cordova-lib/spec-cordova/fixtures/plugins/com.plugin.withhooks/pluginOnlyNonPlatformScripts_bat.xml
new file mode 100644
index 0000000..fcbdb61
--- /dev/null
+++ b/cordova-lib/spec-cordova/fixtures/plugins/com.plugin.withhooks/pluginOnlyNonPlatformScripts_bat.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<plugin xmlns="http://apache.org/cordova/ns/plugins/1.0"
+        xmlns:android="http://schemas.android.com/apk/res/android"
+        id="com.plugin.withhooks"
+        version="0.0.1">
+    <name>Plugin with hooks</name>
+
+    <hook type="before_plugin_install" src="scripts/beforeInstall01.js" />
+    <hook type="before_plugin_install" src="scripts/beforeInstall2.js" />
+    <hook type="before_plugin_install" src="scripts/beforeInstall.bat" />
+    <hook type="before_plugin_uninstall" src="scripts/beforeUninstall.js" />
+    <hook type="before_build" src="scripts/beforeBuild.js" />
+    <hook type="before_build" src="scripts/beforeBuild.bat" />
+</plugin>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/eed41399/cordova-lib/spec-cordova/fixtures/plugins/com.plugin.withhooks/pluginOnlyNonPlatformScripts_sh.xml
----------------------------------------------------------------------
diff --git a/cordova-lib/spec-cordova/fixtures/plugins/com.plugin.withhooks/pluginOnlyNonPlatformScripts_sh.xml b/cordova-lib/spec-cordova/fixtures/plugins/com.plugin.withhooks/pluginOnlyNonPlatformScripts_sh.xml
new file mode 100644
index 0000000..7593ffe
--- /dev/null
+++ b/cordova-lib/spec-cordova/fixtures/plugins/com.plugin.withhooks/pluginOnlyNonPlatformScripts_sh.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<plugin xmlns="http://apache.org/cordova/ns/plugins/1.0"
+        xmlns:android="http://schemas.android.com/apk/res/android"
+        id="com.plugin.withhooks"
+        version="0.0.1">
+    <name>Plugin with hooks</name>
+
+    <hook type="before_plugin_install" src="scripts/beforeInstall01.js" />
+    <hook type="before_plugin_install" src="scripts/beforeInstall2.js" />
+    <hook type="before_plugin_install" src="scripts/beforeInstall.sh" />
+    <hook type="before_plugin_uninstall" src="scripts/beforeUninstall.js" />
+    <hook type="before_build" src="scripts/beforeBuild.js" />
+    <hook type="before_build" src="scripts/beforeBuild.sh" />
+</plugin>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/eed41399/cordova-lib/spec-cordova/fixtures/plugins/com.plugin.withhooks/pluginTwoPlatforms_bat.xml
----------------------------------------------------------------------
diff --git a/cordova-lib/spec-cordova/fixtures/plugins/com.plugin.withhooks/pluginTwoPlatforms_bat.xml b/cordova-lib/spec-cordova/fixtures/plugins/com.plugin.withhooks/pluginTwoPlatforms_bat.xml
new file mode 100644
index 0000000..8fd6d38
--- /dev/null
+++ b/cordova-lib/spec-cordova/fixtures/plugins/com.plugin.withhooks/pluginTwoPlatforms_bat.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<plugin xmlns="http://apache.org/cordova/ns/plugins/1.0"
+        xmlns:android="http://schemas.android.com/apk/res/android"
+        id="com.plugin.withhooks"
+        version="0.0.1">
+    <name>Plugin with hooks</name>
+
+    <hook type="before_plugin_install" src="scripts/beforeInstall01.js" />
+    <hook type="before_plugin_install" src="scripts/beforeInstall2.js" />
+    <hook type="before_plugin_install" src="scripts/beforeInstall.bat" />
+    <hook type="before_plugin_uninstall" src="scripts/beforeUninstall.js" />
+    <hook type="before_build" src="scripts/beforeBuild.js" />
+    <hook type="before_build" src="scripts/beforeBuild.bat" />
+
+    <platform name="windows">
+        <hook type="before_plugin_install" src="scripts/windows/windowsBeforeInstall.js" />
+        <hook type="before_build" src="scripts/windows/windowsBeforeBuild.js" />
+    </platform>
+
+    <platform name="android">
+        <hook type="before_plugin_install" src="scripts/android/androidBeforeInstall.js" />
+        <hook type="before_build" src="scripts/android/androidBeforeBuild.js" />
+    </platform>
+</plugin>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/eed41399/cordova-lib/spec-cordova/fixtures/plugins/com.plugin.withhooks/pluginTwoPlatforms_sh.xml
----------------------------------------------------------------------
diff --git a/cordova-lib/spec-cordova/fixtures/plugins/com.plugin.withhooks/pluginTwoPlatforms_sh.xml b/cordova-lib/spec-cordova/fixtures/plugins/com.plugin.withhooks/pluginTwoPlatforms_sh.xml
new file mode 100644
index 0000000..6a4e11d
--- /dev/null
+++ b/cordova-lib/spec-cordova/fixtures/plugins/com.plugin.withhooks/pluginTwoPlatforms_sh.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<plugin xmlns="http://apache.org/cordova/ns/plugins/1.0"
+        xmlns:android="http://schemas.android.com/apk/res/android"
+        id="com.plugin.withhooks"
+        version="0.0.1">
+    <name>Plugin with hooks</name>
+
+    <hook type="before_plugin_install" src="scripts/beforeInstall01.js" />
+    <hook type="before_plugin_install" src="scripts/beforeInstall2.js" />
+    <hook type="before_plugin_install" src="scripts/beforeInstall.sh" />
+    <hook type="before_plugin_uninstall" src="scripts/beforeUninstall.js" />
+    <hook type="before_build" src="scripts/beforeBuild.js" />
+    <hook type="before_build" src="scripts/beforeBuild.sh" />
+
+    <platform name="windows">
+        <hook type="before_plugin_install" src="scripts/windows/windowsBeforeInstall.js" />
+        <hook type="before_build" src="scripts/windows/windowsBeforeBuild.js" />
+    </platform>
+
+    <platform name="android">
+        <hook type="before_plugin_install" src="scripts/android/androidBeforeInstall.js" />
+        <hook type="before_build" src="scripts/android/androidBeforeBuild.js" />
+    </platform>
+</plugin>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/eed41399/cordova-lib/spec-cordova/fixtures/plugins/com.plugin.withhooks/scripts/android/androidBeforeBuild.js
----------------------------------------------------------------------
diff --git a/cordova-lib/spec-cordova/fixtures/plugins/com.plugin.withhooks/scripts/android/androidBeforeBuild.js b/cordova-lib/spec-cordova/fixtures/plugins/com.plugin.withhooks/scripts/android/androidBeforeBuild.js
new file mode 100644
index 0000000..4203c17
--- /dev/null
+++ b/cordova-lib/spec-cordova/fixtures/plugins/com.plugin.withhooks/scripts/android/androidBeforeBuild.js
@@ -0,0 +1,4 @@
+module.exports = function(context) {
+    var orderLogger = require(require('path').join(context.opts.projectRoot, 'scripts', 'orderLogger'));
+    orderLogger.logOrder('26', context);
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/eed41399/cordova-lib/spec-cordova/fixtures/plugins/com.plugin.withhooks/scripts/android/androidBeforeInstall.js
----------------------------------------------------------------------
diff --git a/cordova-lib/spec-cordova/fixtures/plugins/com.plugin.withhooks/scripts/android/androidBeforeInstall.js b/cordova-lib/spec-cordova/fixtures/plugins/com.plugin.withhooks/scripts/android/androidBeforeInstall.js
new file mode 100644
index 0000000..96ac175
--- /dev/null
+++ b/cordova-lib/spec-cordova/fixtures/plugins/com.plugin.withhooks/scripts/android/androidBeforeInstall.js
@@ -0,0 +1,4 @@
+module.exports = function(context) {
+    var orderLogger = require(require('path').join(context.opts.projectRoot, 'scripts', 'orderLogger'));
+    orderLogger.logOrder('25', context);
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/eed41399/cordova-lib/spec-cordova/fixtures/plugins/com.plugin.withhooks/scripts/beforeBuild.bat
----------------------------------------------------------------------
diff --git a/cordova-lib/spec-cordova/fixtures/plugins/com.plugin.withhooks/scripts/beforeBuild.bat b/cordova-lib/spec-cordova/fixtures/plugins/com.plugin.withhooks/scripts/beforeBuild.bat
new file mode 100644
index 0000000..768a404
--- /dev/null
+++ b/cordova-lib/spec-cordova/fixtures/plugins/com.plugin.withhooks/scripts/beforeBuild.bat
@@ -0,0 +1,2 @@
+@echo off
+echo 22 >> hooks_order.txt
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/eed41399/cordova-lib/spec-cordova/fixtures/plugins/com.plugin.withhooks/scripts/beforeBuild.js
----------------------------------------------------------------------
diff --git a/cordova-lib/spec-cordova/fixtures/plugins/com.plugin.withhooks/scripts/beforeBuild.js b/cordova-lib/spec-cordova/fixtures/plugins/com.plugin.withhooks/scripts/beforeBuild.js
new file mode 100644
index 0000000..1f40574
--- /dev/null
+++ b/cordova-lib/spec-cordova/fixtures/plugins/com.plugin.withhooks/scripts/beforeBuild.js
@@ -0,0 +1,4 @@
+module.exports = function(context) {
+    var orderLogger = require(require('path').join(context.opts.projectRoot, 'scripts', 'orderLogger'));
+    orderLogger.logOrder('21', context);
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/eed41399/cordova-lib/spec-cordova/fixtures/plugins/com.plugin.withhooks/scripts/beforeBuild.sh
----------------------------------------------------------------------
diff --git a/cordova-lib/spec-cordova/fixtures/plugins/com.plugin.withhooks/scripts/beforeBuild.sh b/cordova-lib/spec-cordova/fixtures/plugins/com.plugin.withhooks/scripts/beforeBuild.sh
new file mode 100644
index 0000000..5698c11
--- /dev/null
+++ b/cordova-lib/spec-cordova/fixtures/plugins/com.plugin.withhooks/scripts/beforeBuild.sh
@@ -0,0 +1 @@
+echo 22 >> hooks_order.txt
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/eed41399/cordova-lib/spec-cordova/fixtures/plugins/com.plugin.withhooks/scripts/beforeInstall.bat
----------------------------------------------------------------------
diff --git a/cordova-lib/spec-cordova/fixtures/plugins/com.plugin.withhooks/scripts/beforeInstall.bat b/cordova-lib/spec-cordova/fixtures/plugins/com.plugin.withhooks/scripts/beforeInstall.bat
new file mode 100644
index 0000000..7e6b0df
--- /dev/null
+++ b/cordova-lib/spec-cordova/fixtures/plugins/com.plugin.withhooks/scripts/beforeInstall.bat
@@ -0,0 +1,2 @@
+@echo off
+echo 19 >> hooks_order.txt
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/eed41399/cordova-lib/spec-cordova/fixtures/plugins/com.plugin.withhooks/scripts/beforeInstall.sh
----------------------------------------------------------------------
diff --git a/cordova-lib/spec-cordova/fixtures/plugins/com.plugin.withhooks/scripts/beforeInstall.sh b/cordova-lib/spec-cordova/fixtures/plugins/com.plugin.withhooks/scripts/beforeInstall.sh
new file mode 100644
index 0000000..2688501
--- /dev/null
+++ b/cordova-lib/spec-cordova/fixtures/plugins/com.plugin.withhooks/scripts/beforeInstall.sh
@@ -0,0 +1 @@
+echo 19 >> hooks_order.txt
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/eed41399/cordova-lib/spec-cordova/fixtures/plugins/com.plugin.withhooks/scripts/beforeInstall01.js
----------------------------------------------------------------------
diff --git a/cordova-lib/spec-cordova/fixtures/plugins/com.plugin.withhooks/scripts/beforeInstall01.js b/cordova-lib/spec-cordova/fixtures/plugins/com.plugin.withhooks/scripts/beforeInstall01.js
new file mode 100644
index 0000000..3d644b2
--- /dev/null
+++ b/cordova-lib/spec-cordova/fixtures/plugins/com.plugin.withhooks/scripts/beforeInstall01.js
@@ -0,0 +1,4 @@
+module.exports = function(context) {
+    var orderLogger = require(require('path').join(context.opts.projectRoot, 'scripts', 'orderLogger'));
+    orderLogger.logOrder('17', context);
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/eed41399/cordova-lib/spec-cordova/fixtures/plugins/com.plugin.withhooks/scripts/beforeInstall2.js
----------------------------------------------------------------------
diff --git a/cordova-lib/spec-cordova/fixtures/plugins/com.plugin.withhooks/scripts/beforeInstall2.js b/cordova-lib/spec-cordova/fixtures/plugins/com.plugin.withhooks/scripts/beforeInstall2.js
new file mode 100644
index 0000000..b49f65c
--- /dev/null
+++ b/cordova-lib/spec-cordova/fixtures/plugins/com.plugin.withhooks/scripts/beforeInstall2.js
@@ -0,0 +1,4 @@
+module.exports = function(context) {
+    var orderLogger = require(require('path').join(context.opts.projectRoot, 'scripts', 'orderLogger'));
+    orderLogger.logOrder('18', context);
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/eed41399/cordova-lib/spec-cordova/fixtures/plugins/com.plugin.withhooks/scripts/beforeUninstall.js
----------------------------------------------------------------------
diff --git a/cordova-lib/spec-cordova/fixtures/plugins/com.plugin.withhooks/scripts/beforeUninstall.js b/cordova-lib/spec-cordova/fixtures/plugins/com.plugin.withhooks/scripts/beforeUninstall.js
new file mode 100644
index 0000000..2b05f62
--- /dev/null
+++ b/cordova-lib/spec-cordova/fixtures/plugins/com.plugin.withhooks/scripts/beforeUninstall.js
@@ -0,0 +1,4 @@
+module.exports = function(context) {
+    var orderLogger = require(require('path').join(context.opts.projectRoot, 'scripts', 'orderLogger'));
+    orderLogger.logOrder('20', context);
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/eed41399/cordova-lib/spec-cordova/fixtures/plugins/com.plugin.withhooks/scripts/windows/windowsBeforeBuild.js
----------------------------------------------------------------------
diff --git a/cordova-lib/spec-cordova/fixtures/plugins/com.plugin.withhooks/scripts/windows/windowsBeforeBuild.js b/cordova-lib/spec-cordova/fixtures/plugins/com.plugin.withhooks/scripts/windows/windowsBeforeBuild.js
new file mode 100644
index 0000000..7729968
--- /dev/null
+++ b/cordova-lib/spec-cordova/fixtures/plugins/com.plugin.withhooks/scripts/windows/windowsBeforeBuild.js
@@ -0,0 +1,4 @@
+module.exports = function(context) {
+    var orderLogger = require(require('path').join(context.opts.projectRoot, 'scripts', 'orderLogger'));
+    orderLogger.logOrder('24', context);
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/eed41399/cordova-lib/spec-cordova/fixtures/plugins/com.plugin.withhooks/scripts/windows/windowsBeforeInstall.js
----------------------------------------------------------------------
diff --git a/cordova-lib/spec-cordova/fixtures/plugins/com.plugin.withhooks/scripts/windows/windowsBeforeInstall.js b/cordova-lib/spec-cordova/fixtures/plugins/com.plugin.withhooks/scripts/windows/windowsBeforeInstall.js
new file mode 100644
index 0000000..db4cbe0
--- /dev/null
+++ b/cordova-lib/spec-cordova/fixtures/plugins/com.plugin.withhooks/scripts/windows/windowsBeforeInstall.js
@@ -0,0 +1,4 @@
+module.exports = function(context) {
+    var orderLogger = require(require('path').join(context.opts.projectRoot, 'scripts', 'orderLogger'));
+    orderLogger.logOrder('23', context);
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/eed41399/cordova-lib/spec-cordova/fixtures/projWithHooks/.cordova/config.json
----------------------------------------------------------------------
diff --git a/cordova-lib/spec-cordova/fixtures/projWithHooks/.cordova/config.json b/cordova-lib/spec-cordova/fixtures/projWithHooks/.cordova/config.json
new file mode 100644
index 0000000..4f52ca7
--- /dev/null
+++ b/cordova-lib/spec-cordova/fixtures/projWithHooks/.cordova/config.json
@@ -0,0 +1,22 @@
+{
+  "id": "org.testing",
+  "name":"TestBase",
+  "lib": {
+    "android": {
+      "url": "/some/junk/path",
+      "version": "dev",
+      "id": "cordova-android-dev"
+    },
+    "ios": {
+      "url": "/some/junk/path",
+      "version": "dev",
+      "id": "cordova-ios-dev"
+    },
+    "wp8": {
+      "url": "/some/junk/path",
+      "version": "dev",
+      "id": "cordova-wp8-dev"
+    }
+  }
+}
+

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/eed41399/cordova-lib/spec-cordova/fixtures/projWithHooks/.cordova/hooks/before_build/hookScriptDot03.js
----------------------------------------------------------------------
diff --git a/cordova-lib/spec-cordova/fixtures/projWithHooks/.cordova/hooks/before_build/hookScriptDot03.js b/cordova-lib/spec-cordova/fixtures/projWithHooks/.cordova/hooks/before_build/hookScriptDot03.js
new file mode 100644
index 0000000..5e69a7f
--- /dev/null
+++ b/cordova-lib/spec-cordova/fixtures/projWithHooks/.cordova/hooks/before_build/hookScriptDot03.js
@@ -0,0 +1,4 @@
+#!/usr/bin/env node
+var path = require('path');
+var orderLogger = require(path.join(process.argv.slice(2)[0], 'scripts', 'orderLogger'));
+orderLogger.logOrder('01');
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/eed41399/cordova-lib/spec-cordova/fixtures/projWithHooks/.cordova/hooks/before_build/hookScriptDot1.js
----------------------------------------------------------------------
diff --git a/cordova-lib/spec-cordova/fixtures/projWithHooks/.cordova/hooks/before_build/hookScriptDot1.js b/cordova-lib/spec-cordova/fixtures/projWithHooks/.cordova/hooks/before_build/hookScriptDot1.js
new file mode 100644
index 0000000..2e8d8d5
--- /dev/null
+++ b/cordova-lib/spec-cordova/fixtures/projWithHooks/.cordova/hooks/before_build/hookScriptDot1.js
@@ -0,0 +1,4 @@
+#!/usr/bin/env node
+var path = require('path');
+var orderLogger = require(path.join(process.argv.slice(2)[0], 'scripts', 'orderLogger'));
+orderLogger.logOrder('02');
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/eed41399/cordova-lib/spec-cordova/fixtures/projWithHooks/.cordova/hooks/fail/fail.js
----------------------------------------------------------------------
diff --git a/cordova-lib/spec-cordova/fixtures/projWithHooks/.cordova/hooks/fail/fail.js b/cordova-lib/spec-cordova/fixtures/projWithHooks/.cordova/hooks/fail/fail.js
new file mode 100644
index 0000000..d2d790b
--- /dev/null
+++ b/cordova-lib/spec-cordova/fixtures/projWithHooks/.cordova/hooks/fail/fail.js
@@ -0,0 +1,2 @@
+#!/usr/bin/env node
+throw Error('test error');
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/eed41399/cordova-lib/spec-cordova/fixtures/projWithHooks/_bat/.cordova/hooks/before_build/hookScriptDot2.bat
----------------------------------------------------------------------
diff --git a/cordova-lib/spec-cordova/fixtures/projWithHooks/_bat/.cordova/hooks/before_build/hookScriptDot2.bat b/cordova-lib/spec-cordova/fixtures/projWithHooks/_bat/.cordova/hooks/before_build/hookScriptDot2.bat
new file mode 100644
index 0000000..0142765
--- /dev/null
+++ b/cordova-lib/spec-cordova/fixtures/projWithHooks/_bat/.cordova/hooks/before_build/hookScriptDot2.bat
@@ -0,0 +1,2 @@
+@echo off
+echo 03 >> hooks_order.txt
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/eed41399/cordova-lib/spec-cordova/fixtures/projWithHooks/_bat/hooks/before_build/hookScript01.bat
----------------------------------------------------------------------
diff --git a/cordova-lib/spec-cordova/fixtures/projWithHooks/_bat/hooks/before_build/hookScript01.bat b/cordova-lib/spec-cordova/fixtures/projWithHooks/_bat/hooks/before_build/hookScript01.bat
new file mode 100644
index 0000000..a6711cf
--- /dev/null
+++ b/cordova-lib/spec-cordova/fixtures/projWithHooks/_bat/hooks/before_build/hookScript01.bat
@@ -0,0 +1,2 @@
+@echo off
+echo 04 >> hooks_order.txt
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/eed41399/cordova-lib/spec-cordova/fixtures/projWithHooks/_bat/hooks/before_build/hookScript02.bat
----------------------------------------------------------------------
diff --git a/cordova-lib/spec-cordova/fixtures/projWithHooks/_bat/hooks/before_build/hookScript02.bat b/cordova-lib/spec-cordova/fixtures/projWithHooks/_bat/hooks/before_build/hookScript02.bat
new file mode 100644
index 0000000..1e824a4
--- /dev/null
+++ b/cordova-lib/spec-cordova/fixtures/projWithHooks/_bat/hooks/before_build/hookScript02.bat
@@ -0,0 +1,2 @@
+@echo off
+echo 05 >> hooks_order.txt
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/eed41399/cordova-lib/spec-cordova/fixtures/projWithHooks/_bat/hooks/before_build/hookScript3.bat
----------------------------------------------------------------------
diff --git a/cordova-lib/spec-cordova/fixtures/projWithHooks/_bat/hooks/before_build/hookScript3.bat b/cordova-lib/spec-cordova/fixtures/projWithHooks/_bat/hooks/before_build/hookScript3.bat
new file mode 100644
index 0000000..f339213
--- /dev/null
+++ b/cordova-lib/spec-cordova/fixtures/projWithHooks/_bat/hooks/before_build/hookScript3.bat
@@ -0,0 +1,2 @@
+@echo off
+echo 07 >> hooks_order.txt
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/eed41399/cordova-lib/spec-cordova/fixtures/projWithHooks/_sh/.cordova/hooks/before_build/hookScriptDot2.sh
----------------------------------------------------------------------
diff --git a/cordova-lib/spec-cordova/fixtures/projWithHooks/_sh/.cordova/hooks/before_build/hookScriptDot2.sh b/cordova-lib/spec-cordova/fixtures/projWithHooks/_sh/.cordova/hooks/before_build/hookScriptDot2.sh
new file mode 100644
index 0000000..7c0c654
--- /dev/null
+++ b/cordova-lib/spec-cordova/fixtures/projWithHooks/_sh/.cordova/hooks/before_build/hookScriptDot2.sh
@@ -0,0 +1 @@
+echo 03 >> hooks_order.txt
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/eed41399/cordova-lib/spec-cordova/fixtures/projWithHooks/_sh/hooks/before_build/hookScript01.sh
----------------------------------------------------------------------
diff --git a/cordova-lib/spec-cordova/fixtures/projWithHooks/_sh/hooks/before_build/hookScript01.sh b/cordova-lib/spec-cordova/fixtures/projWithHooks/_sh/hooks/before_build/hookScript01.sh
new file mode 100644
index 0000000..ccc8c89
--- /dev/null
+++ b/cordova-lib/spec-cordova/fixtures/projWithHooks/_sh/hooks/before_build/hookScript01.sh
@@ -0,0 +1 @@
+echo 04 >> hooks_order.txt
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/eed41399/cordova-lib/spec-cordova/fixtures/projWithHooks/_sh/hooks/before_build/hookScript02.sh
----------------------------------------------------------------------
diff --git a/cordova-lib/spec-cordova/fixtures/projWithHooks/_sh/hooks/before_build/hookScript02.sh b/cordova-lib/spec-cordova/fixtures/projWithHooks/_sh/hooks/before_build/hookScript02.sh
new file mode 100644
index 0000000..4926cd8
--- /dev/null
+++ b/cordova-lib/spec-cordova/fixtures/projWithHooks/_sh/hooks/before_build/hookScript02.sh
@@ -0,0 +1 @@
+echo 05 >> hooks_order.txt
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/eed41399/cordova-lib/spec-cordova/fixtures/projWithHooks/_sh/hooks/before_build/hookScript3.sh
----------------------------------------------------------------------
diff --git a/cordova-lib/spec-cordova/fixtures/projWithHooks/_sh/hooks/before_build/hookScript3.sh b/cordova-lib/spec-cordova/fixtures/projWithHooks/_sh/hooks/before_build/hookScript3.sh
new file mode 100644
index 0000000..c52c84a
--- /dev/null
+++ b/cordova-lib/spec-cordova/fixtures/projWithHooks/_sh/hooks/before_build/hookScript3.sh
@@ -0,0 +1 @@
+echo 07 >> hooks_order.txt
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/eed41399/cordova-lib/spec-cordova/fixtures/projWithHooks/config.xml
----------------------------------------------------------------------
diff --git a/cordova-lib/spec-cordova/fixtures/projWithHooks/config.xml b/cordova-lib/spec-cordova/fixtures/projWithHooks/config.xml
new file mode 100644
index 0000000..bc81273
--- /dev/null
+++ b/cordova-lib/spec-cordova/fixtures/projWithHooks/config.xml
@@ -0,0 +1,12 @@
+<?xml version='1.0' encoding='utf-8'?>
+<widget id="io.cordova.hellocordova" version="0.0.1" xmlns="http://www.w3.org/ns/widgets" xmlns:cdv="http://cordova.apache.org/ns/1.0">
+    <name>HelloCordova</name>
+    <description>
+        A sample Apache Cordova application that responds to the deviceready event.
+    </description>
+    <author email="dev@cordova.apache.org" href="http://cordova.io">
+        Apache Cordova Team
+    </author>
+    <content src="index.html" />
+    <access origin="*" />
+</widget>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/eed41399/cordova-lib/spec-cordova/fixtures/projWithHooks/configOnePlatform_bat.xml
----------------------------------------------------------------------
diff --git a/cordova-lib/spec-cordova/fixtures/projWithHooks/configOnePlatform_bat.xml b/cordova-lib/spec-cordova/fixtures/projWithHooks/configOnePlatform_bat.xml
new file mode 100644
index 0000000..6f1a691
--- /dev/null
+++ b/cordova-lib/spec-cordova/fixtures/projWithHooks/configOnePlatform_bat.xml
@@ -0,0 +1,22 @@
+<?xml version='1.0' encoding='utf-8'?>
+<widget id="io.cordova.hellocordova" version="0.0.1" xmlns="http://www.w3.org/ns/widgets" xmlns:cdv="http://cordova.apache.org/ns/1.0">
+    <name>HelloCordova</name>
+    <description>
+        A sample Apache Cordova application that responds to the deviceready event.
+    </description>
+    <author email="dev@cordova.apache.org" href="http://cordova.io">
+        Apache Cordova Team
+    </author>
+    <content src="index.html" />
+    <access origin="*" />
+
+    <hook type="before_build" src="scripts/appBeforeBuild1.bat" />
+    <hook type="before_build" src="scripts/appBeforeBuild02.js" />
+    <hook type="before_plugin_install" src="scripts/appBeforePluginInstall.js" />
+
+    <platform name="windows">
+        <hook type="before_build" src="scripts/windows/appWindowsBeforeBuild.bat" />
+        <hook type="before_build" src="scripts/windows/appWindowsBeforeBuild.js" />
+        <hook type="before_plugin_install" src="scripts/windows/appWindowsBeforePluginInstall.js" />
+    </platform>
+</widget>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/eed41399/cordova-lib/spec-cordova/fixtures/projWithHooks/configOnePlatform_sh.xml
----------------------------------------------------------------------
diff --git a/cordova-lib/spec-cordova/fixtures/projWithHooks/configOnePlatform_sh.xml b/cordova-lib/spec-cordova/fixtures/projWithHooks/configOnePlatform_sh.xml
new file mode 100644
index 0000000..bddcd25
--- /dev/null
+++ b/cordova-lib/spec-cordova/fixtures/projWithHooks/configOnePlatform_sh.xml
@@ -0,0 +1,22 @@
+<?xml version='1.0' encoding='utf-8'?>
+<widget id="io.cordova.hellocordova" version="0.0.1" xmlns="http://www.w3.org/ns/widgets" xmlns:cdv="http://cordova.apache.org/ns/1.0">
+    <name>HelloCordova</name>
+    <description>
+        A sample Apache Cordova application that responds to the deviceready event.
+    </description>
+    <author email="dev@cordova.apache.org" href="http://cordova.io">
+        Apache Cordova Team
+    </author>
+    <content src="index.html" />
+    <access origin="*" />
+
+    <hook type="before_build" src="scripts/appBeforeBuild1.sh" />
+    <hook type="before_build" src="scripts/appBeforeBuild02.js" />
+    <hook type="before_plugin_install" src="scripts/appBeforePluginInstall.js" />
+
+    <platform name="windows">
+        <hook type="before_build" src="scripts/windows/appWindowsBeforeBuild.sh" />
+        <hook type="before_build" src="scripts/windows/appWindowsBeforeBuild.js" />
+        <hook type="before_plugin_install" src="scripts/windows/appWindowsBeforePluginInstall.js" />
+    </platform>
+</widget>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/eed41399/cordova-lib/spec-cordova/fixtures/projWithHooks/configOnlyNonPlatformScripts_bat.xml
----------------------------------------------------------------------
diff --git a/cordova-lib/spec-cordova/fixtures/projWithHooks/configOnlyNonPlatformScripts_bat.xml b/cordova-lib/spec-cordova/fixtures/projWithHooks/configOnlyNonPlatformScripts_bat.xml
new file mode 100644
index 0000000..8ad84f6
--- /dev/null
+++ b/cordova-lib/spec-cordova/fixtures/projWithHooks/configOnlyNonPlatformScripts_bat.xml
@@ -0,0 +1,16 @@
+<?xml version='1.0' encoding='utf-8'?>
+<widget id="io.cordova.hellocordova" version="0.0.1" xmlns="http://www.w3.org/ns/widgets" xmlns:cdv="http://cordova.apache.org/ns/1.0">
+    <name>HelloCordova</name>
+    <description>
+        A sample Apache Cordova application that responds to the deviceready event.
+    </description>
+    <author email="dev@cordova.apache.org" href="http://cordova.io">
+        Apache Cordova Team
+    </author>
+    <content src="index.html" />
+    <access origin="*" />
+
+    <hook type="before_build" src="scripts/appBeforeBuild1.bat" />
+    <hook type="before_build" src="scripts/appBeforeBuild02.js" />
+    <hook type="before_plugin_install" src="scripts/appBeforePluginInstall.js" />
+</widget>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/eed41399/cordova-lib/spec-cordova/fixtures/projWithHooks/configOnlyNonPlatformScripts_sh.xml
----------------------------------------------------------------------
diff --git a/cordova-lib/spec-cordova/fixtures/projWithHooks/configOnlyNonPlatformScripts_sh.xml b/cordova-lib/spec-cordova/fixtures/projWithHooks/configOnlyNonPlatformScripts_sh.xml
new file mode 100644
index 0000000..8634f64
--- /dev/null
+++ b/cordova-lib/spec-cordova/fixtures/projWithHooks/configOnlyNonPlatformScripts_sh.xml
@@ -0,0 +1,16 @@
+<?xml version='1.0' encoding='utf-8'?>
+<widget id="io.cordova.hellocordova" version="0.0.1" xmlns="http://www.w3.org/ns/widgets" xmlns:cdv="http://cordova.apache.org/ns/1.0">
+    <name>HelloCordova</name>
+    <description>
+        A sample Apache Cordova application that responds to the deviceready event.
+    </description>
+    <author email="dev@cordova.apache.org" href="http://cordova.io">
+        Apache Cordova Team
+    </author>
+    <content src="index.html" />
+    <access origin="*" />
+
+    <hook type="before_build" src="scripts/appBeforeBuild1.sh" />
+    <hook type="before_build" src="scripts/appBeforeBuild02.js" />
+    <hook type="before_plugin_install" src="scripts/appBeforePluginInstall.js" />
+</widget>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/eed41399/cordova-lib/spec-cordova/fixtures/projWithHooks/configTwoPlatforms_bat.xml
----------------------------------------------------------------------
diff --git a/cordova-lib/spec-cordova/fixtures/projWithHooks/configTwoPlatforms_bat.xml b/cordova-lib/spec-cordova/fixtures/projWithHooks/configTwoPlatforms_bat.xml
new file mode 100644
index 0000000..758ac70
--- /dev/null
+++ b/cordova-lib/spec-cordova/fixtures/projWithHooks/configTwoPlatforms_bat.xml
@@ -0,0 +1,28 @@
+<?xml version='1.0' encoding='utf-8'?>
+<widget id="io.cordova.hellocordova" version="0.0.1" xmlns="http://www.w3.org/ns/widgets" xmlns:cdv="http://cordova.apache.org/ns/1.0">
+    <name>HelloCordova</name>
+    <description>
+        A sample Apache Cordova application that responds to the deviceready event.
+    </description>
+    <author email="dev@cordova.apache.org" href="http://cordova.io">
+        Apache Cordova Team
+    </author>
+    <content src="index.html" />
+    <access origin="*" />
+
+    <hook type="before_build" src="scripts/appBeforeBuild1.bat" />
+    <hook type="before_build" src="scripts/appBeforeBuild02.js" />
+    <hook type="before_plugin_install" src="scripts/appBeforePluginInstall.js" />
+
+    <platform name="windows">
+        <hook type="before_build" src="scripts/windows/appWindowsBeforeBuild.bat" />
+        <hook type="before_build" src="scripts/windows/appWindowsBeforeBuild.js" />
+        <hook type="before_plugin_install" src="scripts/windows/appWindowsBeforePluginInstall.js" />
+    </platform>
+
+    <platform name="android">
+        <hook type="before_build" src="scripts/android/appAndroidBeforeBuild.bat" />
+        <hook type="before_build" src="scripts/android/appAndroidBeforeBuild.js" />
+        <hook type="before_plugin_install" src="scripts/android/appAndroidBeforePluginInstall.js" />
+    </platform>
+</widget>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/eed41399/cordova-lib/spec-cordova/fixtures/projWithHooks/configTwoPlatforms_sh.xml
----------------------------------------------------------------------
diff --git a/cordova-lib/spec-cordova/fixtures/projWithHooks/configTwoPlatforms_sh.xml b/cordova-lib/spec-cordova/fixtures/projWithHooks/configTwoPlatforms_sh.xml
new file mode 100644
index 0000000..1175e6c
--- /dev/null
+++ b/cordova-lib/spec-cordova/fixtures/projWithHooks/configTwoPlatforms_sh.xml
@@ -0,0 +1,28 @@
+<?xml version='1.0' encoding='utf-8'?>
+<widget id="io.cordova.hellocordova" version="0.0.1" xmlns="http://www.w3.org/ns/widgets" xmlns:cdv="http://cordova.apache.org/ns/1.0">
+    <name>HelloCordova</name>
+    <description>
+        A sample Apache Cordova application that responds to the deviceready event.
+    </description>
+    <author email="dev@cordova.apache.org" href="http://cordova.io">
+        Apache Cordova Team
+    </author>
+    <content src="index.html" />
+    <access origin="*" />
+
+    <hook type="before_build" src="scripts/appBeforeBuild1.sh" />
+    <hook type="before_build" src="scripts/appBeforeBuild02.js" />
+    <hook type="before_plugin_install" src="scripts/appBeforePluginInstall.js" />
+
+    <platform name="windows">
+        <hook type="before_build" src="scripts/windows/appWindowsBeforeBuild.sh" />
+        <hook type="before_build" src="scripts/windows/appWindowsBeforeBuild.js" />
+        <hook type="before_plugin_install" src="scripts/windows/appWindowsBeforePluginInstall.js" />
+    </platform>
+
+    <platform name="android">
+        <hook type="before_build" src="scripts/android/appAndroidBeforeBuild.sh" />
+        <hook type="before_build" src="scripts/android/appAndroidBeforeBuild.js" />
+        <hook type="before_plugin_install" src="scripts/android/appAndroidBeforePluginInstall.js" />
+    </platform>
+</widget>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/eed41399/cordova-lib/spec-cordova/fixtures/projWithHooks/hooks/before_build/hookScript10.js
----------------------------------------------------------------------
diff --git a/cordova-lib/spec-cordova/fixtures/projWithHooks/hooks/before_build/hookScript10.js b/cordova-lib/spec-cordova/fixtures/projWithHooks/hooks/before_build/hookScript10.js
new file mode 100644
index 0000000..bad1036
--- /dev/null
+++ b/cordova-lib/spec-cordova/fixtures/projWithHooks/hooks/before_build/hookScript10.js
@@ -0,0 +1,4 @@
+#!/usr/bin/env node
+var path = require('path');
+var orderLogger = require(path.join(process.argv.slice(2)[0], 'scripts', 'orderLogger'));
+orderLogger.logOrder('06');
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/eed41399/cordova-lib/spec-cordova/fixtures/projWithHooks/merges/.gitignore
----------------------------------------------------------------------
diff --git a/cordova-lib/spec-cordova/fixtures/projWithHooks/merges/.gitignore b/cordova-lib/spec-cordova/fixtures/projWithHooks/merges/.gitignore
new file mode 100644
index 0000000..e69de29

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/eed41399/cordova-lib/spec-cordova/fixtures/projWithHooks/plugins/.gitignore
----------------------------------------------------------------------
diff --git a/cordova-lib/spec-cordova/fixtures/projWithHooks/plugins/.gitignore b/cordova-lib/spec-cordova/fixtures/projWithHooks/plugins/.gitignore
new file mode 100644
index 0000000..e69de29

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/eed41399/cordova-lib/spec-cordova/fixtures/projWithHooks/scripts/android/appAndroidBeforeBuild.bat
----------------------------------------------------------------------
diff --git a/cordova-lib/spec-cordova/fixtures/projWithHooks/scripts/android/appAndroidBeforeBuild.bat b/cordova-lib/spec-cordova/fixtures/projWithHooks/scripts/android/appAndroidBeforeBuild.bat
new file mode 100644
index 0000000..1893215
--- /dev/null
+++ b/cordova-lib/spec-cordova/fixtures/projWithHooks/scripts/android/appAndroidBeforeBuild.bat
@@ -0,0 +1,2 @@
+@echo off
+echo 14 >> hooks_order.txt
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/eed41399/cordova-lib/spec-cordova/fixtures/projWithHooks/scripts/android/appAndroidBeforeBuild.js
----------------------------------------------------------------------
diff --git a/cordova-lib/spec-cordova/fixtures/projWithHooks/scripts/android/appAndroidBeforeBuild.js b/cordova-lib/spec-cordova/fixtures/projWithHooks/scripts/android/appAndroidBeforeBuild.js
new file mode 100644
index 0000000..b5e0971
--- /dev/null
+++ b/cordova-lib/spec-cordova/fixtures/projWithHooks/scripts/android/appAndroidBeforeBuild.js
@@ -0,0 +1,4 @@
+module.exports = function(context) {
+    var orderLogger = require(require('path').join(context.opts.projectRoot, 'scripts', 'orderLogger'));
+    orderLogger.logOrder('15', context);
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/eed41399/cordova-lib/spec-cordova/fixtures/projWithHooks/scripts/android/appAndroidBeforeBuild.sh
----------------------------------------------------------------------
diff --git a/cordova-lib/spec-cordova/fixtures/projWithHooks/scripts/android/appAndroidBeforeBuild.sh b/cordova-lib/spec-cordova/fixtures/projWithHooks/scripts/android/appAndroidBeforeBuild.sh
new file mode 100644
index 0000000..34f9b56
--- /dev/null
+++ b/cordova-lib/spec-cordova/fixtures/projWithHooks/scripts/android/appAndroidBeforeBuild.sh
@@ -0,0 +1 @@
+echo 14 >> hooks_order.txt
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/eed41399/cordova-lib/spec-cordova/fixtures/projWithHooks/scripts/android/appAndroidBeforePluginInstall.js
----------------------------------------------------------------------
diff --git a/cordova-lib/spec-cordova/fixtures/projWithHooks/scripts/android/appAndroidBeforePluginInstall.js b/cordova-lib/spec-cordova/fixtures/projWithHooks/scripts/android/appAndroidBeforePluginInstall.js
new file mode 100644
index 0000000..608be4f
--- /dev/null
+++ b/cordova-lib/spec-cordova/fixtures/projWithHooks/scripts/android/appAndroidBeforePluginInstall.js
@@ -0,0 +1,4 @@
+module.exports = function(context) {
+    var orderLogger = require(require('path').join(context.opts.projectRoot, 'scripts', 'orderLogger'));
+    orderLogger.logOrder('16', context);
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/eed41399/cordova-lib/spec-cordova/fixtures/projWithHooks/scripts/appBeforeBuild02.js
----------------------------------------------------------------------
diff --git a/cordova-lib/spec-cordova/fixtures/projWithHooks/scripts/appBeforeBuild02.js b/cordova-lib/spec-cordova/fixtures/projWithHooks/scripts/appBeforeBuild02.js
new file mode 100644
index 0000000..e248272
--- /dev/null
+++ b/cordova-lib/spec-cordova/fixtures/projWithHooks/scripts/appBeforeBuild02.js
@@ -0,0 +1,4 @@
+module.exports = function(context) {
+    var orderLogger = require(require('path').join(context.opts.projectRoot, 'scripts', 'orderLogger'));
+    orderLogger.logOrder('09', context);
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/eed41399/cordova-lib/spec-cordova/fixtures/projWithHooks/scripts/appBeforeBuild1.bat
----------------------------------------------------------------------
diff --git a/cordova-lib/spec-cordova/fixtures/projWithHooks/scripts/appBeforeBuild1.bat b/cordova-lib/spec-cordova/fixtures/projWithHooks/scripts/appBeforeBuild1.bat
new file mode 100644
index 0000000..c3d28b8
--- /dev/null
+++ b/cordova-lib/spec-cordova/fixtures/projWithHooks/scripts/appBeforeBuild1.bat
@@ -0,0 +1,2 @@
+@echo off
+echo 08 >> hooks_order.txt
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/eed41399/cordova-lib/spec-cordova/fixtures/projWithHooks/scripts/appBeforeBuild1.sh
----------------------------------------------------------------------
diff --git a/cordova-lib/spec-cordova/fixtures/projWithHooks/scripts/appBeforeBuild1.sh b/cordova-lib/spec-cordova/fixtures/projWithHooks/scripts/appBeforeBuild1.sh
new file mode 100644
index 0000000..03793d8
--- /dev/null
+++ b/cordova-lib/spec-cordova/fixtures/projWithHooks/scripts/appBeforeBuild1.sh
@@ -0,0 +1 @@
+echo 08 >> hooks_order.txt
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/eed41399/cordova-lib/spec-cordova/fixtures/projWithHooks/scripts/appBeforePluginInstall.js
----------------------------------------------------------------------
diff --git a/cordova-lib/spec-cordova/fixtures/projWithHooks/scripts/appBeforePluginInstall.js b/cordova-lib/spec-cordova/fixtures/projWithHooks/scripts/appBeforePluginInstall.js
new file mode 100644
index 0000000..93e6701
--- /dev/null
+++ b/cordova-lib/spec-cordova/fixtures/projWithHooks/scripts/appBeforePluginInstall.js
@@ -0,0 +1,4 @@
+module.exports = function(context) {
+    var orderLogger = require(require('path').join(context.opts.projectRoot, 'scripts', 'orderLogger'));
+    orderLogger.logOrder('10', context);
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/eed41399/cordova-lib/spec-cordova/fixtures/projWithHooks/scripts/orderLogger.js
----------------------------------------------------------------------
diff --git a/cordova-lib/spec-cordova/fixtures/projWithHooks/scripts/orderLogger.js b/cordova-lib/spec-cordova/fixtures/projWithHooks/scripts/orderLogger.js
new file mode 100644
index 0000000..f50390a
--- /dev/null
+++ b/cordova-lib/spec-cordova/fixtures/projWithHooks/scripts/orderLogger.js
@@ -0,0 +1,12 @@
+module.exports.logOrder = function logOrder(index, context) {
+    var indexWithEOL = index + require('os').EOL;
+    var path = require('path');
+    var fs = require('fs');
+
+    if(context) {
+        fs.appendFileSync(path.join(context.opts.projectRoot, 'hooks_order.txt'), indexWithEOL);
+    } else {
+
+        fs.appendFileSync('hooks_order.txt', indexWithEOL);
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/eed41399/cordova-lib/spec-cordova/fixtures/projWithHooks/scripts/windows/appWindowsBeforeBuild.bat
----------------------------------------------------------------------
diff --git a/cordova-lib/spec-cordova/fixtures/projWithHooks/scripts/windows/appWindowsBeforeBuild.bat b/cordova-lib/spec-cordova/fixtures/projWithHooks/scripts/windows/appWindowsBeforeBuild.bat
new file mode 100644
index 0000000..1da7b9d
--- /dev/null
+++ b/cordova-lib/spec-cordova/fixtures/projWithHooks/scripts/windows/appWindowsBeforeBuild.bat
@@ -0,0 +1,2 @@
+@echo off
+echo 11 >> hooks_order.txt
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/eed41399/cordova-lib/spec-cordova/fixtures/projWithHooks/scripts/windows/appWindowsBeforeBuild.js
----------------------------------------------------------------------
diff --git a/cordova-lib/spec-cordova/fixtures/projWithHooks/scripts/windows/appWindowsBeforeBuild.js b/cordova-lib/spec-cordova/fixtures/projWithHooks/scripts/windows/appWindowsBeforeBuild.js
new file mode 100644
index 0000000..01284f1
--- /dev/null
+++ b/cordova-lib/spec-cordova/fixtures/projWithHooks/scripts/windows/appWindowsBeforeBuild.js
@@ -0,0 +1,4 @@
+module.exports = function(context) {
+    var orderLogger = require(require('path').join(context.opts.projectRoot, 'scripts', 'orderLogger'));
+    orderLogger.logOrder('12', context);
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/eed41399/cordova-lib/spec-cordova/fixtures/projWithHooks/scripts/windows/appWindowsBeforeBuild.sh
----------------------------------------------------------------------
diff --git a/cordova-lib/spec-cordova/fixtures/projWithHooks/scripts/windows/appWindowsBeforeBuild.sh b/cordova-lib/spec-cordova/fixtures/projWithHooks/scripts/windows/appWindowsBeforeBuild.sh
new file mode 100644
index 0000000..d699b61
--- /dev/null
+++ b/cordova-lib/spec-cordova/fixtures/projWithHooks/scripts/windows/appWindowsBeforeBuild.sh
@@ -0,0 +1 @@
+echo 11 >> hooks_order.txt
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/eed41399/cordova-lib/spec-cordova/fixtures/projWithHooks/scripts/windows/appWindowsBeforePluginInstall.js
----------------------------------------------------------------------
diff --git a/cordova-lib/spec-cordova/fixtures/projWithHooks/scripts/windows/appWindowsBeforePluginInstall.js b/cordova-lib/spec-cordova/fixtures/projWithHooks/scripts/windows/appWindowsBeforePluginInstall.js
new file mode 100644
index 0000000..1ad17e2
--- /dev/null
+++ b/cordova-lib/spec-cordova/fixtures/projWithHooks/scripts/windows/appWindowsBeforePluginInstall.js
@@ -0,0 +1,4 @@
+module.exports = function(context) {
+    var orderLogger = require(require('path').join(context.opts.projectRoot, 'scripts', 'orderLogger'));
+    orderLogger.logOrder('13', context);
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/eed41399/cordova-lib/spec-cordova/fixtures/projWithHooks/www/config.xml
----------------------------------------------------------------------
diff --git a/cordova-lib/spec-cordova/fixtures/projWithHooks/www/config.xml b/cordova-lib/spec-cordova/fixtures/projWithHooks/www/config.xml
new file mode 100644
index 0000000..9e7b9e0
--- /dev/null
+++ b/cordova-lib/spec-cordova/fixtures/projWithHooks/www/config.xml
@@ -0,0 +1,14 @@
+<?xml version='1.0' encoding='utf-8'?>
+<widget id="org.testing" version="0.0.1" xmlns="http://www.w3.org/ns/widgets" xmlns:cdv="http://cordova.apache.org/ns/1.0">
+    <name>TestBase</name>
+    <description>
+        A sample Apache Cordova application that responds to the deviceready event.
+    </description>
+    <author email="dev@cordova.apache.org" href="http://cordova.io">
+        Apache Cordova Team
+    </author>
+    <content src="index.html" />
+    <access origin="*" />
+    <preference name="fullscreen" value="true" />
+    <preference name="webviewbounce" value="true" />
+</widget>


[12/13] git commit: CB-6481 getPluginsHookScripts to work if plugin platform not defined

Posted by sg...@apache.org.
CB-6481 getPluginsHookScripts to work if plugin platform not defined

Also HookRunner minor code improvements


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

Branch: refs/heads/master
Commit: a8cf9fd23dd74b897e45de6b4f94a796885f9b7c
Parents: b74d87d
Author: sgrebnov <v-...@microsoft.com>
Authored: Sun Aug 10 19:59:12 2014 +0400
Committer: daserge <da...@yandex.ru>
Committed: Thu Sep 25 19:06:15 2014 +0400

----------------------------------------------------------------------
 cordova-lib/src/hooks/HooksRunner.js   | 26 +++++---------------------
 cordova-lib/src/hooks/scriptsFinder.js |  4 ++--
 2 files changed, 7 insertions(+), 23 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/a8cf9fd2/cordova-lib/src/hooks/HooksRunner.js
----------------------------------------------------------------------
diff --git a/cordova-lib/src/hooks/HooksRunner.js b/cordova-lib/src/hooks/HooksRunner.js
index 77ed54a..0bb199f 100644
--- a/cordova-lib/src/hooks/HooksRunner.js
+++ b/cordova-lib/src/hooks/HooksRunner.js
@@ -61,7 +61,6 @@ HooksRunner.prototype.fire = function fire(hook, opts) {
 
 /**
  * Refines passed options so that all required parameters are set.
- * Returns a promise.
  */
 HooksRunner.prototype.prepareOptions = function(opts) {
     opts = opts || {};
@@ -110,26 +109,11 @@ function executeEventHandlersSerially(hook, opts) {
  * 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;
+    return scripts.reduce(function(prevScriptPromise, nextScript) {
+        return prevScriptPromise.then(function() { 
+            return runScript(nextScript, context);
+        });
+    }, Q());
 }
 
 /**

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/a8cf9fd2/cordova-lib/src/hooks/scriptsFinder.js
----------------------------------------------------------------------
diff --git a/cordova-lib/src/hooks/scriptsFinder.js b/cordova-lib/src/hooks/scriptsFinder.js
index 3345af1..33a076a 100644
--- a/cordova-lib/src/hooks/scriptsFinder.js
+++ b/cordova-lib/src/hooks/scriptsFinder.js
@@ -71,8 +71,8 @@ function getPluginsHookScripts(hook, opts) {
     // retrieve scripts exclusive for this plugin.
     if(opts.plugin) {
         events.emit('debug', 'Executing "' + hook + '"  hook for "' + opts.plugin.id + '" on ' + opts.plugin.platform + '.');
-
-        return getPluginScriptFiles(opts.plugin, hook, [ opts.plugin.platform ]);
+        // if plugin hook is not run for specific platform then use all available platforms
+        return getPluginScriptFiles(opts.plugin, hook, opts.plugin.platform  ? [opts.plugin.platform] : opts.cordova.platforms);
     }
 
     events.emit('debug', 'Executing "' + hook + '"  hook for all plugins.');


[04/13] git commit: CB-6481 Updated hooks documentation

Posted by sg...@apache.org.
CB-6481 Updated hooks documentation


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

Branch: refs/heads/master
Commit: f1398408ee9e506b7e92e48f6b11a5a2fb3a9900
Parents: a972451
Author: daserge <da...@yandex.ru>
Authored: Wed Jul 9 16:20:11 2014 +0400
Committer: daserge <da...@yandex.ru>
Committed: Thu Sep 25 18:59:08 2014 +0400

----------------------------------------------------------------------
 cordova-lib/templates/hooks-README.md | 123 ++++++++++++++++++++++++++++-
 1 file changed, 120 insertions(+), 3 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/f1398408/cordova-lib/templates/hooks-README.md
----------------------------------------------------------------------
diff --git a/cordova-lib/templates/hooks-README.md b/cordova-lib/templates/hooks-README.md
index accfa3a..464bd3d 100644
--- a/cordova-lib/templates/hooks-README.md
+++ b/cordova-lib/templates/hooks-README.md
@@ -25,11 +25,18 @@ directory used to exist at `.cordova/hooks`, but has now been moved to the
 project root. Any scripts you add to these directories will be executed before
 and after the commands corresponding to the directory name. Useful for
 integrating your own build systems or integrating with version control systems.
+Hook scripts can also be defined in `config.xml` and `plugins/.../plugin.xml` 
+and will be run serially in the following order: 
+* Application hooks from `.cordova/hooks`;
+* Application hooks from `/hooks`;
+* Application hooks from `config.xml`;
+* Plugin hooks from `plugins/.../plugin.xml`.
 
 __Remember__: Make your scripts executable.
 
-## Hook Directories
-The following subdirectories will be used for hooks:
+## Ways to define hooks
+### Hook Directories
+The following subdirectories of `.cordova/hooks` and `/hooks` will be used for hooks:
 
     after_build/
     after_compile/
@@ -42,6 +49,7 @@ The following subdirectories will be used for hooks:
     after_plugin_ls/
     after_plugin_rm/
     after_plugin_search/
+    after_plugin_install/   <-- Plugin hooks defined in plugin.xml are executed exclusively for a plugin being installed
     after_prepare/
     after_run/
     after_serve/
@@ -56,14 +64,123 @@ The following subdirectories will be used for hooks:
     before_plugin_ls/
     before_plugin_rm/
     before_plugin_search/
+    before_plugin_install/   <-- Plugin hooks defined in plugin.xml are executed exclusively for a plugin being installed
+    before_plugin_uninstall/   <-- Plugin hooks defined in plugin.xml are executed exclusively for a plugin being uninstalled
     before_prepare/
     before_run/
     before_serve/
     pre_package/ <-- Windows 8 and Windows Phone only.
 
+### Config.xml
+
+Hooks can be defined in project's `config.xml` in the following way:
+
+    <script type="before_build" src="scripts/appBeforeBuild.bat" />
+    <script type="before_build" src="scripts/appBeforeBuild.js" />
+    <script type="before_plugin_install" src="scripts/appBeforePluginInstall.js" />
+
+    <platform name="wp8">
+        <script type="before_build" src="scripts/wp8/appWP8BeforeBuild.bat" />
+        <script type="before_build" src="scripts/wp8/appWP8BeforeBuild.js" />
+        <script type="before_plugin_install" src="scripts/wp8/appWP8BeforePluginInstall.js" />
+        ...
+    </platform>
+
+    <platform name="windows8">
+        <script type="before_build" src="scripts/windows8/appWin8BeforeBuild.bat" />
+        <script type="before_build" src="scripts/windows8/appWin8BeforeBuild.js" />
+        <script type="before_plugin_install" src="scripts/windows8/appWin8BeforePluginInstall.js" />
+        ...
+    </platform>
+
+### Plugin hooks (plugin.xml)
+
+As a plugin developer you can define hook scripts using `<script>` elements in a `plugin.xml` like that:
+
+    <script type="before_plugin_install" src="scripts/beforeInstall.js" />
+    <script type="after_build" src="scripts/afterBuild.js" />
+
+    <platform name="wp8">
+        <script type="before_plugin_install" src="scripts/wp8BeforeInstall.js" />
+        <script type="before_build" src="scripts/wp8BeforeBuild.js" />
+        ...
+    </platform>
+
+`before_plugin_install`, `after_plugin_install`, `before_plugin_uninstall` plugin hooks will be fired exclusively for the plugin being installed/uninstalled.
+
 ## Script Interface
 
-All scripts are run from the project's root directory and have the root directory passes as the first argument. All other options are passed to the script using environment variables:
+### Javascript
+
+If you are writing hooks in Javascript you should use the following module definition:
+```javascript
+module.exports = function(context) {
+    ...
+}
+```
+
+You can make your scipts async using Q, which can be retrieved from `context.commonModules`:
+```javascript
+module.exports = function(context) {
+    var Q = context.commonModules.Q;
+	var deferral = new Q.defer();
+
+    setTimeout(function(){
+    	console.log('hook.js>> end');
+		deferral.resolve();
+    }, 1000);
+
+    return deferral.promise;
+}
+```
+
+`context` object contains hook type, executed script full path, hook options, common modules, and command-line arguments passed to Cordova:
+```json
+{
+	"hook": "before_plugin_install",
+	"scriptLocation": "c:\\script\\full\\path\\appBeforePluginInstall.js",
+	"cmdLine": "The\\exact\\command\\cordova\\run\\with arguments",
+	"opts": {
+		"projectRoot":"C:\\path\\to\\the\\project",
+		"cordova": {
+			"platforms": ["wp8"],
+			"plugins": ["com.plugin.withhooks"],
+			"version": "0.21.7-dev"
+		},
+		"plugin": {
+			"id": "com.plugin.withhooks",
+			"pluginInfo": {
+				...
+			},
+			"platform": "wp8",
+			"dir": "C:\\path\\to\\the\\project\\plugins\\com.plugin.withhooks"
+		}
+	},
+	"commonModules": { 
+		"fs": { ... },
+		"path": { ... },
+		"os": { ... },
+		"events": { ... },
+		"util": { ... },
+		"cordovaUtil": { ... }
+	}
+}
+
+```
+`context.opts.plugin` object will only be passed to plugin hooks scripts.
+
+You can also require additional Cordova modules in your script using `context.requireCordovaModule` in the following way:
+```javascript
+var et = context.requireCordovaModule('elementtree');
+var xmlHelpers = context.requireCordovaModule('../util/xml-helpers');
+```
+
+New module loader script interface is used for the `.js` files defined via `config.xml` or `plugin.xml` only. 
+For compatibility reasons hook files specified via `.cordova/hooks` and `/hooks` folders are run via Node child_process spawn, see 'Non-javascript' section below.
+
+### Non-javascript
+
+Non-javascript scripts are run via Node child_process spawn from the project's root directory and have the root directory passes as the first argument. All other options are passed to the script using environment variables:
 
 * CORDOVA_VERSION - The version of the Cordova-CLI.
 * CORDOVA_PLATFORMS - Comma separated list of platforms that the command applies to (e.g.: android, ios).


[03/13] git commit: CB-6481 Docs: deprecated .cordova/hooks + other minor updates

Posted by sg...@apache.org.
CB-6481 Docs: deprecated .cordova/hooks + other minor updates


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

Branch: refs/heads/master
Commit: 4f0e74fb40775aca8bf3868f05963e076738079d
Parents: f139840
Author: sgrebnov <v-...@microsoft.com>
Authored: Fri Jul 11 11:28:11 2014 +0400
Committer: daserge <da...@yandex.ru>
Committed: Thu Sep 25 18:59:08 2014 +0400

----------------------------------------------------------------------
 cordova-lib/templates/hooks-README.md | 31 +++++++++++++++---------------
 1 file changed, 16 insertions(+), 15 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/4f0e74fb/cordova-lib/templates/hooks-README.md
----------------------------------------------------------------------
diff --git a/cordova-lib/templates/hooks-README.md b/cordova-lib/templates/hooks-README.md
index 464bd3d..5b9aa04 100644
--- a/cordova-lib/templates/hooks-README.md
+++ b/cordova-lib/templates/hooks-README.md
@@ -20,23 +20,17 @@
 -->
 # Cordova Hooks
 
-This directory may contain scripts used to customize cordova commands. This
-directory used to exist at `.cordova/hooks`, but has now been moved to the
-project root. Any scripts you add to these directories will be executed before
-and after the commands corresponding to the directory name. Useful for
-integrating your own build systems or integrating with version control systems.
-Hook scripts can also be defined in `config.xml` and `plugins/.../plugin.xml` 
-and will be run serially in the following order: 
-* Application hooks from `.cordova/hooks`;
+Cordova Hooks represent special scripts which could be added by application and plugin developers or even by your own build system  to customize cordova commands. Hook scripts could be defined by adding them to the special predefined folder (`/hooks`) or via configuration files (`config.xml` and `plugin.xml`) and run serially in the following order: 
 * Application hooks from `/hooks`;
 * Application hooks from `config.xml`;
 * Plugin hooks from `plugins/.../plugin.xml`.
 
 __Remember__: Make your scripts executable.
 
-## Ways to define hooks
-### Hook Directories
-The following subdirectories of `.cordova/hooks` and `/hooks` will be used for hooks:
+__Note__: `.cordova/hooks` directory is also supported for backward compatibility, but we don't recommend using it as it is deprecated.
+
+## Supported hook types
+The following hook types are supported:
 
     after_build/
     after_compile/
@@ -71,9 +65,17 @@ The following subdirectories of `.cordova/hooks` and `/hooks` will be used for h
     before_serve/
     pre_package/ <-- Windows 8 and Windows Phone only.
 
+## Ways to define hooks
+### Via '/hooks' directory
+To execute custom action when corresponding hook type is fired, use hook type as a name for a subfolder inside 'hooks' directory and place you script file here, for example:
+
+    # script file will be automatically executed after each build
+    hooks/after_build/after_build_custom_action.js
+
+
 ### Config.xml
 
-Hooks can be defined in project's `config.xml` in the following way:
+Hooks can be defined in project's `config.xml` using `<script>` elements, for example:
 
     <script type="before_build" src="scripts/appBeforeBuild.bat" />
     <script type="before_build" src="scripts/appBeforeBuild.js" />
@@ -175,8 +177,8 @@ var et = context.requireCordovaModule('elementtree');
 var xmlHelpers = context.requireCordovaModule('../util/xml-helpers');
 ```
 
-New module loader script interface is used for the `.js` files defined via `config.xml` or `plugin.xml` only. 
-For compatibility reasons hook files specified via `.cordova/hooks` and `/hooks` folders are run via Node child_process spawn, see 'Non-javascript' section below.
+__Note__:  new module loader script interface is used for the `.js` files defined via `config.xml` or `plugin.xml` only. 
+For compatibility reasons hook files specified via `/hooks` folders are run via Node child_process spawn, see 'Non-javascript' section below.
 
 ### Non-javascript
 
@@ -200,4 +202,3 @@ cross-platform. Some good examples are shown here:
 Also, note that even if you are working on Windows, and in case your hook scripts aren't bat files (which is recommended, if you want your scripts to work in non-Windows operating systems) Cordova CLI will expect a shebang line as the first line for it to know the interpreter it needs to use to launch the script. The shebang line should match the following example:
 
     #!/usr/bin/env [name_of_interpreter_executable]
-


[07/13] CB-6481 Updated tests

Posted by sg...@apache.org.
http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/eed41399/cordova-lib/spec-cordova/fixtures/projWithHooks/www/css/index.css
----------------------------------------------------------------------
diff --git a/cordova-lib/spec-cordova/fixtures/projWithHooks/www/css/index.css b/cordova-lib/spec-cordova/fixtures/projWithHooks/www/css/index.css
new file mode 100644
index 0000000..51daa79
--- /dev/null
+++ b/cordova-lib/spec-cordova/fixtures/projWithHooks/www/css/index.css
@@ -0,0 +1,115 @@
+/*
+ * 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.
+ */
+* {
+    -webkit-tap-highlight-color: rgba(0,0,0,0); /* make transparent link selection, adjust last value opacity 0 to 1.0 */
+}
+
+body {
+    -webkit-touch-callout: none;                /* prevent callout to copy image, etc when tap to hold */
+    -webkit-text-size-adjust: none;             /* prevent webkit from resizing text to fit */
+    -webkit-user-select: none;                  /* prevent copy paste, to allow, change 'none' to 'text' */
+    background-color:#E4E4E4;
+    background-image:linear-gradient(top, #A7A7A7 0%, #E4E4E4 51%);
+    background-image:-webkit-linear-gradient(top, #A7A7A7 0%, #E4E4E4 51%);
+    background-image:-ms-linear-gradient(top, #A7A7A7 0%, #E4E4E4 51%);
+    background-image:-webkit-gradient(
+        linear,
+        left top,
+        left bottom,
+        color-stop(0, #A7A7A7),
+        color-stop(0.51, #E4E4E4)
+    );
+    background-attachment:fixed;
+    font-family:'HelveticaNeue-Light', 'HelveticaNeue', Helvetica, Arial, sans-serif;
+    font-size:12px;
+    height:100%;
+    margin:0px;
+    padding:0px;
+    text-transform:uppercase;
+    width:100%;
+}
+
+/* Portrait layout (default) */
+.app {
+    background:url(../img/logo.png) no-repeat center top; /* 170px x 200px */
+    position:absolute;             /* position in the center of the screen */
+    left:50%;
+    top:50%;
+    height:50px;                   /* text area height */
+    width:225px;                   /* text area width */
+    text-align:center;
+    padding:180px 0px 0px 0px;     /* image height is 200px (bottom 20px are overlapped with text) */
+    margin:-115px 0px 0px -112px;  /* offset vertical: half of image height and text area height */
+                                   /* offset horizontal: half of text area width */
+}
+
+/* Landscape layout (with min-width) */
+@media screen and (min-aspect-ratio: 1/1) and (min-width:400px) {
+    .app {
+        background-position:left center;
+        padding:75px 0px 75px 170px;  /* padding-top + padding-bottom + text area = image height */
+        margin:-90px 0px 0px -198px;  /* offset vertical: half of image height */
+                                      /* offset horizontal: half of image width and text area width */
+    }
+}
+
+h1 {
+    font-size:24px;
+    font-weight:normal;
+    margin:0px;
+    overflow:visible;
+    padding:0px;
+    text-align:center;
+}
+
+.event {
+    border-radius:4px;
+    -webkit-border-radius:4px;
+    color:#FFFFFF;
+    font-size:12px;
+    margin:0px 30px;
+    padding:2px 0px;
+}
+
+.event.listening {
+    background-color:#333333;
+    display:block;
+}
+
+.event.received {
+    background-color:#4B946A;
+    display:none;
+}
+
+@keyframes fade {
+    from { opacity: 1.0; }
+    50% { opacity: 0.4; }
+    to { opacity: 1.0; }
+}
+ 
+@-webkit-keyframes fade {
+    from { opacity: 1.0; }
+    50% { opacity: 0.4; }
+    to { opacity: 1.0; }
+}
+ 
+.blink {
+    animation:fade 3000ms infinite;
+    -webkit-animation:fade 3000ms infinite;
+}

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

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/eed41399/cordova-lib/spec-cordova/fixtures/projWithHooks/www/index.html
----------------------------------------------------------------------
diff --git a/cordova-lib/spec-cordova/fixtures/projWithHooks/www/index.html b/cordova-lib/spec-cordova/fixtures/projWithHooks/www/index.html
new file mode 100644
index 0000000..bde5741
--- /dev/null
+++ b/cordova-lib/spec-cordova/fixtures/projWithHooks/www/index.html
@@ -0,0 +1,43 @@
+<!DOCTYPE html>
+<!--
+    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.
+-->
+<html>
+    <head>
+        <meta charset="utf-8" />
+        <meta name="format-detection" content="telephone=no" />
+        <!-- WARNING: for iOS 7, remove the width=device-width and height=device-height attributes. See https://issues.apache.org/jira/browse/CB-4323 -->
+        <meta name="viewport" content="user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1, width=device-width, height=device-height, target-densitydpi=device-dpi" />
+        <link rel="stylesheet" type="text/css" href="css/index.css" />
+        <title>Hello World</title>
+    </head>
+    <body>
+        <div class="app">
+            <h1>Apache Cordova</h1>
+            <div id="deviceready" class="blink">
+                <p class="event listening">Connecting to Device</p>
+                <p class="event received">Device is Ready</p>
+            </div>
+        </div>
+        <script type="text/javascript" src="cordova.js"></script>
+        <script type="text/javascript" src="js/index.js"></script>
+        <script type="text/javascript">
+            app.initialize();
+        </script>
+    </body>
+</html>

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/eed41399/cordova-lib/spec-cordova/fixtures/projWithHooks/www/js/index.js
----------------------------------------------------------------------
diff --git a/cordova-lib/spec-cordova/fixtures/projWithHooks/www/js/index.js b/cordova-lib/spec-cordova/fixtures/projWithHooks/www/js/index.js
new file mode 100644
index 0000000..31d9064
--- /dev/null
+++ b/cordova-lib/spec-cordova/fixtures/projWithHooks/www/js/index.js
@@ -0,0 +1,49 @@
+/*
+ * 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 app = {
+    // Application Constructor
+    initialize: function() {
+        this.bindEvents();
+    },
+    // Bind Event Listeners
+    //
+    // Bind any events that are required on startup. Common events are:
+    // 'load', 'deviceready', 'offline', and 'online'.
+    bindEvents: function() {
+        document.addEventListener('deviceready', this.onDeviceReady, false);
+    },
+    // deviceready Event Handler
+    //
+    // The scope of 'this' is the event. In order to call the 'receivedEvent'
+    // function, we must explicity call 'app.receivedEvent(...);'
+    onDeviceReady: function() {
+        app.receivedEvent('deviceready');
+    },
+    // Update DOM on a Received Event
+    receivedEvent: function(id) {
+        var parentElement = document.getElementById(id);
+        var listeningElement = parentElement.querySelector('.listening');
+        var receivedElement = parentElement.querySelector('.received');
+
+        listeningElement.setAttribute('style', 'display:none;');
+        receivedElement.setAttribute('style', 'display:block;');
+
+        console.log('Received Event: ' + id);
+    }
+};

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/eed41399/cordova-lib/spec-cordova/fixtures/projWithHooks/www/spec.html
----------------------------------------------------------------------
diff --git a/cordova-lib/spec-cordova/fixtures/projWithHooks/www/spec.html b/cordova-lib/spec-cordova/fixtures/projWithHooks/www/spec.html
new file mode 100644
index 0000000..71f00de
--- /dev/null
+++ b/cordova-lib/spec-cordova/fixtures/projWithHooks/www/spec.html
@@ -0,0 +1,68 @@
+<!DOCTYPE html>
+<!--
+    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.
+-->
+<html>
+    <head>
+        <title>Jasmine Spec Runner</title>
+
+        <!-- jasmine source -->
+        <link rel="shortcut icon" type="image/png" href="spec/lib/jasmine-1.2.0/jasmine_favicon.png">
+        <link rel="stylesheet" type="text/css" href="spec/lib/jasmine-1.2.0/jasmine.css">
+        <script type="text/javascript" src="spec/lib/jasmine-1.2.0/jasmine.js"></script>
+        <script type="text/javascript" src="spec/lib/jasmine-1.2.0/jasmine-html.js"></script>
+
+        <!-- include source files here... -->
+        <script type="text/javascript" src="js/index.js"></script>
+
+        <!-- include spec files here... -->
+        <script type="text/javascript" src="spec/helper.js"></script>
+        <script type="text/javascript" src="spec/index.js"></script>
+
+        <script type="text/javascript">
+            (function() {
+                var jasmineEnv = jasmine.getEnv();
+                jasmineEnv.updateInterval = 1000;
+
+                var htmlReporter = new jasmine.HtmlReporter();
+
+                jasmineEnv.addReporter(htmlReporter);
+
+                jasmineEnv.specFilter = function(spec) {
+                    return htmlReporter.specFilter(spec);
+                };
+
+                var currentWindowOnload = window.onload;
+
+                window.onload = function() {
+                    if (currentWindowOnload) {
+                        currentWindowOnload();
+                    }
+                    execJasmine();
+                };
+
+                function execJasmine() {
+                    jasmineEnv.execute();
+                }
+            })();
+        </script>
+    </head>
+    <body>
+        <div id="stage" style="display:none;"></div>
+    </body>
+</html>

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/eed41399/cordova-lib/spec-cordova/hooker.spec.js
----------------------------------------------------------------------
diff --git a/cordova-lib/spec-cordova/hooker.spec.js b/cordova-lib/spec-cordova/hooker.spec.js
deleted file mode 100644
index 3696cb1..0000000
--- a/cordova-lib/spec-cordova/hooker.spec.js
+++ /dev/null
@@ -1,261 +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 cordova = require('../src/cordova/cordova'),
-    hooker = require('../src/cordova/hooker'),
-    shell  = require('shelljs'),
-    path   = require('path'),
-    fs     = require('fs'),
-    os     = require('os'),
-    Q      = require('q'),
-    child_process = require('child_process'),
-    helpers = require('./helpers');
-
-var platform = os.platform();
-var tmpDir = helpers.tmpDir('hooks_test');
-var project = path.join(tmpDir, 'project');
-var dotCordova = path.join(project, '.cordova');
-var hooksDir = path.join(project, '.cordova', 'hooks');
-var ext = platform.match(/(win32|win64)/)?'bat':'sh';
-
-
-// copy fixture
-shell.rm('-rf', project);
-shell.mkdir('-p', project);
-shell.cp('-R', path.join(__dirname, 'fixtures', 'base', '*'), project);
-shell.mkdir('-p', dotCordova);
-shell.cp('-R', path.join(__dirname, 'fixtures', 'hooks_' + ext), dotCordova);
-shell.mv(path.join(dotCordova, 'hooks_' + ext), hooksDir);
-shell.chmod('-R', 'ug+x', hooksDir);
-
-
-describe('hooker', function() {
-    it('should throw if provided directory is not a cordova project', function() {
-        expect(function() {
-            new hooker(tmpDir);
-        }).toThrow();
-    });
-});
-
-describe('global (static) fire method', function() {
-    it('should execute listeners serially', function(done) {
-        var test_event = 'foo';
-        var h1_fired = false;
-        var h1 = function() {
-            expect(h2_fired).toBe(false);
-            // Delay 100 ms here to check that h2 is not executed until after
-            // the promise returned by h1 is resolved.
-            var q = Q.delay(100).then(function() {
-                h1_fired = true;
-            });
-            return q;
-        };
-        var h2_fired = false;
-        var h2 = function() {
-            h2_fired = true;
-            expect(h1_fired).toBe(true);
-            return Q();
-        };
-
-        cordova.on(test_event, h1);
-        cordova.on(test_event, h2);
-        hooker.fire(test_event).then(function() {
-            expect(h1_fired).toBe(true);
-            expect(h2_fired).toBe(true);
-            done();
-        });
-    });
-});
-
-describe('module-level hooks', function() {
-    var handler = jasmine.createSpy().andReturn(Q());
-    var test_event = 'before_build';
-    var h;
-
-    beforeEach(function() {
-        h = new hooker(project);
-    });
-
-    afterEach(function() {
-        cordova.removeAllListeners(test_event);
-        handler.reset();
-    });
-
-    it('should fire handlers using cordova.on', function(done) {
-        cordova.on(test_event, handler);
-        h.fire(test_event)
-        .then(function() {
-            expect(handler).toHaveBeenCalled();
-        })
-        .fail(function(err) {
-            expect(err).not.toBeDefined();
-        })
-        .fin(done);
-    });
-
-    it('should pass the project root folder as parameter into the module-level handlers', function(done) {
-        cordova.on(test_event, handler);
-        h.fire(test_event)
-        .then(function() {
-            expect(handler).toHaveBeenCalledWith({root:project});
-        })
-        .fail(function(err) {
-            console.log(err);
-            expect(err).not.toBeDefined();
-        })
-        .fin(done);
-    });
-
-    it('should be able to stop listening to events using cordova.off', function(done) {
-        cordova.on(test_event, handler);
-        cordova.off(test_event, handler);
-        h.fire(test_event)
-        .then(function() {
-            expect(handler).not.toHaveBeenCalled();
-        })
-        .fail(function(err) {
-            console.log(err);
-            expect(err).toBeUndefined();
-        })
-        .fin(done);
-    });
-
-    it('should allow for hook to opt into asynchronous execution and block further hooks from firing using the done callback', function(done) {
-        var h1_fired = false;
-        var h1 = function() {
-            h1_fired = true;
-            expect(h2_fired).toBe(false);
-            return Q();
-        };
-        var h2_fired = false;
-        var h2 = function() {
-            h2_fired = true;
-            expect(h1_fired).toBe(true);
-            return Q();
-        };
-
-        cordova.on(test_event, h1);
-        cordova.on(test_event, h2);
-        h.fire(test_event).then(function() {
-            expect(h1_fired).toBe(true);
-            expect(h2_fired).toBe(true);
-            done();
-        });
-    });
-
-    it('should pass data object that fire calls into async handlers', function(done) {
-        var data = {
-            "hi":"ho",
-            "offtowork":"wego"
-        };
-        var async = function(opts) {
-            data.root = tmpDir;
-            expect(opts).toEqual(data);
-            return Q();
-        };
-        cordova.on(test_event, async);
-        h.fire(test_event, data).then(done);
-    });
-
-    it('should pass data object that fire calls into sync handlers', function(done) {
-        var data = {
-            "hi":"ho",
-            "offtowork":"wego"
-        };
-        var async = function(opts) {
-            data.root = tmpDir;
-            expect(opts).toEqual(data);
-        };
-        cordova.on(test_event, async);
-        h.fire(test_event, data).then(done);
-    });
-});
-
-
-describe('hooks', function() {
-    var h;
-    beforeEach(function() {
-        h = new hooker(project);
-    });
-
-
-    it('should not error if the hook is unrecognized', function(done) {
-        h.fire('CLEAN YOUR SHORTS GODDAMNIT LIKE A BIG BOY!')
-        .fail(function (err) {
-            expect('Call with unrecogized hook ').toBe('successful.\n' + err);
-        })
-        .fin(done);
-    });
-
-    it('should error if any script exits with non-zero code', function(done) {
-        h.fire('fail').then(function() {
-            expect('the call').toBe('a failure');
-        }, function(err) {
-            expect(err).toBeDefined();
-        })
-        .fin(done);
-    });
-
-    it('should execute all scripts in order', function(done) {
-        h.fire('test')
-        .then(function() {
-            var hooksOrderFile = path.join(project, 'hooks_order.txt');
-            var hooksEnvFile = path.join(project, 'hooks_env.json');
-            var hooksParamsFile = path.join(project, 'hooks_params.txt');
-            expect(hooksOrderFile).toExist();
-            expect(hooksEnvFile).toExist();
-            expect(hooksParamsFile).toExist();
-            expect(path.join(project, 'dotted_hook_should_not_fire.txt')).not.toExist();
-
-            var order = fs.readFileSync(hooksOrderFile, 'ascii').replace(/\W/gm, '');
-            expect(order).toBe('ab');
-
-            var params = fs.readFileSync(hooksParamsFile, 'ascii').trim().trim('"');
-            expect(params).toMatch(project.replace(/\\/g, '\\\\'));
-
-            var env = JSON.parse(fs.readFileSync(hooksEnvFile, 'ascii'));
-            expect(env.CORDOVA_VERSION).toEqual(require('../package').version);
-        })
-        .fail(function(err) {
-            console.log(err);
-            expect('Test hook call').toBe('successful');
-        })
-        .fin(done);
-
-    });
-
-    // Cleanup. Must be the last spec. Is there a better place for final cleanup in Jasmine?
-    it('should not fail during cleanup', function() {
-        process.chdir(path.join(__dirname, '..'));  // Non e2e tests assume CWD is repo root.
-        if(ext == 'sh') {
-            //shell.rm('-rf', tmpDir);
-        } else { // Windows:
-            // For some mysterious reason, both shell.rm and RMDIR /S /Q won't
-            // delete the dir on Windows, but they do remove the files leaving
-            // only folders. But the dir is removed just fine by
-            // shell.rm('-rf', tmpDir) at the top of this file with the next
-            // invocation of this test. The benefit of RMDIR /S /Q is that it
-            // doesn't print warnings like shell.rmdir() that look like this:
-            // rm: could not remove directory (code ENOTEMPTY): C:\Users\...
-            var cmd =  'RMDIR /S /Q ' + tmpDir;
-            child_process.exec(cmd);
-        }
-    });
-});

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/eed41399/cordova-lib/spec-cordova/lazy_load.spec.js
----------------------------------------------------------------------
diff --git a/cordova-lib/spec-cordova/lazy_load.spec.js b/cordova-lib/spec-cordova/lazy_load.spec.js
index 72a26bf..f62f4c6 100644
--- a/cordova-lib/spec-cordova/lazy_load.spec.js
+++ b/cordova-lib/spec-cordova/lazy_load.spec.js
@@ -22,7 +22,7 @@ var lazy_load = require('../src/cordova/lazy_load'),
     shell = require('shelljs'),
     npmconf = require('npmconf');
     path = require('path'),
-    hooker = require('../src/cordova/hooker'),
+    HooksRunner = require('../src/hooks/HooksRunner'),
     request = require('request'),
     fs = require('fs'),
     Q = require('q'),
@@ -78,7 +78,7 @@ describe('lazy_load module', function() {
             mv = spyOn(shell, 'mv');
             exists = spyOn(fs, 'existsSync').andReturn(false);
             readdir = spyOn(fs, 'readdirSync').andReturn(['somefile.txt']);
-            fire = spyOn(hooker, 'fire').andReturn(Q());
+            fire = spyOn(HooksRunner, 'fire').andReturn(Q());
         });
 
         it('should callback with no errors and not fire event hooks if library already exists', function(done) {

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/eed41399/cordova-lib/spec-cordova/prepare.spec.js
----------------------------------------------------------------------
diff --git a/cordova-lib/spec-cordova/prepare.spec.js b/cordova-lib/spec-cordova/prepare.spec.js
index 475b90e..44d16b2 100644
--- a/cordova-lib/spec-cordova/prepare.spec.js
+++ b/cordova-lib/spec-cordova/prepare.spec.js
@@ -26,7 +26,7 @@ var cordova = require('../src/cordova/cordova'),
     lazy_load = require('../src/cordova/lazy_load'),
     ConfigParser = require('../src/configparser/ConfigParser'),
     platforms = require('../src/cordova/platforms'),
-    hooker = require('../src/cordova/hooker'),
+    HooksRunner = require('../src/hooks/HooksRunner'),
     xmlHelpers = require('../src/util/xml-helpers'),
     fixtures = path.join(__dirname, 'fixtures'),
     et = require('elementtree'),
@@ -71,7 +71,7 @@ describe('prepare command', function() {
         is_cordova = spyOn(util, 'isCordova').andReturn(project_dir);
         cd_project_root = spyOn(util, 'cdProjectRoot').andReturn(project_dir);
         list_platforms = spyOn(util, 'listPlatforms').andReturn(supported_platforms);
-        fire = spyOn(hooker.prototype, 'fire').andReturn(Q());
+        fire = spyOn(HooksRunner.prototype, 'fire').andReturn(Q());
         supported_platforms.forEach(function(p) {
             parsers[p] = jasmine.createSpy(p + ' update_project').andReturn(Q());
             spyOn(platforms[p], 'parser').andReturn({

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/eed41399/cordova-lib/spec-cordova/run.spec.js
----------------------------------------------------------------------
diff --git a/cordova-lib/spec-cordova/run.spec.js b/cordova-lib/spec-cordova/run.spec.js
index ec33f0f..7234a6d 100644
--- a/cordova-lib/spec-cordova/run.spec.js
+++ b/cordova-lib/spec-cordova/run.spec.js
@@ -21,7 +21,7 @@ var cordova = require('../src/cordova/cordova'),
     superspawn = require('../src/cordova/superspawn'),
     path = require('path'),
     fs = require('fs'),
-    hooker = require('../src/cordova/hooker'),
+    HooksRunner = require('../src/hooks/HooksRunner'),
     Q = require('q'),
     util = require('../src/cordova/util');
 
@@ -36,7 +36,7 @@ describe('run command', function() {
         is_cordova = spyOn(util, 'isCordova').andReturn(project_dir);
         cd_project_root = spyOn(util, 'cdProjectRoot').andReturn(project_dir);
         list_platforms = spyOn(util, 'listPlatforms').andReturn(supported_platforms);
-        fire = spyOn(hooker.prototype, 'fire').andReturn(Q());
+        fire = spyOn(HooksRunner.prototype, 'fire').andReturn(Q());
         prepare_spy = spyOn(cordova.raw, 'prepare').andReturn(Q());
         spyOn(superspawn, 'spawn').andReturn(Q);
     });

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/eed41399/cordova-lib/spec-cordova/serve.spec.js
----------------------------------------------------------------------
diff --git a/cordova-lib/spec-cordova/serve.spec.js b/cordova-lib/spec-cordova/serve.spec.js
index 2ea37c2..5c238e3 100644
--- a/cordova-lib/spec-cordova/serve.spec.js
+++ b/cordova-lib/spec-cordova/serve.spec.js
@@ -23,7 +23,6 @@ var cordova = require('../src/cordova/cordova'),
     fs = require('fs'),
     Q = require('q'),
     util = require('../src/cordova/util'),
-    hooker = require('../src/cordova/hooker'),
     tempDir,
     http = require('http'),
     firefoxos_parser = require('../src/cordova/metadata/firefoxos_parser'),


[05/13] git commit: CB-6481 Updated docs

Posted by sg...@apache.org.
CB-6481 Updated docs


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

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

----------------------------------------------------------------------
 cordova-lib/templates/hooks-README.md | 50 +++++++++++++-----------------
 1 file changed, 21 insertions(+), 29 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/d8c586ab/cordova-lib/templates/hooks-README.md
----------------------------------------------------------------------
diff --git a/cordova-lib/templates/hooks-README.md b/cordova-lib/templates/hooks-README.md
index 5b9aa04..66f2873 100644
--- a/cordova-lib/templates/hooks-README.md
+++ b/cordova-lib/templates/hooks-README.md
@@ -75,36 +75,36 @@ To execute custom action when corresponding hook type is fired, use hook type as
 
 ### Config.xml
 
-Hooks can be defined in project's `config.xml` using `<script>` elements, for example:
+Hooks can be defined in project's `config.xml` using `<hook>` elements, for example:
 
-    <script type="before_build" src="scripts/appBeforeBuild.bat" />
-    <script type="before_build" src="scripts/appBeforeBuild.js" />
-    <script type="before_plugin_install" src="scripts/appBeforePluginInstall.js" />
+    <hook type="before_build" src="scripts/appBeforeBuild.bat" />
+    <hook type="before_build" src="scripts/appBeforeBuild.js" />
+    <hook type="before_plugin_install" src="scripts/appBeforePluginInstall.js" />
 
     <platform name="wp8">
-        <script type="before_build" src="scripts/wp8/appWP8BeforeBuild.bat" />
-        <script type="before_build" src="scripts/wp8/appWP8BeforeBuild.js" />
-        <script type="before_plugin_install" src="scripts/wp8/appWP8BeforePluginInstall.js" />
+        <hook type="before_build" src="scripts/wp8/appWP8BeforeBuild.bat" />
+        <hook type="before_build" src="scripts/wp8/appWP8BeforeBuild.js" />
+        <hook type="before_plugin_install" src="scripts/wp8/appWP8BeforePluginInstall.js" />
         ...
     </platform>
 
     <platform name="windows8">
-        <script type="before_build" src="scripts/windows8/appWin8BeforeBuild.bat" />
-        <script type="before_build" src="scripts/windows8/appWin8BeforeBuild.js" />
-        <script type="before_plugin_install" src="scripts/windows8/appWin8BeforePluginInstall.js" />
+        <hook type="before_build" src="scripts/windows8/appWin8BeforeBuild.bat" />
+        <hook type="before_build" src="scripts/windows8/appWin8BeforeBuild.js" />
+        <hook type="before_plugin_install" src="scripts/windows8/appWin8BeforePluginInstall.js" />
         ...
     </platform>
 
 ### Plugin hooks (plugin.xml)
 
-As a plugin developer you can define hook scripts using `<script>` elements in a `plugin.xml` like that:
+As a plugin developer you can define hook scripts using `<hook>` elements in a `plugin.xml` like that:
 
-    <script type="before_plugin_install" src="scripts/beforeInstall.js" />
-    <script type="after_build" src="scripts/afterBuild.js" />
+    <hook type="before_plugin_install" src="scripts/beforeInstall.js" />
+    <hook type="after_build" src="scripts/afterBuild.js" />
 
     <platform name="wp8">
-        <script type="before_plugin_install" src="scripts/wp8BeforeInstall.js" />
-        <script type="before_build" src="scripts/wp8BeforeBuild.js" />
+        <hook type="before_plugin_install" src="scripts/wp8BeforeInstall.js" />
+        <hook type="before_build" src="scripts/wp8BeforeBuild.js" />
         ...
     </platform>
 
@@ -121,11 +121,11 @@ module.exports = function(context) {
 }
 ```
 
-You can make your scipts async using Q, which can be retrieved from `context.commonModules`:
+You can make your scipts async using Q:
 ```javascript
 module.exports = function(context) {
-    var Q = context.commonModules.Q;
-	var deferral = new Q.defer();
+    var Q = context.requireCordovaModule('q');
+    var deferral = new Q.defer();
 
     setTimeout(function(){
     	console.log('hook.js>> end');
@@ -136,7 +136,7 @@ module.exports = function(context) {
 }
 ```
 
-`context` object contains hook type, executed script full path, hook options, common modules, and command-line arguments passed to Cordova:
+`context` object contains hook type, executed script full path, hook options, command-line arguments passed to Cordova and top-level "cordova" object:
 ```json
 {
 	"hook": "before_plugin_install",
@@ -158,14 +158,7 @@ module.exports = function(context) {
 			"dir": "C:\\path\\to\\the\\project\\plugins\\com.plugin.withhooks"
 		}
 	},
-	"commonModules": { 
-		"fs": { ... },
-		"path": { ... },
-		"os": { ... },
-		"events": { ... },
-		"util": { ... },
-		"cordovaUtil": { ... }
-	}
+	"cordova": {...}
 }
 
 ```
@@ -173,8 +166,7 @@ module.exports = function(context) {
 
 You can also require additional Cordova modules in your script using `context.requireCordovaModule` in the following way:
 ```javascript
-var et = context.requireCordovaModule('elementtree');
-var xmlHelpers = context.requireCordovaModule('../util/xml-helpers');
+var Q = context.requireCordovaModule('q');
 ```
 
 __Note__:  new module loader script interface is used for the `.js` files defined via `config.xml` or `plugin.xml` only. 


[02/13] git commit: CB-6481 Added unified hooks support for cordova app and plugins

Posted by sg...@apache.org.
CB-6481 Added unified hooks support for cordova app and plugins

* Hooks can be defined in .cordova/hooks/hook_type, hooks/hook_type directories, config.xml and plugins/.../plugin.xml
* Javascript hooks retrieved from config.xml and plugins/.../plugin.xml will be run via new module loader
* Introduced before_plugin_install, after_plugin_install and before_plugin_uninstall hooks


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

Branch: refs/heads/master
Commit: a9724517a5f8528308e44c1557c2e8326625ccb3
Parents: 8abfaf1
Author: daserge <da...@yandex.ru>
Authored: Wed Jul 9 16:08:59 2014 +0400
Committer: daserge <da...@yandex.ru>
Committed: Thu Sep 25 18:59:08 2014 +0400

----------------------------------------------------------------------
 cordova-lib/src/PluginInfo.js                   |  20 +++
 cordova-lib/src/configparser/ConfigParser.js    |  24 +++
 cordova-lib/src/cordova/build.js                |  16 +-
 cordova-lib/src/cordova/compile.js              |   1 +
 cordova-lib/src/cordova/emulate.js              |   1 +
 cordova-lib/src/cordova/lazy_load.js            |   1 +
 .../src/cordova/metadata/windows_parser.js      |   1 +
 cordova-lib/src/cordova/metadata/wp8_parser.js  |   1 +
 cordova-lib/src/cordova/platform.js             |   1 +
 cordova-lib/src/cordova/plugin.js               |   1 +
 cordova-lib/src/cordova/prepare.js              |   1 +
 cordova-lib/src/cordova/run.js                  |   1 +
 cordova-lib/src/cordova/serve.js                |   1 +
 cordova-lib/src/hooks/Context.js                |  52 ++++++
 cordova-lib/src/hooks/Hooker.js                 |  94 +++++++++++
 cordova-lib/src/hooks/ScriptsFinder.js          | 158 ++++++++++++++++++
 cordova-lib/src/hooks/ScriptsRunner.js          | 162 +++++++++++++++++++
 cordova-lib/src/plugman/install.js              |  26 ++-
 cordova-lib/src/plugman/uninstall.js            |  27 +++-
 19 files changed, 578 insertions(+), 11 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/a9724517/cordova-lib/src/PluginInfo.js
----------------------------------------------------------------------
diff --git a/cordova-lib/src/PluginInfo.js b/cordova-lib/src/PluginInfo.js
index 94d6fb1..98e4fec 100644
--- a/cordova-lib/src/PluginInfo.js
+++ b/cordova-lib/src/PluginInfo.js
@@ -200,6 +200,26 @@ function PluginInfo(dirname) {
         var libFiles = _getTagsInPlatform(self._et, 'lib-file', platform, cloneAttribs);
         return libFiles;
     }
+    
+    // <script>
+    // Example:
+    // <script type="before_build" src="scripts/beforeBuild.js" />
+    self.getHookScripts = getHookScripts;
+    function getHookScripts(hook, platforms) {
+        var scriptElements =  self._et.findall('./script');
+
+        if(platforms) {
+            platforms.forEach(function (platform) {
+                scriptElements = scriptElements.concat(self._et.findall('./platform[@name="' + platform + '"]/script'));
+            });
+        }
+
+        function filterScriptByHookType(el) {
+            return el.attrib.src && el.attrib.type && el.attrib.type.toLowerCase() === hook;
+        }
+
+        return scriptElements.filter(filterScriptByHookType);
+    }
     ///// End of PluginInfo methods /////
 
 

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/a9724517/cordova-lib/src/configparser/ConfigParser.js
----------------------------------------------------------------------
diff --git a/cordova-lib/src/configparser/ConfigParser.js b/cordova-lib/src/configparser/ConfigParser.js
index da6376e..e02c4e8 100644
--- a/cordova-lib/src/configparser/ConfigParser.js
+++ b/cordova-lib/src/configparser/ConfigParser.js
@@ -228,6 +228,29 @@ ConfigParser.prototype = {
     getSplashScreens: function(platform) {
         return this.getStaticResources(platform, 'splash');
     },
+    
+    /**
+     * Returns all hook scripts for the hook type specified.
+     * @param  {String} hook     The hook type.
+     * @param {Array}  platforms Platforms to look for scripts into (root scripts will be included as well).
+     * @return {Array}               Script elements.
+     */
+    getHookScripts: function(hook, platforms) {
+        var self = this;
+        var scriptElements = self.doc.findall('./script');
+
+        if(platforms) {
+            platforms.forEach(function (platform) {
+                scriptElements = scriptElements.concat(self.doc.findall('./platform[@name="' + platform + '"]/script'));
+            });
+        }
+
+        function filterScriptByHookType(el) {
+            return el.attrib.src && el.attrib.type && el.attrib.type.toLowerCase() === hook;
+        }
+
+        return scriptElements.filter(filterScriptByHookType);
+    },
 
     /**
      * Returns a list of features (IDs)
@@ -316,6 +339,7 @@ ConfigParser.prototype = {
         }
     },
 
+
     /**
      *This does not check for duplicate feature entries
      */

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/a9724517/cordova-lib/src/cordova/build.js
----------------------------------------------------------------------
diff --git a/cordova-lib/src/cordova/build.js b/cordova-lib/src/cordova/build.js
index 384d9e2..1469c6b 100644
--- a/cordova-lib/src/cordova/build.js
+++ b/cordova-lib/src/cordova/build.js
@@ -21,12 +21,12 @@
           indent:4, unused:vars, latedef:nofunc
 */
 
-var cordova_util      = require('./util'),
-    hooker            = require('./hooker');
+var cordovaUtil      = require('./util'),
+    Hooker           = require('../hooks/Hooker');
 
 // Returns a promise.
 module.exports = function build(options) {
-    var projectRoot = cordova_util.cdProjectRoot();
+    var projectRoot = cordovaUtil.cdProjectRoot();
 
     if (!options) {
         options = {
@@ -36,16 +36,18 @@ module.exports = function build(options) {
         };
     }
 
-    options = cordova_util.preProcessOptions(options);
+    options = cordovaUtil.preProcessOptions(options);
+
+    var hookOptions = { projectRoot: projectRoot, cordova: options };
 
     // fire build hooks
-    var hooks = new hooker(projectRoot);
-    return hooks.fire('before_build', options)
+    var hooker = new Hooker(projectRoot);
+    return hooker.fire('before_build', hookOptions)
     .then(function() {
         return require('./cordova').raw.prepare(options);
     }).then(function() {
         return require('./cordova').raw.compile(options);
     }).then(function() {
-        return hooks.fire('after_build', options);
+        return hooker.fire('after_build', hookOptions);
     });
 };

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/a9724517/cordova-lib/src/cordova/compile.js
----------------------------------------------------------------------
diff --git a/cordova-lib/src/cordova/compile.js b/cordova-lib/src/cordova/compile.js
index 814d3eb..558b0c0 100644
--- a/cordova-lib/src/cordova/compile.js
+++ b/cordova-lib/src/cordova/compile.js
@@ -31,6 +31,7 @@ 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);
     options.platforms.forEach(function(platform) {

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/a9724517/cordova-lib/src/cordova/emulate.js
----------------------------------------------------------------------
diff --git a/cordova-lib/src/cordova/emulate.js b/cordova-lib/src/cordova/emulate.js
index 2f23197..651a434 100644
--- a/cordova-lib/src/cordova/emulate.js
+++ b/cordova-lib/src/cordova/emulate.js
@@ -32,6 +32,7 @@ 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)
     .then(function() {

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/a9724517/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 8ea791b..943adc8 100644
--- a/cordova-lib/src/cordova/lazy_load.js
+++ b/cordova-lib/src/cordova/lazy_load.js
@@ -186,6 +186,7 @@ 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', {
         platform:platform,
         url:url,

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/a9724517/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 353d68b..3e4a632 100644
--- a/cordova-lib/src/cordova/metadata/windows_parser.js
+++ b/cordova-lib/src/cordova/metadata/windows_parser.js
@@ -244,6 +244,7 @@ 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'] })
         .then(function() {

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/a9724517/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 4d5b332..9798a6e 100644
--- a/cordova-lib/src/cordova/metadata/wp8_parser.js
+++ b/cordova-lib/src/cordova/metadata/wp8_parser.js
@@ -209,6 +209,7 @@ 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']  })
         .then(function() {

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/a9724517/cordova-lib/src/cordova/platform.js
----------------------------------------------------------------------
diff --git a/cordova-lib/src/cordova/platform.js b/cordova-lib/src/cordova/platform.js
index 487803e..7becd9e 100644
--- a/cordova-lib/src/cordova/platform.js
+++ b/cordova-lib/src/cordova/platform.js
@@ -203,6 +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);
         // Acquire the version number of each platform we have installed, and output that too.
         Q.all(platforms_on_fs.map(function(p) {

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/a9724517/cordova-lib/src/cordova/plugin.js
----------------------------------------------------------------------
diff --git a/cordova-lib/src/cordova/plugin.js b/cordova-lib/src/cordova/plugin.js
index 5d4562f..f608a38 100644
--- a/cordova-lib/src/cordova/plugin.js
+++ b/cordova-lib/src/cordova/plugin.js
@@ -59,6 +59,7 @@ module.exports = function plugin(command, targets, opts) {
     opts.options = opts.options || [];
     opts.plugins = [];
 
+    // TODO: Replace with unified Hooker
     var hooks = new hooker(projectRoot);
     var platformList = cordova_util.listPlatforms(projectRoot);
 

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/a9724517/cordova-lib/src/cordova/prepare.js
----------------------------------------------------------------------
diff --git a/cordova-lib/src/cordova/prepare.js b/cordova-lib/src/cordova/prepare.js
index 8b4b545..1906d78 100644
--- a/cordova-lib/src/cordova/prepare.js
+++ b/cordova-lib/src/cordova/prepare.js
@@ -56,6 +56,7 @@ function prepare(options) {
     });
     options.paths = paths;
 
+    // TODO: Replace with unified Hooker
     var hooks = new hooker(projectRoot);
     return hooks.fire('before_prepare', options)
     .then(function() {

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/a9724517/cordova-lib/src/cordova/run.js
----------------------------------------------------------------------
diff --git a/cordova-lib/src/cordova/run.js b/cordova-lib/src/cordova/run.js
index 8ccdb38..abde56f 100644
--- a/cordova-lib/src/cordova/run.js
+++ b/cordova-lib/src/cordova/run.js
@@ -32,6 +32,7 @@ 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)
     .then(function() {

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/a9724517/cordova-lib/src/cordova/serve.js
----------------------------------------------------------------------
diff --git a/cordova-lib/src/cordova/serve.js b/cordova-lib/src/cordova/serve.js
index 26c114b..2d88d7b 100644
--- a/cordova-lib/src/cordova/serve.js
+++ b/cordova-lib/src/cordova/serve.js
@@ -247,6 +247,7 @@ 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')
     .then(function() {

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/a9724517/cordova-lib/src/hooks/Context.js
----------------------------------------------------------------------
diff --git a/cordova-lib/src/hooks/Context.js b/cordova-lib/src/hooks/Context.js
new file mode 100644
index 0000000..936c9c1
--- /dev/null
+++ b/cordova-lib/src/hooks/Context.js
@@ -0,0 +1,52 @@
+/**
+ 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'),
+    path = require('path'),
+    os = require('os'),
+    events = require('../events');
+
+/**
+ * Creates hook script context
+ * @constructor
+ * @param {String} hook The hook type
+ * @param {Object} opts Hook options
+ * @returns {Object} */
+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')
+    };
+}
+
+/**
+ * Returns a required module
+ * @param {String} path Module path
+ * @returns {Object} */
+Context.prototype.requireCordovaModule = function (path) {
+    return require(path);
+};
+
+module.exports = Context;
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/a9724517/cordova-lib/src/hooks/Hooker.js
----------------------------------------------------------------------
diff --git a/cordova-lib/src/hooks/Hooker.js b/cordova-lib/src/hooks/Hooker.js
new file mode 100644
index 0000000..9951e20
--- /dev/null
+++ b/cordova-lib/src/hooks/Hooker.js
@@ -0,0 +1,94 @@
+/**
+ 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'),
+    CordovaError = require('../CordovaError');
+
+/**
+ * Tries to create a hooker for passed project root.
+ * @constructor
+ */
+function Hooker(projectRoot) {
+    if (!util.isCordova(projectRoot)) {
+        throw new CordovaError('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 CordovaError('hook type is not specified');
+    }
+    // execute hook event listeners first
+    return setPluginsProperty(opts).then(function(){
+        setCordovaVersionProperty(opts);
+
+        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);
+    });
+};
+
+/**
+ * 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/a9724517/cordova-lib/src/hooks/ScriptsFinder.js
----------------------------------------------------------------------
diff --git a/cordova-lib/src/hooks/ScriptsFinder.js b/cordova-lib/src/hooks/ScriptsFinder.js
new file mode 100644
index 0000000..5fb9ed2
--- /dev/null
+++ b/cordova-lib/src/hooks/ScriptsFinder.js
@@ -0,0 +1,158 @@
+/**
+ 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 path = require('path'),
+    fs = require('fs'),
+    cordovaUtil = require('../cordova/util'),
+    events = require('../events'),
+    Q = require('q'),
+    plugin  = require('../cordova/plugin'),
+    PluginInfo = require('../PluginInfo'),
+    ConfigParser = require('../configparser/ConfigParser'),
+    CordovaError = require('../CordovaError'),
+    Context = require('./Context');
+
+/**
+ * Implements logic to retrieve hook script files defined in special folders and configuration
+ * files: config.xml, hooks/hook_type, plugins/../plugin.xml, etc
+ */
+module.exports  = {
+    /**
+     * Returns all script files for the hook type specified.
+     */
+    getHookScripts: function(hook, opts) {
+        // args check
+        if (!hook) {
+            throw new CordovaError('hook type is not specified');
+        }
+        return getApplicationHookScripts(hook, opts)
+            .concat(getPluginsHookScripts(hook, opts));
+    }
+};
+
+/**
+ * Returns script files defined on application level.
+ * They are stored in .cordova/hooks folders and in config.xml.
+ */
+function getApplicationHookScripts(hook, opts) {
+    // args check
+    if (!hook) {
+        throw new CordovaError('hook type is not specified');
+    }
+    return getApplicationHookScriptsFromDir(path.join(opts.projectRoot, '.cordova', 'hooks', hook))
+        .concat(getApplicationHookScriptsFromDir(path.join(opts.projectRoot, 'hooks', hook)))
+        .concat(getScriptsFromConfigXml(hook, opts));
+}
+
+/**
+ * Returns script files defined by plugin developers as part of plugin.xml.
+ */
+function getPluginsHookScripts(hook, opts) {
+    // args check
+    if (!hook) {
+        throw new CordovaError('hook type is not specified');
+    }
+
+    // In case before_plugin_install, after_plugin_install, before_plugin_uninstall hooks we receive opts.plugin and
+    // retrieve scripts exclusive for this plugin.
+    if(opts.plugin) {
+        events.emit('debug', 'Executing "' + hook + '"  hook for "' + opts.plugin.id + '" on ' + opts.plugin.platform + '.');
+
+        return getPluginScriptFiles(opts.plugin, hook, [ opts.plugin.platform ]);
+    }
+
+    events.emit('debug', 'Executing "' + hook + '"  hook for all plugins.');
+    return getAllPluginsHookScriptFiles(hook, opts);
+}
+
+/**
+ * Gets application level hooks from the directrory specified.
+ */
+function getApplicationHookScriptsFromDir(dir) {
+    if (!(fs.existsSync(dir))) {
+        return [];
+    }
+
+    var compareNumbers = function(a, b) {
+        // TODO SG looks very complex, do we really need this?
+        return isNaN (parseInt(a, 10)) ? a.toLowerCase().localeCompare(b.toLowerCase ? b.toLowerCase(): b)
+            : parseInt(a, 10) > parseInt(b, 10) ? 1 : parseInt(a, 10) < parseInt(b, 10) ? -1 : 0;
+    };
+
+    var scripts = fs.readdirSync(dir).sort(compareNumbers).filter(function(s) {
+        return s[0] != '.';
+    });
+    return scripts.map(function (scriptPath) {
+        // for old style hook files we don't use module loader for backward compatibility
+        return { path: scriptPath, fullPath: path.join(dir, scriptPath), useModuleLoader: false };
+    });
+}
+
+/**
+ * Gets all scripts defined in config.xml with the specified type and platforms.
+ */
+function getScriptsFromConfigXml(hook, opts) {
+    var configPath = cordovaUtil.projectConfig(opts.projectRoot);
+    var configXml = new ConfigParser(configPath);
+
+    return configXml.getHookScripts(hook, opts.cordova.platforms).map(function(scriptElement) {
+        return {
+            path: scriptElement.attrib.src,
+            fullPath: path.join(opts.projectRoot, scriptElement.attrib.src)
+        };
+    });
+}
+
+/**
+ * Gets hook scripts defined by the plugin.
+ */
+function getPluginScriptFiles(plugin, hook, platforms) {
+    var scriptElements = plugin.pluginInfo.getHookScripts(hook, platforms);
+
+    return scriptElements.map(function(scriptElement) {
+        return {
+            path: scriptElement.attrib.src,
+            fullPath: path.join(plugin.dir, scriptElement.attrib.src),
+            plugin: plugin
+        };
+    });
+}
+
+/**
+ * Gets hook scripts defined by all plugins.
+ */
+function getAllPluginsHookScriptFiles(hook, opts) {
+    var scripts = [];
+    var pluginDir;
+    var pluginInfo;
+    var currentPluginOptions;
+
+    opts.cordova.plugins.forEach(function(pluginId) {
+        pluginDir = path.join(opts.projectRoot, 'plugins', pluginId);
+
+        currentPluginOptions = {
+            id: pluginId,
+            pluginInfo: new PluginInfo.PluginInfo(pluginDir),
+            dir: pluginDir
+        };
+        
+        scripts = scripts.concat(getPluginScriptFiles(currentPluginOptions, hook, opts.cordova.platforms));
+    });
+    return scripts;
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/a9724517/cordova-lib/src/hooks/ScriptsRunner.js
----------------------------------------------------------------------
diff --git a/cordova-lib/src/hooks/ScriptsRunner.js b/cordova-lib/src/hooks/ScriptsRunner.js
new file mode 100644
index 0000000..c7ff70d
--- /dev/null
+++ b/cordova-lib/src/hooks/ScriptsRunner.js
@@ -0,0 +1,162 @@
+/**
+ 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'),
+    CordovaError = require('../CordovaError'),
+    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 CordovaError('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/a9724517/cordova-lib/src/plugman/install.js
----------------------------------------------------------------------
diff --git a/cordova-lib/src/plugman/install.js b/cordova-lib/src/plugman/install.js
index 045afb7..4823b68 100644
--- a/cordova-lib/src/plugman/install.js
+++ b/cordova-lib/src/plugman/install.js
@@ -38,7 +38,9 @@ var path = require('path'),
     shell   = require('shelljs'),
     events = require('../events'),
     plugman = require('./plugman'),
-    isWindows = (os.platform().substr(0,3) === 'win');
+    Hooker = require('../hooks/Hooker'),
+    isWindows = (os.platform().substr(0,3) === 'win'),
+    cordovaUtil = require('../cordova/util');
 
 /* INSTALL FLOW
    ------------
@@ -319,7 +321,27 @@ function runInstall(actions, platform, project_dir, plugin_dir, plugins_dir, opt
                 copyPlugin(plugin_dir, plugins_dir, options.link);
             }
 
-            return handleInstall(actions, pluginInfo, platform, project_dir, plugins_dir, install_plugin_dir, filtered_variables, options);
+            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
+                }
+            };
+
+            var hooker = new Hooker(projectRoot);
+
+            hooker.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 hooker.fire('after_plugin_install', hookOptions);
+            });
         }
     ).fail(
         function (error) {

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/a9724517/cordova-lib/src/plugman/uninstall.js
----------------------------------------------------------------------
diff --git a/cordova-lib/src/plugman/uninstall.js b/cordova-lib/src/plugman/uninstall.js
index 06bcb85..0a48fa2 100644
--- a/cordova-lib/src/plugman/uninstall.js
+++ b/cordova-lib/src/plugman/uninstall.js
@@ -32,11 +32,13 @@ var path = require('path'),
     CordovaError  = require('../CordovaError'),
     underscore = require('underscore'),
     Q = require('q'),
-    underscore = require('underscore'),
     events = require('../events'),
     platform_modules = require('./platforms'),
     plugman = require('./plugman'),
-    promiseutil = require('../util/promise-util');
+    promiseutil = require('../util/promise-util'),
+    Hooker = require('../hooks/Hooker'),
+    PluginInfo = require('../PluginInfo'),
+    cordovaUtil      = require('../cordova/util');
 
 // possible options: cli_variables, www_dir
 // Returns a promise.
@@ -237,8 +239,29 @@ function runUninstallPlatform(actions, platform, project_dir, plugin_dir, plugin
         promise = Q();
     }
 
+    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);
+
     return promise.then(function() {
+        return hooker.fire('before_plugin_uninstall', hookerOptions);
+    }).then(function() {
         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);
     });
 }
 


[09/13] git commit: CB-6481 Fixed HooksRunner and tests Avoided issue with parallel tests running Added checks for handling mocked config.xml and package.json in HooksRunner and scriptsFinder Addressed jshint issues Renamed ScriptsFinder to scriptsFinder

Posted by sg...@apache.org.
CB-6481 Fixed HooksRunner and tests
Avoided issue with parallel tests running
Added checks for handling mocked config.xml and package.json in HooksRunner and scriptsFinder
Addressed jshint issues
Renamed ScriptsFinder to scriptsFinder


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

Branch: refs/heads/master
Commit: a3169336634508246754b8e52bd452edba5ecc7f
Parents: eed4139
Author: daserge <v-...@microsoft.com>
Authored: Thu Jul 24 08:09:08 2014 -0700
Committer: daserge <da...@yandex.ru>
Committed: Thu Sep 25 19:04:55 2014 +0400

----------------------------------------------------------------------
 cordova-lib/spec-cordova/HooksRunner.spec.js |  16 ++-
 cordova-lib/src/cordova/plugin.js            |   1 -
 cordova-lib/src/hooks/HooksRunner.js         |  10 +-
 cordova-lib/src/hooks/ScriptsFinder.js       | 156 --------------------
 cordova-lib/src/hooks/scriptsFinder.js       | 164 ++++++++++++++++++++++
 5 files changed, 181 insertions(+), 166 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/a3169336/cordova-lib/spec-cordova/HooksRunner.spec.js
----------------------------------------------------------------------
diff --git a/cordova-lib/spec-cordova/HooksRunner.spec.js b/cordova-lib/spec-cordova/HooksRunner.spec.js
index 1e89808..5cbb431 100644
--- a/cordova-lib/spec-cordova/HooksRunner.spec.js
+++ b/cordova-lib/spec-cordova/HooksRunner.spec.js
@@ -64,10 +64,6 @@ shell.chmod('-R', 'ug+x', hooksDir);
 shell.chmod('-R', 'ug+x', hooksDirDot);
 shell.chmod('-R', 'ug+x', scriptsDir);
 
-jasmine.getEnv().defaultTimeoutInterval = 3000;
-process.chdir(project);
-
-
 describe('HooksRunner', function() {
     var hooksRunner;
     var hookOptions;
@@ -75,6 +71,14 @@ describe('HooksRunner', function() {
     var projectRoot;
     var fire;
 
+    beforeEach(function() {
+        process.chdir(project);
+    });
+
+    afterEach(function() {
+        process.chdir(path.join(__dirname, '..'));  // Non e2e tests assume CWD is repo root.
+    });
+
     it('should throw if provided directory is not a cordova project', function() {
         expect(function() {
             new HooksRunner(tmpDir);
@@ -590,10 +594,8 @@ describe('HooksRunner', function() {
             }).fin(done);
         });
     });
-});
 
-describe('cleanup', function() {
-// Cleanup. Must be the last spec. Is there a better place for final cleanup in Jasmine?
+    // Cleanup. Must be the last spec. Is there a better place for final cleanup in Jasmine?
     it('should not fail during cleanup', function () {
         process.chdir(path.join(__dirname, '..'));  // Non e2e tests assume CWD is repo root.
         if (ext == 'sh') {

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/a3169336/cordova-lib/src/cordova/plugin.js
----------------------------------------------------------------------
diff --git a/cordova-lib/src/cordova/plugin.js b/cordova-lib/src/cordova/plugin.js
index 9d6b8ab..6763560 100644
--- a/cordova-lib/src/cordova/plugin.js
+++ b/cordova-lib/src/cordova/plugin.js
@@ -24,7 +24,6 @@
 var cordova_util  = require('./util'),
     path          = require('path'),
     semver        = require('semver'),
-    HooksRunner        = require('../hooks/HooksRunner'),
     config        = require('./config'),
     Q             = require('q'),
     CordovaError  = require('../CordovaError'),

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/a3169336/cordova-lib/src/hooks/HooksRunner.js
----------------------------------------------------------------------
diff --git a/cordova-lib/src/hooks/HooksRunner.js b/cordova-lib/src/hooks/HooksRunner.js
index 0f11da0..77ed54a 100644
--- a/cordova-lib/src/hooks/HooksRunner.js
+++ b/cordova-lib/src/hooks/HooksRunner.js
@@ -69,7 +69,13 @@ HooksRunner.prototype.prepareOptions = function(opts) {
     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;
+
+    try {
+        opts.cordova.version = opts.cordova.version || require('../../package').version;
+    } catch(ex) {
+        events.emit('err', 'HooksRunner could not load package.json: ' + ex.message);
+        console.log('HooksRunner could not load package.json: ' + ex.message);
+    }
 
     return opts;
 };
@@ -124,7 +130,7 @@ function runScriptsSerially (scripts, context) {
     }
     executePendingScript();
     return deferral.promise;
-};
+}
 
 /**
  * Async runs single script file.

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/a3169336/cordova-lib/src/hooks/ScriptsFinder.js
----------------------------------------------------------------------
diff --git a/cordova-lib/src/hooks/ScriptsFinder.js b/cordova-lib/src/hooks/ScriptsFinder.js
deleted file mode 100644
index 3345af1..0000000
--- a/cordova-lib/src/hooks/ScriptsFinder.js
+++ /dev/null
@@ -1,156 +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 path = require('path'),
-    fs = require('fs'),
-    cordovaUtil = require('../cordova/util'),
-    events = require('../events'),
-    Q = require('q'),
-    plugin  = require('../cordova/plugin'),
-    PluginInfo = require('../PluginInfo'),
-    ConfigParser = require('../configparser/ConfigParser');
-
-/**
- * Implements logic to retrieve hook script files defined in special folders and configuration
- * files: config.xml, hooks/hook_type, plugins/../plugin.xml, etc
- */
-module.exports  = {
-    /**
-     * Returns all script files for the hook type specified.
-     */
-    getHookScripts: function(hook, opts) {
-        // args check
-        if (!hook) {
-            throw new Error('hook type is not specified');
-        }
-        return getApplicationHookScripts(hook, opts)
-            .concat(getPluginsHookScripts(hook, opts));
-    }
-};
-
-/**
- * Returns script files defined on application level.
- * They are stored in .cordova/hooks folders and in config.xml.
- */
-function getApplicationHookScripts(hook, opts) {
-    // args check
-    if (!hook) {
-        throw new Error('hook type is not specified');
-    }
-    return getApplicationHookScriptsFromDir(path.join(opts.projectRoot, '.cordova', 'hooks', hook))
-        .concat(getApplicationHookScriptsFromDir(path.join(opts.projectRoot, 'hooks', hook)))
-        .concat(getScriptsFromConfigXml(hook, opts));
-}
-
-/**
- * Returns script files defined by plugin developers as part of plugin.xml.
- */
-function getPluginsHookScripts(hook, opts) {
-    // args check
-    if (!hook) {
-        throw new Error('hook type is not specified');
-    }
-
-    // In case before_plugin_install, after_plugin_install, before_plugin_uninstall hooks we receive opts.plugin and
-    // retrieve scripts exclusive for this plugin.
-    if(opts.plugin) {
-        events.emit('debug', 'Executing "' + hook + '"  hook for "' + opts.plugin.id + '" on ' + opts.plugin.platform + '.');
-
-        return getPluginScriptFiles(opts.plugin, hook, [ opts.plugin.platform ]);
-    }
-
-    events.emit('debug', 'Executing "' + hook + '"  hook for all plugins.');
-    return getAllPluginsHookScriptFiles(hook, opts);
-}
-
-/**
- * Gets application level hooks from the directrory specified.
- */
-function getApplicationHookScriptsFromDir(dir) {
-    if (!(fs.existsSync(dir))) {
-        return [];
-    }
-
-    var compareNumbers = function(a, b) {
-        // TODO SG looks very complex, do we really need this?
-        return isNaN (parseInt(a, 10)) ? a.toLowerCase().localeCompare(b.toLowerCase ? b.toLowerCase(): b)
-            : parseInt(a, 10) > parseInt(b, 10) ? 1 : parseInt(a, 10) < parseInt(b, 10) ? -1 : 0;
-    };
-
-    var scripts = fs.readdirSync(dir).sort(compareNumbers).filter(function(s) {
-        return s[0] != '.';
-    });
-    return scripts.map(function (scriptPath) {
-        // for old style hook files we don't use module loader for backward compatibility
-        return { path: scriptPath, fullPath: path.join(dir, scriptPath), useModuleLoader: false };
-    });
-}
-
-/**
- * Gets all scripts defined in config.xml with the specified type and platforms.
- */
-function getScriptsFromConfigXml(hook, opts) {
-    var configPath = cordovaUtil.projectConfig(opts.projectRoot);
-    var configXml = new ConfigParser(configPath);
-
-    return configXml.getHookScripts(hook, opts.cordova.platforms).map(function(scriptElement) {
-        return {
-            path: scriptElement.attrib.src,
-            fullPath: path.join(opts.projectRoot, scriptElement.attrib.src)
-        };
-    });
-}
-
-/**
- * Gets hook scripts defined by the plugin.
- */
-function getPluginScriptFiles(plugin, hook, platforms) {
-    var scriptElements = plugin.pluginInfo.getHookScripts(hook, platforms);
-
-    return scriptElements.map(function(scriptElement) {
-        return {
-            path: scriptElement.attrib.src,
-            fullPath: path.join(plugin.dir, scriptElement.attrib.src),
-            plugin: plugin
-        };
-    });
-}
-
-/**
- * Gets hook scripts defined by all plugins.
- */
-function getAllPluginsHookScriptFiles(hook, opts) {
-    var scripts = [];
-    var pluginDir;
-    var pluginInfo;
-    var currentPluginOptions;
-
-    opts.cordova.plugins.forEach(function(pluginId) {
-        pluginDir = path.join(opts.projectRoot, 'plugins', pluginId);
-
-        currentPluginOptions = {
-            id: pluginId,
-            pluginInfo: new PluginInfo.PluginInfo(pluginDir),
-            dir: pluginDir
-        };
-        
-        scripts = scripts.concat(getPluginScriptFiles(currentPluginOptions, hook, opts.cordova.platforms));
-    });
-    return scripts;
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/a3169336/cordova-lib/src/hooks/scriptsFinder.js
----------------------------------------------------------------------
diff --git a/cordova-lib/src/hooks/scriptsFinder.js b/cordova-lib/src/hooks/scriptsFinder.js
new file mode 100644
index 0000000..9abbb8e
--- /dev/null
+++ b/cordova-lib/src/hooks/scriptsFinder.js
@@ -0,0 +1,164 @@
+/**
+ 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 path = require('path'),
+    fs = require('fs'),
+    cordovaUtil = require('../cordova/util'),
+    events = require('../events'),
+    Q = require('q'),
+    plugin  = require('../cordova/plugin'),
+    PluginInfo = require('../PluginInfo'),
+    ConfigParser = require('../configparser/ConfigParser');
+
+/**
+ * Implements logic to retrieve hook script files defined in special folders and configuration
+ * files: config.xml, hooks/hook_type, plugins/../plugin.xml, etc
+ */
+module.exports  = {
+    /**
+     * Returns all script files for the hook type specified.
+     */
+    getHookScripts: function(hook, opts) {
+        // args check
+        if (!hook) {
+            throw new Error('hook type is not specified');
+        }
+        return getApplicationHookScripts(hook, opts)
+            .concat(getPluginsHookScripts(hook, opts));
+    }
+};
+
+/**
+ * Returns script files defined on application level.
+ * They are stored in .cordova/hooks folders and in config.xml.
+ */
+function getApplicationHookScripts(hook, opts) {
+    // args check
+    if (!hook) {
+        throw new Error('hook type is not specified');
+    }
+    return getApplicationHookScriptsFromDir(path.join(opts.projectRoot, '.cordova', 'hooks', hook))
+        .concat(getApplicationHookScriptsFromDir(path.join(opts.projectRoot, 'hooks', hook)))
+        .concat(getScriptsFromConfigXml(hook, opts));
+}
+
+/**
+ * Returns script files defined by plugin developers as part of plugin.xml.
+ */
+function getPluginsHookScripts(hook, opts) {
+    // args check
+    if (!hook) {
+        throw new Error('hook type is not specified');
+    }
+
+    // In case before_plugin_install, after_plugin_install, before_plugin_uninstall hooks we receive opts.plugin and
+    // retrieve scripts exclusive for this plugin.
+    if(opts.plugin) {
+        events.emit('debug', 'Executing "' + hook + '"  hook for "' + opts.plugin.id + '" on ' + opts.plugin.platform + '.');
+
+        return getPluginScriptFiles(opts.plugin, hook, [ opts.plugin.platform ]);
+    }
+
+    events.emit('debug', 'Executing "' + hook + '"  hook for all plugins.');
+    return getAllPluginsHookScriptFiles(hook, opts);
+}
+
+/**
+ * Gets application level hooks from the directrory specified.
+ */
+function getApplicationHookScriptsFromDir(dir) {
+    if (!(fs.existsSync(dir))) {
+        return [];
+    }
+
+    var compareNumbers = function(a, b) {
+        // TODO SG looks very complex, do we really need this?
+        return isNaN (parseInt(a, 10)) ? a.toLowerCase().localeCompare(b.toLowerCase ? b.toLowerCase(): b)
+            : parseInt(a, 10) > parseInt(b, 10) ? 1 : parseInt(a, 10) < parseInt(b, 10) ? -1 : 0;
+    };
+
+    var scripts = fs.readdirSync(dir).sort(compareNumbers).filter(function(s) {
+        return s[0] != '.';
+    });
+    return scripts.map(function (scriptPath) {
+        // for old style hook files we don't use module loader for backward compatibility
+        return { path: scriptPath, fullPath: path.join(dir, scriptPath), useModuleLoader: false };
+    });
+}
+
+/**
+ * Gets all scripts defined in config.xml with the specified type and platforms.
+ */
+function getScriptsFromConfigXml(hook, opts) {
+    var configPath = cordovaUtil.projectConfig(opts.projectRoot);
+    var configXml;
+
+    try {
+        configXml = new ConfigParser(configPath);
+    } catch(ex) {
+        events.emit('err', 'scriptsFinder could not load config.xml: ' + ex.message);
+        console.log('scriptsFinder could not load config.xml: ' + ex.message);
+        return [];
+    }
+
+    return configXml.getHookScripts(hook, opts.cordova.platforms).map(function(scriptElement) {
+        return {
+            path: scriptElement.attrib.src,
+            fullPath: path.join(opts.projectRoot, scriptElement.attrib.src)
+        };
+    });
+}
+
+/**
+ * Gets hook scripts defined by the plugin.
+ */
+function getPluginScriptFiles(plugin, hook, platforms) {
+    var scriptElements = plugin.pluginInfo.getHookScripts(hook, platforms);
+
+    return scriptElements.map(function(scriptElement) {
+        return {
+            path: scriptElement.attrib.src,
+            fullPath: path.join(plugin.dir, scriptElement.attrib.src),
+            plugin: plugin
+        };
+    });
+}
+
+/**
+ * Gets hook scripts defined by all plugins.
+ */
+function getAllPluginsHookScriptFiles(hook, opts) {
+    var scripts = [];
+    var pluginDir;
+    var pluginInfo;
+    var currentPluginOptions;
+
+    opts.cordova.plugins.forEach(function(pluginId) {
+        pluginDir = path.join(opts.projectRoot, 'plugins', pluginId);
+
+        currentPluginOptions = {
+            id: pluginId,
+            pluginInfo: new PluginInfo.PluginInfo(pluginDir),
+            dir: pluginDir
+        };
+        
+        scripts = scripts.concat(getPluginScriptFiles(currentPluginOptions, hook, opts.cordova.platforms));
+    });
+    return scripts;
+}
\ No newline at end of file


[13/13] git commit: CB-6481 Fixed comment

Posted by sg...@apache.org.
CB-6481 Fixed comment


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

Branch: refs/heads/master
Commit: 57f454b2875fd429d1b02da5bd5c3196d77363e6
Parents: a8cf9fd
Author: daserge <da...@yandex.ru>
Authored: Thu Sep 25 20:36:13 2014 +0400
Committer: daserge <da...@yandex.ru>
Committed: Thu Sep 25 20:36:13 2014 +0400

----------------------------------------------------------------------
 cordova-lib/src/PluginInfo.js | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/57f454b2/cordova-lib/src/PluginInfo.js
----------------------------------------------------------------------
diff --git a/cordova-lib/src/PluginInfo.js b/cordova-lib/src/PluginInfo.js
index 47fa293..2690fdf 100644
--- a/cordova-lib/src/PluginInfo.js
+++ b/cordova-lib/src/PluginInfo.js
@@ -201,9 +201,9 @@ function PluginInfo(dirname) {
         return libFiles;
     }
     
-    // <script>
+    // <hook>
     // Example:
-    // <script type="before_build" src="scripts/beforeBuild.js" />
+    // <hook type="before_build" src="scripts/beforeBuild.js" />
     self.getHookScripts = getHookScripts;
     function getHookScripts(hook, platforms) {
         var scriptElements =  self._et.findall('./hook');


[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

Posted by sg...@apache.org.
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.