Skip to content

Commit 9c1936b

Browse files
author
Georgi Alexandrov
committed
Enable Plugman to run hooks defined in plugin.xml
1 parent 024b970 commit 9c1936b

File tree

12 files changed

+123
-36
lines changed

12 files changed

+123
-36
lines changed

cordova-lib/spec-cordova/HooksRunner.spec.js

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -81,12 +81,6 @@ describe('HooksRunner', function() {
8181
process.chdir(path.join(__dirname, '..')); // Non e2e tests assume CWD is repo root.
8282
});
8383

84-
it('should throw if provided directory is not a cordova project', function() {
85-
expect(function() {
86-
new HooksRunner(tmpDir);
87-
}).toThrow();
88-
});
89-
9084
it('should not throw if provided directory is a cordova project', function() {
9185
expect(function () {
9286
new HooksRunner(project);
@@ -116,7 +110,6 @@ describe('HooksRunner', function() {
116110
return Q();
117111
});
118112

119-
120113
// Add the testing platform.
121114
cordova.raw.platform('add', [helpers.testPlatform]).fail(function (err) {
122115
expect(err).toBeUndefined();

cordova-lib/spec-plugman/install.spec.js

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ var install = require('../src/plugman/install'),
2525
events = require('../src/events'),
2626
plugman = require('../src/plugman/plugman'),
2727
platforms = require('../src/plugman/platforms/common'),
28+
HooksRunner = require('../src/hooks/HooksRunner'),
2829
common = require('./common'),
2930
fs = require('fs'),
3031
os = require('os'),
@@ -45,7 +46,8 @@ var install = require('../src/plugman/install'),
4546
'com.cordova.engine' : path.join(plugins_dir, 'com.cordova.engine'),
4647
'com.cordova.engine-android' : path.join(plugins_dir, 'com.cordova.engine-android'),
4748
'org.test.plugins.childbrowser' : path.join(plugins_dir, 'org.test.plugins.childbrowser'),
48-
'com.adobe.vars' : path.join(plugins_dir, 'com.adobe.vars'),
49+
'com.adobe.vars' : path.join(plugins_dir, 'com.adobe.vars'),
50+
'org.test.plugin-with-hooks' : path.join(plugins_dir, 'org.test.plugin-with-hooks'),
4951
'A' : path.join(plugins_dir, 'dependencies', 'A'),
5052
'B' : path.join(plugins_dir, 'dependencies', 'B'),
5153
'C' : path.join(plugins_dir, 'dependencies', 'C'),
@@ -149,7 +151,7 @@ describe('start', function() {
149151
});
150152

151153
describe('install', function() {
152-
var chmod, exec, add_to_queue, prepare, cp, rm, fetchSpy;
154+
var chmod, exec, add_to_queue, prepare, cp, rm, fetchSpy, fire;
153155
var spawnSpy;
154156

155157
beforeEach(function() {
@@ -168,11 +170,32 @@ describe('install', function() {
168170
spyOn(fs, 'writeFileSync').andReturn(true);
169171
cp = spyOn(shell, 'cp').andReturn(true);
170172
rm = spyOn(shell, 'rm').andReturn(true);
171-
add_to_queue = spyOn(PlatformJson.prototype, 'addInstalledPluginToPrepareQueue');
172-
done = false;
173+
add_to_queue = spyOn(PlatformJson.prototype, 'addInstalledPluginToPrepareQueue');
174+
fire = spyOn(HooksRunner.prototype, 'fire').andReturn(Q());
175+
done = false;
173176
});
174177

175178
describe('success', function() {
179+
it('should fire hooks on plugin successful install', function() {
180+
runs(function() {
181+
installPromise( install('android', project, plugins['org.test.plugin-with-hooks']) );
182+
});
183+
waitsFor(function() { return done; }, 'install promise never resolved', 200);
184+
runs(function() {
185+
expect(fire).toHaveBeenCalled();
186+
});
187+
});
188+
189+
it('should not fire hooks on plugin successful install when run_hooks=false', function() {
190+
runs(function() {
191+
installPromise( install('android', project, plugins['org.test.plugin-with-hooks'], {run_hooks:false}) );
192+
});
193+
waitsFor(function() { return done; }, 'install promise never resolved', 200);
194+
runs(function() {
195+
expect(fire).not.toHaveBeenCalled();
196+
});
197+
});
198+
176199
it('should call prepare after a successful install', function() {
177200
expect(results['prepareCount']).toBe(4);
178201
});
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<plugin xmlns="http://apache.org/cordova/ns/plugins/1.0"
3+
xmlns:android="http://schemas.android.com/apk/res/android"
4+
id="org.test.plugin-with-hooks" version="0.0.1">
5+
6+
<name>Plugin With Hooks</name>
7+
<license>Commercial</license>
8+
<keywords>cordova,device</keywords>
9+
<engines>
10+
<engine name="cordova" version=">=3.0.0" />
11+
</engines>
12+
13+
<hook type="before_plugin_install" src="scripts/beforeInstall.js" />
14+
<hook type="after_plugin_install" src="scripts/afterInstall.js" />
15+
<hook type="before_plugin_uninstall" src="scripts/beforeUninstall.js" />
16+
</plugin>
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
module.exports = function(context) {
2+
}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
module.exports = function(context) {
2+
}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
module.exports = function(context) {
2+
}

cordova-lib/spec-plugman/uninstall.spec.js

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,8 @@ var uninstall = require('../src/plugman/uninstall'),
2424
actions = require('../src/plugman/util/action-stack'),
2525
PlatformJson = require('../src/plugman/util/PlatformJson'),
2626
events = require('../src/events'),
27-
plugman = require('../src/plugman/plugman'),
27+
plugman = require('../src/plugman/plugman'),
28+
HooksRunner = require('../src/hooks/HooksRunner'),
2829
common = require('./common'),
2930
fs = require('fs'),
3031
path = require('path'),
@@ -41,7 +42,8 @@ var uninstall = require('../src/plugman/uninstall'),
4142
plugins_install_dir2 = path.join(project2, 'cordova', 'plugins'),
4243

4344
plugins = {
44-
'org.test.plugins.dummyplugin' : path.join(plugins_dir, 'org.test.plugins.dummyplugin'),
45+
'org.test.plugins.dummyplugin' : path.join(plugins_dir, 'org.test.plugins.dummyplugin'),
46+
'org.test.plugin-with-hooks' : path.join(plugins_dir, 'org.test.plugin-with-hooks'),
4547
'A' : path.join(plugins_dir, 'dependencies', 'A'),
4648
'C' : path.join(plugins_dir, 'dependencies', 'C')
4749
},
@@ -64,6 +66,8 @@ describe('start', function() {
6466
promise = Q()
6567
.then(function(){
6668
return install('android', project, plugins['org.test.plugins.dummyplugin']);
69+
}).then(function(){
70+
return install('android', project, plugins['org.test.plugin-with-hooks']);
6771
}).then(function(){
6872
return install('android', project, plugins['A']);
6973
}).then( function(){
@@ -97,7 +101,7 @@ describe('uninstallPlatform', function() {
97101
add_to_queue = spyOn(PlatformJson.prototype, 'addUninstalledPluginToPrepareQueue');
98102
done = false;
99103
});
100-
describe('success', function() {
104+
describe('success', function() {
101105
it('should call prepare after a successful uninstall', function() {
102106
runs(function() {
103107
uninstallPromise(uninstall.uninstallPlatform('android', project, dummy_id));
@@ -177,7 +181,7 @@ describe('uninstallPlugin', function() {
177181
done = false;
178182
});
179183
describe('with dependencies', function() {
180-
184+
181185
it('should delete all dependent plugins', function() {
182186
runs(function() {
183187
uninstallPromise( uninstall.uninstallPlugin('A', plugins_install_dir) );
@@ -234,15 +238,26 @@ describe('uninstallPlugin', function() {
234238
});
235239

236240
describe('uninstall', function() {
237-
var fsWrite, rm, add_to_queue;
241+
var fsWrite, rm, add_to_queue, fire;
238242

239243
beforeEach(function() {
240244
fsWrite = spyOn(fs, 'writeFileSync').andReturn(true);
241245
rm = spyOn(shell, 'rm').andReturn(true);
242246
add_to_queue = spyOn(PlatformJson.prototype, 'addUninstalledPluginToPrepareQueue');
247+
fire = spyOn(HooksRunner.prototype, 'fire').andReturn(Q());
243248
done = false;
244249
});
245250
describe('success', function() {
251+
it('should fire hooks on plugin successful uninstalled', function() {
252+
runs(function() {
253+
uninstallPromise( uninstall('android', project, plugins['org.test.plugin-with-hooks']) );
254+
});
255+
waitsFor(function() { return done; }, 'promise never resolved', 200);
256+
runs(function() {
257+
expect(fire).toHaveBeenCalled();
258+
});
259+
});
260+
246261
it('should call the config-changes module\'s add_uninstalled_plugin_to_prepare_queue method after processing an install', function() {
247262
runs(function() {
248263
uninstallPromise( uninstall('android', project, plugins['org.test.plugins.dummyplugin']) );
@@ -285,6 +300,10 @@ describe('end', function() {
285300
function(){
286301
return uninstall('android', project, plugins['org.test.plugins.dummyplugin']);
287302
}
303+
).then(
304+
function(){
305+
return uninstall('android', project, plugins['org.test.plugin-with-hooks']);
306+
}
288307
).then(
289308
function(){
290309
// Fails... A depends on

cordova-lib/src/hooks/HooksRunner.js

Lines changed: 33 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -33,17 +33,21 @@ var isWindows = os.platform().slice(0, 3) === 'win';
3333
* Tries to create a HooksRunner for passed project root.
3434
* @constructor
3535
*/
36-
function HooksRunner(projectRoot) {
37-
var root = cordovaUtil.isCordova(projectRoot);
38-
if (!root) throw new CordovaError('Not a Cordova project ("' + projectRoot + '"), can\'t use hooks.');
39-
else this.projectRoot = root;
36+
function DefaultHooksRunner(projectRoot) {
37+
this.projectRoot = projectRoot;
4038
}
4139

40+
DefaultHooksRunner.prototype.prepareOptions = function(opts) {
41+
opts = opts || {};
42+
opts.projectRoot = this.projectRoot;
43+
return opts;
44+
};
45+
4246
/**
4347
* Fires all event handlers and scripts for a passed hook type.
4448
* Returns a promise.
4549
*/
46-
HooksRunner.prototype.fire = function fire(hook, opts) {
50+
DefaultHooksRunner.prototype.fire = function fire(hook, opts) {
4751
// args check
4852
if (!hook) {
4953
throw new Error('hook type is not specified');
@@ -59,12 +63,24 @@ HooksRunner.prototype.fire = function fire(hook, opts) {
5963
});
6064
};
6165

66+
/**
67+
* Tries to create a CordovaHooksRunner for passed project root.
68+
* @constructor
69+
*/
70+
function CordovaHooksRunner(projectRoot) {
71+
DefaultHooksRunner.call(this, projectRoot);
72+
var root = cordovaUtil.isCordova(projectRoot);
73+
if (!root) throw new CordovaError('Not a Cordova project ("' + projectRoot + '"), can\'t use hooks.');
74+
else this.projectRoot = root;
75+
}
76+
77+
require('util').inherits(CordovaHooksRunner, DefaultHooksRunner);
78+
6279
/**
6380
* Refines passed options so that all required parameters are set.
6481
*/
65-
HooksRunner.prototype.prepareOptions = function(opts) {
66-
opts = opts || {};
67-
opts.projectRoot = this.projectRoot;
82+
CordovaHooksRunner.prototype.prepareOptions = function(opts) {
83+
opts = DefaultHooksRunner.prototype.prepareOptions.call(this, opts);
6884
opts.cordova = opts.cordova || {};
6985
opts.cordova.platforms = opts.cordova.platforms || opts.platforms || cordovaUtil.listPlatforms(opts.projectRoot);
7086
opts.cordova.platforms = opts.cordova.platforms.map(function(platform) { return platform.split('@')[0]; } );
@@ -80,6 +96,15 @@ HooksRunner.prototype.prepareOptions = function(opts) {
8096
return opts;
8197
};
8298

99+
function HooksRunner(projectRoot) {
100+
var root = cordovaUtil.isCordova(projectRoot);
101+
this.hooksRunner = root ? new CordovaHooksRunner(root) : new DefaultHooksRunner(projectRoot);
102+
}
103+
104+
HooksRunner.prototype.fire = function fire(hook, opts) {
105+
return this.hooksRunner.fire(hook, opts);
106+
};
107+
83108
module.exports = HooksRunner;
84109

85110
/**

cordova-lib/src/hooks/scriptsFinder.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,11 @@ function getApplicationHookScriptsFromDir(dir) {
105105
*/
106106
function getScriptsFromConfigXml(hook, opts) {
107107
var configPath = cordovaUtil.projectConfig(opts.projectRoot);
108+
109+
if (!(fs.existsSync(configPath))) {
110+
return [];
111+
}
112+
108113
var configXml = new ConfigParser(configPath);
109114

110115
return configXml.getHookScripts(hook, opts.cordova.platforms).map(function(scriptElement) {

cordova-lib/src/plugman/install.js

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -315,16 +315,15 @@ function runInstall(actions, platform, project_dir, plugin_dir, plugins_dir, opt
315315
}
316316
).then(
317317
function(){
318-
var install_plugin_dir = path.join(plugins_dir, pluginInfo.id);
318+
var install_plugin_dir = path.join(plugins_dir, pluginInfo.id),
319+
run_hooks = options.hasOwnProperty('run_hooks') ? options.run_hooks : true;
319320

320321
// may need to copy to destination...
321322
if ( !fs.existsSync(install_plugin_dir) ) {
322323
copyPlugin(plugin_dir, plugins_dir, options.link, pluginInfoProvider);
323324
}
324325

325-
var projectRoot = cordovaUtil.isCordova();
326-
327-
if(projectRoot) {
326+
if(run_hooks) {
328327
// using unified hooksRunner
329328
var hookOptions = {
330329
cordova: { platforms: [ platform ] },
@@ -336,7 +335,7 @@ function runInstall(actions, platform, project_dir, plugin_dir, plugins_dir, opt
336335
}
337336
};
338337

339-
var hooksRunner = new HooksRunner(projectRoot);
338+
var hooksRunner = new HooksRunner(cordovaUtil.isCordova() || project_dir);
340339

341340
return hooksRunner.fire('before_plugin_install', hookOptions).then(function() {
342341
return handleInstall(actions, pluginInfo, platform, project_dir, plugins_dir, install_plugin_dir, filtered_variables, options);

0 commit comments

Comments
 (0)