/* | |
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'); | |
var fs = require('fs-extra'); | |
var path = require('path'); | |
var ActionStack = require('./ActionStack'); | |
var PlatformJson = require('./PlatformJson'); | |
var CordovaError = require('./CordovaError/CordovaError'); | |
var PlatformMunger = require('./ConfigChanges/ConfigChanges').PlatformMunger; | |
var PluginInfoProvider = require('./PluginInfo/PluginInfoProvider'); | |
/** | |
* @constructor | |
* @class PluginManager | |
* Represents an entity for adding/removing plugins for platforms | |
* | |
* @param {String} platform Platform name | |
* @param {Object} locations - Platform files and directories | |
* @param {IDEProject} ideProject The IDE project to add/remove plugin changes to/from | |
*/ | |
function PluginManager (platform, locations, ideProject) { | |
this.platform = platform; | |
this.locations = locations; | |
this.project = ideProject; | |
var platformJson = PlatformJson.load(locations.root, platform); | |
this.munger = new PlatformMunger(platform, locations.root, platformJson, new PluginInfoProvider()); | |
} | |
/** | |
* @constructs PluginManager | |
* A convenience shortcut to new PluginManager(...) | |
* | |
* @param {String} platform Platform name | |
* @param {Object} locations - Platform files and directories | |
* @param {IDEProject} ideProject The IDE project to add/remove plugin changes to/from | |
* @returns new PluginManager instance | |
*/ | |
PluginManager.get = function (platform, locations, ideProject) { | |
return new PluginManager(platform, locations, ideProject); | |
}; | |
PluginManager.INSTALL = 'install'; | |
PluginManager.UNINSTALL = 'uninstall'; | |
module.exports = PluginManager; | |
/** | |
* Describes and implements common plugin installation/uninstallation routine. The flow is the following: | |
* * Validate and set defaults for options. Note that options are empty by default. Everything | |
* needed for platform IDE project must be passed from outside. Plugin variables (which | |
* are the part of the options) also must be already populated with 'PACKAGE_NAME' variable. | |
* * Collect all plugin's native and web files, get installers/uninstallers and process | |
* all these via ActionStack. | |
* * Save the IDE project, so the changes made by installers are persisted. | |
* * Generate config changes munge for plugin and apply it to all required files | |
* * Generate metadata for plugin and plugin modules and save it to 'cordova_plugins.js' | |
* | |
* @param {PluginInfo} plugin A PluginInfo structure representing plugin to install | |
* @param {Object} [options={}] An installation options. It is expected but is not necessary | |
* that options would contain 'variables' inner object with 'PACKAGE_NAME' field set by caller. | |
* | |
* @returns {Promise} Returns a Q promise, either resolved in case of success, rejected otherwise. | |
*/ | |
PluginManager.prototype.doOperation = function (operation, plugin, options) { | |
if (operation !== PluginManager.INSTALL && operation !== PluginManager.UNINSTALL) { return Q.reject(new CordovaError('The parameter is incorrect. The opeation must be either "add" or "remove"')); } | |
if (!plugin || plugin.constructor.name !== 'PluginInfo') { return Q.reject(new CordovaError('The parameter is incorrect. The first parameter should be a PluginInfo instance')); } | |
// Set default to empty object to play safe when accesing properties | |
options = options || {}; | |
var self = this; | |
var actions = new ActionStack(); | |
// gather all files need to be handled during operation ... | |
plugin.getFilesAndFrameworks(this.platform, options) | |
.concat(plugin.getAssets(this.platform)) | |
.concat(plugin.getJsModules(this.platform)) | |
// ... put them into stack ... | |
.forEach(function (item) { | |
var installer = self.project.getInstaller(item.itemType); | |
var uninstaller = self.project.getUninstaller(item.itemType); | |
var actionArgs = [item, plugin, self.project, options]; | |
var action; | |
if (operation === PluginManager.INSTALL) { | |
action = actions.createAction.apply(actions, [installer, actionArgs, uninstaller, actionArgs]); /* eslint no-useless-call: 0 */ | |
} else /* op === PluginManager.UNINSTALL */{ | |
action = actions.createAction.apply(actions, [uninstaller, actionArgs, installer, actionArgs]); /* eslint no-useless-call: 0 */ | |
} | |
actions.push(action); | |
}); | |
// ... and run through the action stack | |
return actions.process(this.platform) | |
.then(function () { | |
if (self.project.write) { | |
self.project.write(); | |
} | |
if (operation === PluginManager.INSTALL) { | |
// Ignore passed `is_top_level` option since platform itself doesn't know | |
// anything about managing dependencies - it's responsibility of caller. | |
self.munger.add_plugin_changes(plugin, options.variables, /* is_top_level= */true, /* should_increment= */true, options.force); | |
self.munger.platformJson.addPluginMetadata(plugin); | |
} else { | |
self.munger.remove_plugin_changes(plugin, /* is_top_level= */true); | |
self.munger.platformJson.removePluginMetadata(plugin); | |
} | |
// Save everything (munge and plugin/modules metadata) | |
self.munger.save_all(); | |
var metadata = self.munger.platformJson.generateMetadata(); | |
fs.writeFileSync(path.join(self.locations.www, 'cordova_plugins.js'), metadata, 'utf-8'); | |
// CB-11022 save plugin metadata to both www and platform_www if options.usePlatformWww is specified | |
if (options.usePlatformWww) { | |
fs.writeFileSync(path.join(self.locations.platformWww, 'cordova_plugins.js'), metadata, 'utf-8'); | |
} | |
}); | |
}; | |
PluginManager.prototype.addPlugin = function (plugin, installOptions) { | |
return this.doOperation(PluginManager.INSTALL, plugin, installOptions); | |
}; | |
PluginManager.prototype.removePlugin = function (plugin, uninstallOptions) { | |
return this.doOperation(PluginManager.UNINSTALL, plugin, uninstallOptions); | |
}; |