You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cordova.apache.org by an...@apache.org on 2015/09/02 13:31:40 UTC
[2/5] cordova-lib git commit: CB-9597 Initial Implementation of
PlatformApiPoly
http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/07271a5c/cordova-lib/src/platforms/PlatformApiPoly.js
----------------------------------------------------------------------
diff --git a/cordova-lib/src/platforms/PlatformApiPoly.js b/cordova-lib/src/platforms/PlatformApiPoly.js
new file mode 100644
index 0000000..183bc4d
--- /dev/null
+++ b/cordova-lib/src/platforms/PlatformApiPoly.js
@@ -0,0 +1,706 @@
+/**
+ 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');
+var path = require('path');
+var unorm = require('unorm');
+var shell = require('shelljs');
+var semver = require('semver');
+
+var superspawn = require('../cordova/superspawn');
+var xmlHelpers = require('../util/xml-helpers');
+var common = require('../plugman/platforms/common');
+var knownPlatforms = require('./platforms');
+var CordovaError = require('../CordovaError');
+var PluginInfo = require('../PluginInfo');
+var ConfigParser = require('../configparser/ConfigParser');
+var PlatformJson = require('../plugman/util/PlatformJson');
+var ActionStack = require('../plugman/util/action-stack');
+var PlatformMunger = require('../plugman/util/config-changes').PlatformMunger;
+var PluginInfoProvider = require('../PluginInfoProvider');
+
+/**
+ * Class, that acts as abstraction over particular platform. Encapsulates the
+ * platform's properties and methods.
+ *
+ * Platform that implements own PlatformApi instance _should implement all
+ * prototype methods_ of this class to be fully compatible with cordova-lib.
+ *
+ * The PlatformApi instance also should define the following field:
+ *
+ * * platform: String that defines a platform name.
+ */
+function PlatformApiPoly(platform, platformRootDir) {
+ if (!platform) throw new CordovaError('\'platform\' argument is missing');
+ if (!platformRootDir) throw new CordovaError('platformRootDir argument is missing');
+
+ this.root = platformRootDir;
+ this.platform = platform;
+
+ if (!(platform in knownPlatforms))
+ throw new CordovaError('Unknown platform ' + platform);
+
+ var ParserConstructor = require(knownPlatforms[platform].parser_file);
+ this._parser = new ParserConstructor(this.root);
+ this._handler = require(knownPlatforms[platform].handler_file);
+
+ this._platformJson = PlatformJson.load(this.root, platform);
+ this._pluginInfoProvider = new PluginInfoProvider();
+ this._munger = new PlatformMunger(platform, this.root, this._platformJson, this._pluginInfoProvider);
+
+ this._config = new ConfigParser(this.getPlatformInfo().locations.configXml);
+}
+
+/**
+ * Installs platform to specified directory and creates a platform project.
+ *
+ * @param {CordovaProject} cordovaProject A CordovaProject instance, that defines a
+ * project structure and configuration, that should be applied to new platform
+ * (contains platform's target location and ConfigParser instance for
+ * project's config). This argument is optional and if not defined, this means
+ * that platform is used as standalone project and is not a part of cordova
+ * project.
+ * @param {Object} options An options object. The most common options are:
+ * @param {String} options.customTemplate A path to custom template, that
+ * should override the default one from platform.
+ * @param {Boolean} options.link Flag that indicates that platform's sources
+ * will be linked to installed platform instead of copying.
+ *
+ * @return {Promise<PlatformApi>} Promise either fulfilled with PlatformApi
+ * instance or rejected with CordovaError.
+ */
+PlatformApiPoly.createPlatform = function (cordovaProject, options) {
+ if (!options || !options.platformDetails)
+ return Q.reject(CordovaError('Failed to find platform\'s \'create\' script. ' +
+ 'Either \'options\' parameter or \'platformDetails\' option is missing'));
+
+ var command = path.join(options.platformDetails.libDir, 'bin', 'create');
+ var commandArguments = getCreateArgs(cordovaProject, options);
+
+ return superspawn.spawn(command, commandArguments,
+ { printCommand: true, stdio: 'inherit', chmod: true })
+ .then(function () {
+ var destination = path.join(cordovaProject.locations.platforms, options.platformDetails.platform);
+ var platformApi = knownPlatforms
+ .getPlatformApi(options.platformDetails.platform, destination);
+ copyCordovaSrc(options.platformDetails.libDir, platformApi.getPlatformInfo());
+ return platformApi;
+ });
+};
+
+/**
+ * Updates already installed platform.
+ *
+ * @param {CordovaProject} cordovaProject A CordovaProject instance, that
+ * defines a project structure and configuration, that should be applied to
+ * new platform (contains platform's target location and ConfigParser instance
+ * for project's config). This argument is optional and if not defined, this
+ * means that platform is used as standalone project and is not a part of
+ * cordova project.
+ * @param {Object} options An options object. The most common options are:
+ * @param {String} options.customTemplate A path to custom template, that
+ * should override the default one from platform.
+ * @param {Boolean} options.link Flag that indicates that platform's sources
+ * will be linked to installed platform instead of copying.
+ *
+ * @return {Promise<PlatformApi>} Promise either fulfilled with PlatformApi
+ * instance or rejected with CordovaError.
+ */
+PlatformApiPoly.updatePlatform = function (cordovaProject, options) {
+ if (!options || !options.platformDetails)
+ return Q.reject(CordovaError('Failed to find platform\'s \'create\' script. ' +
+ 'Either \'options\' parameter or \'platformDetails\' option is missing'));
+
+ var command = path.join(options.platformDetails.libDir, 'bin', 'update');
+ var destination = path.join(cordovaProject.locations.platforms, options.platformDetails.platform);
+
+ return superspawn.spawn(command, [destination],
+ { printCommand: true, stdio: 'inherit', chmod: true })
+ .then(function () {
+ var platformApi = knownPlatforms
+ .getPlatformApi(options.platformDetails.platform, destination);
+ copyCordovaSrc(options.platformDetails.libDir, platformApi.getPlatformInfo());
+ return platformApi;
+ });
+};
+
+/**
+ * Gets a CordovaPlatform object, that represents the platform structure.
+ *
+ * @return {CordovaPlatform} A structure that contains the description of
+ * platform's file structure and other properties of platform.
+ */
+PlatformApiPoly.prototype.getPlatformInfo = function () {
+ var self = this;
+ var result = {};
+ result.locations = {
+ www: self._parser.www_dir(),
+ platformWww: path.join(self.root, 'platform_www'),
+ configXml: self._parser.config_xml(),
+ // NOTE: Due to platformApi spec we need to return relative paths here
+ cordovaJs: path.relative(self.root, self._parser.cordovajs_path.call(self.parser, self.root)),
+ cordovaJsSrc: path.relative(self.root, self._parser.cordovajs_src_path.call(self.parser, self.root))
+ };
+ result.root = self.root;
+ result.name = self.platform;
+ result.version = knownPlatforms[self.platform].version;
+ result.projectConfig = self._config;
+
+ return result;
+};
+
+/**
+ * Updates installed platform with provided www assets and new app
+ * configuration. This method is required for CLI workflow and will be called
+ * each time before build, so the changes, made to app configuration and www
+ * code, will be applied to platform.
+ *
+ * @param {CordovaProject} cordovaProject A CordovaProject instance, that defines a
+ * project structure and configuration, that should be applied to platform
+ * (contains project's www location and ConfigParser instance for project's
+ * config).
+ *
+ * @return {Promise} Return a promise either fulfilled, or rejected with
+ * CordovaError instance.
+ */
+PlatformApiPoly.prototype.prepare = function (cordovaProject) {
+
+ // First cleanup current config and merge project's one into own
+ var defaultConfig = path.join(this.root, 'cordova', 'defaults.xml');
+ var ownConfig = this._config.path;
+ var sourceCfg = cordovaProject.projectConfig.path;
+ // If defaults.xml is present, overwrite platform config.xml with it.
+ // Otherwise save whatever is there as defaults so it can be
+ // restored or copy project config into platform if none exists.
+ if (fs.existsSync(defaultConfig)) {
+ // events.emit('verbose', 'Generating config.xml from defaults for platform "' + this.platform + '"');
+ shell.cp('-f', defaultConfig, ownConfig);
+ this._config = new ConfigParser(ownConfig);
+ } else if (fs.existsSync(ownConfig)) {
+ shell.cp('-f', ownConfig, defaultConfig);
+ } else {
+ shell.cp('-f', sourceCfg.path, ownConfig);
+ this._config = new ConfigParser(ownConfig);
+ }
+
+ xmlHelpers.mergeXml(cordovaProject.projectConfig.doc.getroot(),
+ this._config.doc.getroot(), this.platform, true);
+ // CB-6976 Windows Universal Apps. For smooth transition and to prevent mass api failures
+ // we allow using windows8 tag for new windows platform
+ if (this.platform == 'windows') {
+ xmlHelpers.mergeXml(cordovaProject.projectConfig.doc.getroot(),
+ this._config.doc.getroot(), 'windows8', true);
+ }
+ this._config.write();
+
+ // Update own www dir with project's www assets and plugins' assets and js-files
+ this._parser.update_www(cordovaProject.locations.www);
+
+ this._munger.reapply_global_munge().save_all();
+
+ // update project according to config.xml changes.
+ return this._parser.update_project(cordovaProject.projectConfig);
+};
+
+/**
+ * Installs a new plugin into platform. This method only copies non-www files
+ * (sources, libs, etc.) to platform. It also doesn't resolves the
+ * dependencies of plugin. Both of handling of www files, such as assets and
+ * js-files and resolving dependencies are the responsibility of caller.
+ *
+ * @param {PluginInfo} plugin A PluginInfo instance that represents plugin
+ * that will be installed.
+ * @param {Object} installOptions An options object. Possible options below:
+ * @param {Boolean} installOptions.link: Flag that specifies that plugin
+ * sources will be symlinked to app's directory instead of copying (if
+ * possible).
+ * @param {Object} installOptions.variables An object that represents
+ * variables that will be used to install plugin. See more details on plugin
+ * variables in documentation:
+ * https://cordova.apache.org/docs/en/4.0.0/plugin_ref_spec.md.html
+ *
+ * @return {Promise} Return a promise either fulfilled, or rejected with
+ * CordovaError instance.
+ */
+PlatformApiPoly.prototype.addPlugin = function (plugin, installOptions) {
+
+ if (!plugin || !(plugin instanceof PluginInfo))
+ return Q.reject('The parameter is incorrect. The first parameter ' +
+ 'should be valid PluginInfo instance');
+
+ installOptions = installOptions || {};
+ installOptions.variables = installOptions.variables || {};
+
+ var self = this;
+ var actions = new ActionStack();
+ var projectFile = this._handler.parseProjectFile && this._handler.parseProjectFile(this.root);
+
+ // gather all files needs to be handled during install
+ plugin.getFilesAndFrameworks(this.platform)
+ .concat(plugin.getAssets(this.platform))
+ .concat(plugin.getJsModules(this.platform))
+ .forEach(function(item) {
+ actions.push(actions.createAction(
+ self._getInstaller(item.itemType), [item, plugin.dir, plugin.id, installOptions, projectFile],
+ self._getUninstaller(item.itemType), [item, plugin.dir, plugin.id, installOptions, projectFile]));
+ });
+
+ // run through the action stack
+ return actions.process(this.platform, this.root)
+ .then(function () {
+ if (projectFile) {
+ projectFile.write();
+ }
+
+ // Add PACKAGE_NAME variable into vars
+ if (!installOptions.variables.PACKAGE_NAME) {
+ installOptions.variables.PACKAGE_NAME = self._handler.package_name(self.root);
+ }
+
+ self._munger
+ // Ignore passed `is_top_level` option since platform itself doesn't know
+ // anything about managing dependencies - it's responsibility of caller.
+ .add_plugin_changes(plugin, installOptions.variables, /*is_top_level=*/true, /*should_increment=*/true)
+ .save_all();
+
+ var targetDir = installOptions.usePlatformWww ?
+ self.getPlatformInfo().locations.platformWww :
+ self.getPlatformInfo().locations.www;
+
+ self._addModulesInfo(plugin, targetDir);
+ });
+};
+
+/**
+ * Removes an installed plugin from platform.
+ *
+ * Since method accepts PluginInfo instance as input parameter instead of plugin
+ * id, caller shoud take care of managing/storing PluginInfo instances for
+ * future uninstalls.
+ *
+ * @param {PluginInfo} plugin A PluginInfo instance that represents plugin
+ * that will be installed.
+ *
+ * @return {Promise} Return a promise either fulfilled, or rejected with
+ * CordovaError instance.
+ */
+PlatformApiPoly.prototype.removePlugin = function (plugin, uninstallOptions) {
+
+ var self = this;
+ var actions = new ActionStack();
+ var projectFile = this._handler.parseProjectFile && this._handler.parseProjectFile(this.root);
+
+ // queue up plugin files
+ plugin.getFilesAndFrameworks(this.platform)
+ .concat(plugin.getAssets(this.platform))
+ .concat(plugin.getJsModules(this.platform))
+ .filter(function (item) {
+ // CB-5238 Skip (don't uninstall) non custom frameworks.
+ return !(item.itemType == 'framework' && !item.custom);
+ }).forEach(function(item) {
+ actions.push(actions.createAction(
+ self._getUninstaller(item.itemType), [item, plugin.dir, plugin.id, uninstallOptions, projectFile],
+ self._getInstaller(item.itemType), [item, plugin.dir, plugin.id, uninstallOptions, projectFile]));
+ });
+
+ // run through the action stack
+ return actions.process(this.platform, this.root)
+ .then(function() {
+ if (projectFile) {
+ projectFile.write();
+ }
+
+ self._munger
+ // Ignore passed `is_top_level` option since platform itself doesn't know
+ // anything about managing dependencies - it's responsibility of caller.
+ .remove_plugin_changes(plugin, /*is_top_level=*/true)
+ .save_all();
+
+ var targetDir = uninstallOptions.usePlatformWww ?
+ self.getPlatformInfo().locations.platformWww :
+ self.getPlatformInfo().locations.www;
+
+ self._removeModulesInfo(plugin, targetDir);
+ // Remove stale plugin directory
+ // TODO: this should be done by plugin files uninstaller
+ shell.rm('-rf', path.resolve(self.root, 'Plugins', plugin.id));
+ });
+};
+
+PlatformApiPoly.prototype.updatePlugin = function (plugin, updateOptions) {
+ var self = this;
+
+ // Set up assets installer to copy asset files into platform_www dir instead of www
+ updateOptions = updateOptions || {};
+ updateOptions.usePlatformWww = true;
+
+ return this.removePlugin(plugin, updateOptions)
+ .then(function () {
+ return self.addPlugin(plugin, updateOptions);
+ });
+};
+
+/**
+ * Builds an application package for current platform.
+ *
+ * @param {Object} buildOptions A build options. This object's structure is
+ * highly depends on platform's specific. The most common options are:
+ * @param {Boolean} buildOptions.debug Indicates that packages should be
+ * built with debug configuration. This is set to true by default unless the
+ * 'release' option is not specified.
+ * @param {Boolean} buildOptions.release Indicates that packages should be
+ * built with release configuration. If not set to true, debug configuration
+ * will be used.
+ * @param {Boolean} buildOptions.device Specifies that built app is intended
+ * to run on device
+ * @param {Boolean} buildOptions.emulator: Specifies that built app is
+ * intended to run on emulator
+ * @param {String} buildOptions.target Specifies the device id that will be
+ * used to run built application.
+ * @param {Boolean} buildOptions.nobuild Indicates that this should be a
+ * dry-run call, so no build artifacts will be produced.
+ * @param {String[]} buildOptions.archs Specifies chip architectures which
+ * app packages should be built for. List of valid architectures is depends on
+ * platform.
+ * @param {String} buildOptions.buildConfig The path to build configuration
+ * file. The format of this file is depends on platform.
+ * @param {String[]} buildOptions.argv Raw array of command-line arguments,
+ * passed to `build` command. The purpose of this property is to pass a
+ * platform-specific arguments, and eventually let platform define own
+ * arguments processing logic.
+ *
+ * @return {Promise<Object[]>} A promise either fulfilled with an array of build
+ * artifacts (application packages) if package was built successfully,
+ * or rejected with CordovaError. The resultant build artifact objects is not
+ * strictly typed and may conatin arbitrary set of fields as in sample below.
+ *
+ * {
+ * architecture: 'x86',
+ * buildType: 'debug',
+ * path: '/path/to/build',
+ * type: 'app'
+ * }
+ *
+ * The return value in most cases will contain only one item but in some cases
+ * there could be multiple items in output array, e.g. when multiple
+ * arhcitectures is specified.
+ */
+PlatformApiPoly.prototype.build = function(buildOptions) {
+ var command = path.join(this.root, 'cordova', 'build');
+ var commandArguments = getBuildArgs(buildOptions);
+ return superspawn.spawn(command, commandArguments, {
+ printCommand: true, stdio: 'inherit', chmod: true });
+};
+
+/**
+ * Builds an application package for current platform and runs it on
+ * specified/default device. If no 'device'/'emulator'/'target' options are
+ * specified, then tries to run app on default device if connected, otherwise
+ * runs the app on emulator.
+ *
+ * @param {Object} runOptions An options object. The structure is the same
+ * as for build options.
+ *
+ * @return {Promise} A promise either fulfilled if package was built and ran
+ * successfully, or rejected with CordovaError.
+ */
+PlatformApiPoly.prototype.run = function(runOptions) {
+ var command = path.join(this.root, 'cordova', 'run');
+ var commandArguments = getBuildArgs(runOptions);
+ return superspawn.spawn(command, commandArguments, {
+ printCommand: true, stdio: 'inherit', chmod: true });
+};
+
+/**
+ * Cleans out the build artifacts from platform's directory.
+ *
+ * @return {Promise} Return a promise either fulfilled, or rejected with
+ * CordovaError.
+ */
+PlatformApiPoly.prototype.clean = function() {
+ var cmd = path.join(this.root, 'cordova', 'clean');
+ return superspawn.spawn(cmd, [], { printCommand: true, stdio: 'inherit', chmod: true });
+};
+
+/**
+ * Performs a requirements check for current platform. Each platform defines its
+ * own set of requirements, which should be resolved before platform can be
+ * built successfully.
+ *
+ * @return {Promise<Requirement[]>} Promise, resolved with set of Requirement
+ * objects for current platform.
+ */
+PlatformApiPoly.prototype.requirements = function() {
+ var modulePath = path.join(this.root, 'cordova', 'lib', 'check_reqs');
+ try {
+ return require(modulePath).check_all();
+ } catch (e) {
+ var errorMsg = 'Failed to check requirements for ' + this.platform + ' platform. ' +
+ 'check_reqs module is missing for platfrom. Skipping it...';
+ return Q.reject(errorMsg);
+ }
+};
+
+module.exports = PlatformApiPoly;
+
+/**
+ * Converts arguments, passed to createPlatform to command-line args to
+ * 'bin/create' script for specific platform.
+ *
+ * @param {ProjectInfo} project A current project information. The vauest
+ * which this method interested in are project.config - config.xml abstraction
+ * - and platformsLocation - to get install destination.
+ * @param {Object} options Set of properties for create script.
+ *
+ * @return {String[]} An array or arguments which can be passed to
+ * 'bin/create'.
+ */
+function getCreateArgs(project, options) {
+ var platformName = options.platformDetails.platform;
+ var platformVersion = options.platformDetails.version;
+
+ var args = [];
+ args.push(path.join(project.locations.platforms, platformName)); // output
+ args.push(project.projectConfig.packageName().replace(/[^\w.]/g,'_'));
+ // CB-6992 it is necessary to normalize characters
+ // because node and shell scripts handles unicode symbols differently
+ // We need to normalize the name to NFD form since iOS uses NFD unicode form
+ args.push(platformName == 'ios' ? unorm.nfd(project.projectConfig.name()) : project.projectConfig.name());
+
+ if (options.customTemplate) {
+ args.push(options.customTemplate);
+ }
+
+ if (/android|ios/.exec(platformName) &&
+ semver.gt(platformVersion, '3.3.0')) args.push('--cli');
+
+ if (options.link) args.push('--link');
+
+ if (platformName === 'android' && semver.gte(platformVersion, '4.0.0-dev')) {
+ var activityName = project.projectConfig.android_activityName();
+ if (activityName) {
+ args.push('--activity-name', activityName.replace(/\W/g, ''));
+ }
+ }
+
+ return args;
+}
+
+/**
+ * Reconstructs the buildOptions tat will be passed along to platform scripts.
+ * This is an ugly temporary fix. The code spawning or otherwise calling into
+ * platform code should be dealing with this based on the parsed args object.
+ *
+ * @param {Object} options A build options set, passed to `build` method
+ *
+ * @return {String[]} An array or arguments which can be passed to
+ * `create` build script.
+ */
+function getBuildArgs(options) {
+ // if no options passed, empty object will be returned
+ if (!options) return [];
+
+ var downstreamArgs = [];
+ var argNames =[
+ 'debug',
+ 'release',
+ 'device',
+ 'emulator',
+ 'nobuild',
+ 'list'
+ ];
+
+ argNames.forEach(function(flag) {
+ if (options[flag]) {
+ downstreamArgs.push('--' + flag);
+ }
+ });
+
+ if (options.buildConfig) {
+ downstreamArgs.push('--buildConfig=' + options.buildConfig);
+ }
+ if (options.target) {
+ downstreamArgs.push('--target=' + options.target);
+ }
+ if (options.archs) {
+ downstreamArgs.push('--archs=' + options.archs);
+ }
+
+ var unparsedArgs = options.argv || [];
+ return downstreamArgs.concat(unparsedArgs);
+}
+
+/**
+ * Removes the specified modules from list of installed modules and updates
+ * platform_json and cordova_plugins.js on disk.
+ *
+ * @param {PluginInfo} plugin PluginInfo instance for plugin, which modules
+ * needs to be added.
+ * @param {String} targetDir The directory, where updated cordova_plugins.js
+ * should be written to.
+ */
+PlatformApiPoly.prototype._addModulesInfo = function(plugin, targetDir) {
+ var installedModules = this._platformJson.root.modules || [];
+
+ var installedPaths = installedModules.map(function (installedModule) {
+ return installedModule.file;
+ });
+
+ var modulesToInstall = plugin.getJsModules(this.platform)
+ .filter(function (moduleToInstall) {
+ return installedPaths.indexOf(moduleToInstall.file) === -1;
+ }).map(function (moduleToInstall) {
+ var moduleName = plugin.id + '.' + ( moduleToInstall.name || moduleToInstall.src.match(/([^\/]+)\.js/)[1] );
+ var obj = {
+ file: ['plugins', plugin.id, moduleToInstall.src].join('/'),
+ id: moduleName
+ };
+ if (moduleToInstall.clobbers.length > 0) {
+ obj.clobbers = moduleToInstall.clobbers.map(function(o) { return o.target; });
+ }
+ if (moduleToInstall.merges.length > 0) {
+ obj.merges = moduleToInstall.merges.map(function(o) { return o.target; });
+ }
+ if (moduleToInstall.runs) {
+ obj.runs = true;
+ }
+
+ return obj;
+ });
+
+ this._platformJson.root.modules = installedModules.concat(modulesToInstall);
+ this._writePluginModules(targetDir);
+ this._platformJson.save();
+};
+
+/**
+ * Removes the specified modules from list of installed modules and updates
+ * platform_json and cordova_plugins.js on disk.
+ *
+ * @param {PluginInfo} plugin PluginInfo instance for plugin, which modules
+ * needs to be removed.
+ * @param {String} targetDir The directory, where updated cordova_plugins.js
+ * should be written to.
+ */
+PlatformApiPoly.prototype._removeModulesInfo = function(plugin, targetDir) {
+ var installedModules = this._platformJson.root.modules || [];
+ var modulesToRemove = plugin.getJsModules(this.platform)
+ .map(function (jsModule) {
+ return ['plugins', plugin.id, jsModule.src].join('/');
+ });
+
+ var updatedModules = installedModules
+ .filter(function (installedModule) {
+ return (modulesToRemove.indexOf(installedModule.file) === -1);
+ });
+
+ this._platformJson.root.modules = updatedModules;
+ this._writePluginModules(targetDir);
+ this._platformJson.save();
+};
+
+/**
+ * Fetches all installed modules, generates cordova_plugins contents and writes
+ * it to file.
+ *
+ * @param {String} targetDir Directory, where write cordova_plugins.js to.
+ * Ususally it is either <platform>/www or <platform>/platform_www
+ * directories.
+ */
+PlatformApiPoly.prototype._writePluginModules = function (targetDir) {
+ var self = this;
+ // Write out moduleObjects as JSON wrapped in a cordova module to cordova_plugins.js
+ var final_contents = 'cordova.define(\'cordova/plugin_list\', function(require, exports, module) {\n';
+ final_contents += 'module.exports = ' + JSON.stringify(this._platformJson.root.modules, null, ' ') + ';\n';
+ final_contents += 'module.exports.metadata = \n';
+ final_contents += '// TOP OF METADATA\n';
+
+ var pluginMetadata = Object.keys(this._platformJson.root.installed_plugins)
+ .reduce(function (metadata, plugin) {
+ metadata[plugin] = self._platformJson.root.installed_plugins[plugin].version;
+ return metadata;
+ }, {});
+
+ final_contents += JSON.stringify(pluginMetadata, null, ' ') + '\n';
+ final_contents += '// BOTTOM OF METADATA\n';
+ final_contents += '});'; // Close cordova.define.
+
+ shell.mkdir('-p', targetDir);
+ fs.writeFileSync(path.join(targetDir, 'cordova_plugins.js'), final_contents, 'utf-8');
+};
+
+PlatformApiPoly.prototype._getInstaller = function(type) {
+ var self = this;
+ return function (item, plugin_dir, plugin_id, options, project) {
+ var installer = self._handler[type] || common[type];
+
+ var wwwDest = options.usePlatformWww ?
+ self.getPlatformInfo().locations.platformWww :
+ self._handler.www_dir(self.root);
+
+ var installerArgs = type === 'asset' ? [wwwDest] :
+ type === 'js-module' ? [plugin_id, wwwDest]:
+ [self.root, plugin_id, options, project];
+
+ installer.install.apply(null, [item, plugin_dir].concat(installerArgs));
+ };
+};
+
+PlatformApiPoly.prototype._getUninstaller = function(type) {
+ var self = this;
+ return function (item, plugin_dir, plugin_id, options, project) {
+ var uninstaller = self._handler[type] || common[type];
+
+ var wwwDest = options.usePlatformWww ?
+ self.getPlatformInfo().locations.platformWww :
+ self._handler.www_dir(self.root);
+
+ var uninstallerArgs = (type === 'asset' || type === 'js-module') ? [wwwDest, plugin_id] :
+ [self.root, plugin_id, options, project];
+
+ uninstaller.uninstall.apply(null, [item].concat(uninstallerArgs));
+ };
+};
+
+/**
+ * Copies cordova.js itself and cordova-js source into installed/updated
+ * platform's `platform_www` directory.
+ *
+ * @param {String} sourceLib Path to platform library. Required to acquire
+ * cordova-js sources.
+ * @param {PlatformInfo} platformInfo PlatformInfo structure, required for
+ * detecting copied files destination.
+ */
+function copyCordovaSrc(sourceLib, platformInfo) {
+ // Copy the cordova.js file to platforms/<platform>/platform_www/
+ // The www dir is nuked on each prepare so we keep cordova.js in platform_www
+ shell.mkdir('-p', platformInfo.locations.platformWww);
+ shell.cp('-f', path.join(platformInfo.locations.www, 'cordova.js'),
+ path.join(platformInfo.locations.platformWww, 'cordova.js'));
+
+ // Copy cordova-js-src directory into platform_www directory.
+ // We need these files to build cordova.js if using browserify method.
+ var cordovaJsSrcPath = path.resolve(sourceLib, platformInfo.locations.cordovaJsSrc);
+
+ //only exists for platforms that have shipped cordova-js-src directory
+ if(fs.existsSync(cordovaJsSrcPath)) {
+ shell.cp('-rf', cordovaJsSrcPath, platformInfo.locations.platformWww);
+ }
+}
http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/07271a5c/cordova-lib/src/platforms/platforms.js
----------------------------------------------------------------------
diff --git a/cordova-lib/src/platforms/platforms.js b/cordova-lib/src/platforms/platforms.js
index cc0e492..d71570f 100644
--- a/cordova-lib/src/platforms/platforms.js
+++ b/cordova-lib/src/platforms/platforms.js
@@ -17,89 +17,47 @@
under the License.
*/
+var path = require('path');
+var util = require('../cordova/util');
var platforms = require('./platformsConfig.json');
-// Remove this block soon. The parser property is no longer used in
-// cordova-lib but some downstream tools still use it.
-var addModuleProperty = require('../cordova/util').addModuleProperty;
-Object.keys(platforms).forEach(function(key) {
- var obj = platforms[key];
- if (obj.parser_file) {
- addModuleProperty(module, 'parser', obj.parser_file, false, obj);
- }
-});
-
-
// Avoid loading the same platform projects more than once (identified by path)
-var cachedProjects = {};
-
-var PARSER_PUBLIC_METHODS = [
- 'config_xml',
- 'cordovajs_path',
- 'cordovajs_src_path',
- 'update_from_config',
- 'update_project',
- 'update_www',
- 'www_dir',
-];
-
-var HANDLER_PUBLIC_METHODS = [
- 'package_name',
- 'parseProjectFile',
- 'purgeProjectFileCache',
-];
-
+var cachedApis = {};
-// A single class that exposes functionality from platform specific files from
-// both places cordova/metadata and plugman/platforms. Hopefully, to be soon
-// replaced by real unified platform specific classes.
-function PlatformProjectAdapter(platform, platformRootDir) {
- var self = this;
- self.root = platformRootDir;
- self.platform = platform;
- var ParserConstructor = require(platforms[platform].parser_file);
- self.parser = new ParserConstructor(platformRootDir);
- self.handler = require(platforms[platform].handler_file);
+// getPlatformApi() should be the only method of instantiating the
+// PlatformProject classes for now.
+function getPlatformApi(platform, platformRootDir) {
- // Expose all public methods from the parser and handler, properly bound.
- PARSER_PUBLIC_METHODS.forEach(function(method) {
- self[method] = self.parser[method].bind(self.parser);
- });
+ // if platformRootDir is not specified, try to detect it first
+ if (!platformRootDir) {
+ var projectRootDir = util.isCordova();
+ platformRootDir = projectRootDir && path.join(projectRootDir, 'platforms', platform);
+ }
- HANDLER_PUBLIC_METHODS.forEach(function(method) {
- if (self.handler[method]) {
- self[method] = self.handler[method].bind(self.handler);
- }
- });
+ if (!platformRootDir) {
+ // If platformRootDir is still undefined, then we're probably is not inside of cordova project
+ throw new Error('Current location is not a Cordova project');
+ }
- self.getInstaller = function(type) {
- function installWrapper(item, plugin_dir, plugin_id, options, project) {
- self.handler[type].install(item, plugin_dir, self.root, plugin_id, options, project);
- }
- return installWrapper;
- };
+ var cached = cachedApis[platformRootDir];
+ if (cached && cached.platform == platform) return cached;
- self.getUninstaller = function(type) {
- function uninstallWrapper(item, plugin_id, options, project) {
- self.handler[type].uninstall(item, self.root, plugin_id, options, project);
- }
- return uninstallWrapper;
- };
-}
+ if (!platforms[platform]) throw new Error('Unknown platform ' + platform);
-// getPlatformProject() should be the only method of instantiating the
-// PlatformProject classes for now.
-function getPlatformProject(platform, platformRootDir) {
- var cached = cachedProjects[platformRootDir];
- if (cached && cached.platform == platform) {
- return cachedProjects[platformRootDir];
- } else if (platforms[platform]) {
- var adapter = new PlatformProjectAdapter(platform, platformRootDir);
- cachedProjects[platformRootDir] = adapter;
- return adapter;
- } else {
- throw new Error('Unknown platform ' + platform);
+ var PlatformApi;
+ try {
+ // First we need to find whether platform exposes its' API via js module
+ // If it has, then we have to require it and extend BasePlatformApi
+ // with platform's API.
+ var platformApiModule = path.join(platformRootDir, 'cordova', 'Api.js');
+ PlatformApi = require(platformApiModule);
+ } catch (err) {
+ PlatformApi = require('./PlatformApiPoly');
}
+
+ var platformApi = new PlatformApi(platform, platformRootDir);
+ cachedApis[platformRootDir] = platformApi;
+ return platformApi;
}
module.exports = platforms;
@@ -107,6 +65,5 @@ module.exports = platforms;
// We don't want these methods to be enumerable on the platforms object, because we expect enumerable properties of the
// platforms object to be platforms.
Object.defineProperties(module.exports, {
- 'getPlatformProject': {value: getPlatformProject, configurable: true, writable: true},
- 'PlatformProjectAdapter': {value: PlatformProjectAdapter, configurable: true, writable: true}
+ 'getPlatformApi': {value: getPlatformApi, configurable: true, writable: true}
});
http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/07271a5c/cordova-lib/src/plugman/browserify.js
----------------------------------------------------------------------
diff --git a/cordova-lib/src/plugman/browserify.js b/cordova-lib/src/plugman/browserify.js
new file mode 100644
index 0000000..8d5581b
--- /dev/null
+++ b/cordova-lib/src/plugman/browserify.js
@@ -0,0 +1,181 @@
+/**
+ 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 unused:false, expr:true */
+
+var platform_modules = require('../platforms/platforms'),
+ path = require('path'),
+ aliasify = require('aliasify'),
+ config_changes = require('./util/config-changes'),
+ common = require('./platforms/common'),
+ fs = require('fs'),
+ childProcess = require('child_process'),
+ util = require('util'),
+ events = require('../events'),
+ plugman = require('./plugman'),
+ bundle = require('cordova-js/tasks/lib/bundle-browserify'),
+ writeLicenseHeader = require('cordova-js/tasks/lib/write-license-header'),
+ Q = require('q'),
+ computeCommitId = require('cordova-js/tasks/lib/compute-commit-id'),
+ Readable = require('stream').Readable;
+
+var PlatformJson = require('./util/PlatformJson');
+var PluginInfoProvider = require('../PluginInfoProvider');
+
+function generateFinalBundle(platform, libraryRelease, outReleaseFile, commitId, platformVersion) {
+ var deferred = Q.defer();
+ var outReleaseFileStream = fs.createWriteStream(outReleaseFile);
+ var time = new Date().valueOf();
+ var symbolList = null;
+
+ writeLicenseHeader(outReleaseFileStream, platform, commitId, platformVersion);
+
+ var releaseBundle = libraryRelease.bundle();
+
+ releaseBundle.pipe(outReleaseFileStream);
+
+ outReleaseFileStream.on('finish', function() {
+ var newtime = new Date().valueOf() - time;
+ plugman.emit('verbose', 'generated cordova.' + platform + '.js @ ' + commitId + ' in ' + newtime + 'ms');
+ deferred.resolve();
+ // TODO clean up all the *.browserify files
+ });
+
+ outReleaseFileStream.on('error', function(err) {
+ events.emit('log', 'error while generating cordova.js');
+ deferred.reject();
+ });
+ return deferred.promise;
+}
+
+function computeCommitIdSync() {
+ var deferred = Q.defer();
+ computeCommitId(function(cId){
+ deferred.resolve(cId);
+ });
+ return deferred.promise;
+}
+
+function getPlatformVersion(cId, project_dir) {
+ var deferred = Q.defer();
+ //run version script for each platform to get platformVersion
+ var versionPath = path.join(project_dir, '/cordova/version');
+ childProcess.exec('"' + versionPath + '"', function(err, stdout, stderr) {
+ if (err) {
+ events.emit('log', 'Error running platform version script');
+ events.emit('log', err);
+ deferred.resolve('N/A');
+ } else {
+ deferred.resolve(stdout.trim());
+ }
+ });
+ return deferred.promise;
+}
+
+module.exports = function doBrowserify (project, platformApi, pluginInfoProvider) {
+ // Process:
+ // - Do config munging by calling into config-changes module
+ // - List all plugins in plugins_dir
+ // - Load and parse their plugin.xml files.
+ // - Skip those without support for this platform. (No <platform> tags means JS-only!)
+ // - Build a list of all their js-modules, including platform-specific js-modules.
+ // - For each js-module (general first, then platform) build up an object storing the path and any clobbers, merges and runs for it.
+ // Write this object into www/cordova_plugins.json.
+ // This file is not really used. Maybe cordova app harness
+ var platform = platformApi.platform;
+ events.emit('verbose', 'Preparing ' + platform + ' browserify project');
+ pluginInfoProvider = pluginInfoProvider || new PluginInfoProvider(); // Allow null for backwards-compat.
+ var platformJson = PlatformJson.load(project.locations.plugins, platform);
+ var wwwDir = platformApi.getPlatformInfo().locations.www;
+
+ var commitId;
+ return computeCommitIdSync()
+ .then(function(cId){
+ commitId = cId;
+ return getPlatformVersion(commitId, platformApi.root);
+ }).then(function(platformVersion){
+ var libraryRelease = bundle(platform, false, commitId, platformVersion);
+
+ var pluginMetadata = {};
+ var modulesMetadata = [];
+
+ var plugins = Object.keys(platformJson.root.installed_plugins).concat(Object.keys(platformJson.root.dependent_plugins));
+ events.emit('verbose', 'Iterating over installed plugins:', plugins);
+ plugins.forEach(function (plugin) {
+ var pluginDir = path.join(project.locations.plugins, plugin);
+ var pluginInfo = pluginInfoProvider.get(pluginDir);
+ // pluginMetadata is a mapping from plugin IDs to versions.
+ pluginMetadata[pluginInfo.id] = pluginInfo.version;
+
+ // Copy www assets described in <asset> tags.
+ pluginInfo.getAssets(platform)
+ .forEach(function(asset) {
+ common.asset.install(asset, pluginDir, wwwDir);
+ });
+
+ pluginInfo.getJsModules(platform)
+ .forEach(function(jsModule) {
+ var moduleName = jsModule.name ? jsModule.name : path.basename(jsModule.src, '.js');
+ var moduleId = pluginInfo.id + '.' + moduleName;
+ var moduleMetadata = {file: jsModule.src, id: moduleId, name: moduleName};
+
+ if (jsModule.clobbers.length > 0) {
+ moduleMetadata.clobbers = jsModule.clobbers.map(function(o) { return o.target; });
+ }
+ if (jsModule.merges.length > 0) {
+ moduleMetadata.merges = jsModule.merges.map(function(o) { return o.target; });
+ }
+ if (jsModule.runs) {
+ moduleMetadata.runs = true;
+ }
+
+ modulesMetadata.push(moduleMetadata);
+ libraryRelease.require(path.join(pluginDir, jsModule.src), { expose: moduleId });
+ });
+ });
+
+ events.emit('verbose', 'Writing out cordova_plugins.js...');
+
+ // Create a stream and write plugin metadata into it
+ // instead of generating intermediate file on FS
+ var cordova_plugins = new Readable();
+ cordova_plugins.push(
+ 'module.exports.metadata = ' + JSON.stringify(pluginMetadata, null, 4) + ';\n' +
+ 'module.exports = ' + JSON.stringify(modulesMetadata, null, 4) + ';\n', 'utf8');
+ cordova_plugins.push(null);
+
+ var bootstrap = new Readable();
+ bootstrap.push('require(\'cordova/init\');\n', 'utf8');
+ bootstrap.push(null);
+
+ var moduleAliases = modulesMetadata
+ .reduce(function (accum, meta) {
+ accum['./' + meta.name] = meta.id;
+ return accum;
+ }, {});
+
+ libraryRelease
+ .add(cordova_plugins, {file: path.join(wwwDir, 'cordova_plugins.js'), expose: 'cordova/plugin_list'})
+ .add(bootstrap)
+ .transform(aliasify, {aliases: moduleAliases});
+
+ var outReleaseFile = path.join(wwwDir, 'cordova.js');
+ return generateFinalBundle(platform, libraryRelease, outReleaseFile, commitId, platformVersion);
+ });
+};
http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/07271a5c/cordova-lib/src/plugman/install.js
----------------------------------------------------------------------
diff --git a/cordova-lib/src/plugman/install.js b/cordova-lib/src/plugman/install.js
index b99d155..071e851 100644
--- a/cordova-lib/src/plugman/install.js
+++ b/cordova-lib/src/plugman/install.js
@@ -471,7 +471,6 @@ function tryFetchDependency(dep, install, options) {
dep.subdir = '';
return Q(url);
}).fail(function(error){
-//console.log("Failed to resolve url='.': " + error);
return Q(dep.url);
});
@@ -565,35 +564,27 @@ function handleInstall(actions, pluginInfo, platform, project_dir, plugins_dir,
// @tests - important this event is checked spec/install.spec.js
events.emit('verbose', 'Install start for "' + pluginInfo.id + '" on ' + platform + '.');
- var handler = platform_modules.getPlatformProject(platform, project_dir);
- var frameworkFiles = pluginInfo.getFrameworks(platform); // Frameworks are needed later
- var pluginItems = pluginInfo.getFilesAndFrameworks(platform);
-
- // queue up native stuff
- pluginItems.forEach(function(item) {
- actions.push(actions.createAction(handler.getInstaller(item.itemType),
- [item, plugin_dir, pluginInfo.id, options],
- handler.getUninstaller(item.itemType),
- [item, pluginInfo.id, options]));
- });
- // run through the action stack
- return actions.process(platform, project_dir)
- .then(function(err) {
- // queue up the plugin so prepare knows what to do.
- var platformJson = PlatformJson.load(plugins_dir, platform);
- platformJson.addInstalledPluginToPrepareQueue(pluginInfo.id, filtered_variables, options.is_top_level);
- platformJson.save();
- // call prepare after a successful install
- if (options.browserify) {
- return plugman.prepareBrowserify(project_dir, platform, plugins_dir, options.www_dir, options.is_top_level, options.pluginInfoProvider);
- } else {
- return plugman.prepare(project_dir, platform, plugins_dir, options.www_dir, options.is_top_level, options.pluginInfoProvider);
- }
- }).then (function() {
+ options.variables = filtered_variables;
+ // Set up platform to install asset files/js modules to <platform>/platform_www dir
+ // instead of <platform>/www. This is required since on each prepare platform's www dir is changed
+ // and files from 'platform_www' merged into 'www'. Thus we need to persist these
+ // files platform_www directory, so they'll be applied to www on each prepare.
+ options.usePlatformWww = true;
+
+ return platform_modules.getPlatformApi(platform, project_dir)
+ .addPlugin(pluginInfo, options)
+ .then (function() {
events.emit('verbose', 'Install complete for ' + pluginInfo.id + ' on ' + platform + '.');
+ // Add plugin to installed list. This already done in platform,
+ // but need to be duplicated here to manage dependencies properly.
+ PlatformJson.load(plugins_dir, platform)
+ .addPlugin(pluginInfo.id, filtered_variables, options.is_top_level)
+ .save();
+
+ if (platform == 'android' && semver.gte(options.platformVersion, '4.0.0-dev') &&
+ pluginInfo.getFrameworks('platform').length > 0) {
- if (platform == 'android' && semver.gte(options.platformVersion, '4.0.0-dev') && frameworkFiles.length > 0) {
events.emit('verbose', 'Updating build files since android plugin contained <framework>');
var buildModule;
try {
http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/07271a5c/cordova-lib/src/plugman/platforms/common.js
----------------------------------------------------------------------
diff --git a/cordova-lib/src/plugman/platforms/common.js b/cordova-lib/src/plugman/platforms/common.js
index e3d3bcd..358ceed 100644
--- a/cordova-lib/src/plugman/platforms/common.js
+++ b/cordova-lib/src/plugman/platforms/common.js
@@ -79,7 +79,11 @@ module.exports = common = {
},
// Sometimes we want to remove some java, and prune any unnecessary empty directories
deleteJava:function(project_dir, destFile) {
- var file = path.resolve(project_dir, destFile);
+ common.removeFileAndParents(project_dir, destFile, 'src');
+ },
+ removeFileAndParents:function(baseDir, destFile, stopper) {
+ stopper = stopper || '.';
+ var file = path.resolve(baseDir, destFile);
if (!fs.existsSync(file)) return;
common.removeFileF(file);
@@ -87,7 +91,7 @@ module.exports = common = {
// check if directory is empty
var curDir = path.dirname(file);
- while(curDir !== path.resolve(project_dir, 'src')) {
+ while(curDir !== path.resolve(baseDir, stopper)) {
if(fs.existsSync(curDir) && fs.readdirSync(curDir).length === 0) {
fs.rmdirSync(curDir);
curDir = path.resolve(curDir, '..');
@@ -119,5 +123,27 @@ module.exports = common = {
common.removeFile(www_dir, target);
common.removeFileF(path.resolve(www_dir, 'plugins', plugin_id));
}
+ },
+ 'js-module': {
+ install: function (jsModule, plugin_dir, plugin_id, www_dir) {
+ // Copy the plugin's files into the www directory.
+ var moduleSource = path.resolve(plugin_dir, jsModule.src);
+ var moduleName = plugin_id + '.' + (jsModule.name || path.parse(jsModule.src).name);
+
+ // Read in the file, prepend the cordova.define, and write it back out.
+ var scriptContent = fs.readFileSync(moduleSource, 'utf-8').replace(/^\ufeff/, ''); // Window BOM
+ if (moduleSource.match(/.*\.json$/)) {
+ scriptContent = 'module.exports = ' + scriptContent;
+ }
+ scriptContent = 'cordova.define("' + moduleName + '", function(require, exports, module) { ' + scriptContent + '\n});\n';
+
+ var moduleDestination = path.resolve(www_dir, 'plugins', plugin_id, jsModule.src);
+ shell.mkdir('-p', path.dirname(moduleDestination));
+ fs.writeFileSync(moduleDestination, scriptContent, 'utf-8');
+ },
+ uninstall: function (jsModule, www_dir, plugin_id) {
+ var pluginRelativePath = path.join('plugins', plugin_id, jsModule.src);
+ common.removeFileAndParents(www_dir, pluginRelativePath);
+ }
}
};
http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/07271a5c/cordova-lib/src/plugman/plugman.js
----------------------------------------------------------------------
diff --git a/cordova-lib/src/plugman/plugman.js b/cordova-lib/src/plugman/plugman.js
index 7d952f5..67637ed 100644
--- a/cordova-lib/src/plugman/plugman.js
+++ b/cordova-lib/src/plugman/plugman.js
@@ -65,8 +65,7 @@ var plugman = {
addProperty(plugman, 'install', './install', true);
addProperty(plugman, 'uninstall', './uninstall', true);
addProperty(plugman, 'fetch', './fetch', true);
-addProperty(plugman, 'prepare', './prepare');
-addProperty(plugman, 'prepareBrowserify', './prepare-browserify');
+addProperty(plugman, 'browserify', './browserify');
addProperty(plugman, 'help', './help');
addProperty(plugman, 'config', './config', true);
addProperty(plugman, 'owner', './owner', true);
http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/07271a5c/cordova-lib/src/plugman/prepare-browserify.js
----------------------------------------------------------------------
diff --git a/cordova-lib/src/plugman/prepare-browserify.js b/cordova-lib/src/plugman/prepare-browserify.js
deleted file mode 100644
index 2dfb26a..0000000
--- a/cordova-lib/src/plugman/prepare-browserify.js
+++ /dev/null
@@ -1,214 +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 unused:false, expr:true */
-
-var platform_modules = require('../platforms/platforms'),
- path = require('path'),
- aliasify = require('aliasify'),
- config_changes = require('./util/config-changes'),
- common = require('./platforms/common'),
- fs = require('fs'),
- childProcess = require('child_process'),
- shell = require('shelljs'),
- util = require('util'),
- events = require('../events'),
- plugman = require('./plugman'),
- bundle = require('cordova-js/tasks/lib/bundle-browserify'),
- writeLicenseHeader = require('cordova-js/tasks/lib/write-license-header'),
- Q = require('q'),
- computeCommitId = require('cordova-js/tasks/lib/compute-commit-id'),
- Readable = require('stream').Readable;
-
-var PlatformJson = require('./util/PlatformJson');
-var PluginInfoProvider = require('../PluginInfoProvider');
-
-function uninstallQueuedPlugins(platformJson, wwwDir) {
- // Check if there are any plugins queued for uninstallation, and if so, remove any of their plugin web assets loaded in
- // via <js-module> elements
- var plugins_to_uninstall = platformJson.root.prepare_queue.uninstalled;
- if (plugins_to_uninstall && plugins_to_uninstall.length) {
- var plugins_www = path.join(wwwDir, 'plugins');
- if (fs.existsSync(plugins_www)) {
- plugins_to_uninstall.forEach(function(plug) {
- var id = plug.id;
- var plugin_modules = path.join(plugins_www, id);
- if (fs.existsSync(plugin_modules)) {
- events.emit('verbose', 'Removing plugins directory from www "'+plugin_modules+'"');
- shell.rm('-rf', plugin_modules);
- }
- });
- }
- }
-}
-
-function generateFinalBundle(platform, libraryRelease, outReleaseFile, commitId, platformVersion) {
- var deferred = Q.defer();
- var outReleaseFileStream = fs.createWriteStream(outReleaseFile);
- var time = new Date().valueOf();
- var symbolList = null;
-
- writeLicenseHeader(outReleaseFileStream, platform, commitId, platformVersion);
-
- var releaseBundle = libraryRelease.bundle();
-
- releaseBundle.pipe(outReleaseFileStream);
-
- outReleaseFileStream.on('finish', function() {
- var newtime = new Date().valueOf() - time;
- plugman.emit('verbose', 'generated cordova.' + platform + '.js @ ' + commitId + ' in ' + newtime + 'ms');
- deferred.resolve();
- // TODO clean up all the *.browserify files
- });
-
- outReleaseFileStream.on('error', function(err) {
- var newtime = new Date().valueOf() - time;
- events.emit('log', 'error while generating cordova.js');
- deferred.reject();
- });
- return deferred.promise;
-}
-
-function computeCommitIdSync() {
- var deferred = Q.defer();
- computeCommitId(function(cId){
- deferred.resolve(cId);
- });
- return deferred.promise;
-}
-
-function getPlatformVersion(cId, project_dir) {
- var deferred = Q.defer();
- //run version script for each platform to get platformVersion
- var versionPath = path.join(project_dir, '/cordova/version');
- childProcess.exec('"' + versionPath + '"', function(err, stdout, stderr) {
- if (err) {
- events.emit('log', 'Error running platform version script');
- events.emit('log', err);
- deferred.resolve('N/A');
- } else {
- deferred.resolve(stdout.trim());
- }
- });
- return deferred.promise;
-}
-
-// Called on --prepare.
-// Sets up each plugin's Javascript code to be loaded properly.
-// Expects a path to the project (platforms/android in CLI, . in plugman-only),
-// a path to where the plugins are downloaded, the www dir, and the platform ('android', 'ios', etc.).
-module.exports = function handlePrepare(project_dir, platform, plugins_dir, www_dir, is_top_level, pluginInfoProvider) {
- // Process:
- // - Do config munging by calling into config-changes module
- // - List all plugins in plugins_dir
- // - Load and parse their plugin.xml files.
- // - Skip those without support for this platform. (No <platform> tags means JS-only!)
- // - Build a list of all their js-modules, including platform-specific js-modules.
- // - For each js-module (general first, then platform) build up an object storing the path and any clobbers, merges and runs for it.
- // Write this object into www/cordova_plugins.json.
- // This file is not really used. Maybe cordova app harness
- events.emit('verbose', 'Preparing ' + platform + ' browserify project');
- pluginInfoProvider = pluginInfoProvider || new PluginInfoProvider(); // Allow null for backwards-compat.
- var platformJson = PlatformJson.load(plugins_dir, platform);
- var wwwDir = www_dir || platform_modules.getPlatformProject(platform, project_dir).www_dir();
-
- uninstallQueuedPlugins(platformJson, www_dir);
-
- events.emit('verbose', 'Processing configuration changes for plugins.');
- config_changes.process(plugins_dir, project_dir, platform, platformJson, pluginInfoProvider);
-
- if(!is_top_level) {
- return Q();
- }
-
- var commitId;
- return computeCommitIdSync()
- .then(function(cId){
- commitId = cId;
- return getPlatformVersion(commitId, project_dir);
- }).then(function(platformVersion){
- var libraryRelease = bundle(platform, false, commitId, platformVersion);
-
- var pluginMetadata = {};
- var modulesMetadata = [];
-
- var plugins = Object.keys(platformJson.root.installed_plugins).concat(Object.keys(platformJson.root.dependent_plugins));
- events.emit('verbose', 'Iterating over installed plugins:', plugins);
- plugins && plugins.forEach(function(plugin) {
- var pluginDir = path.join(plugins_dir, plugin);
- var pluginInfo = pluginInfoProvider.get(pluginDir);
- // pluginMetadata is a mapping from plugin IDs to versions.
- pluginMetadata[pluginInfo.id] = pluginInfo.version;
-
- // Copy www assets described in <asset> tags.
- pluginInfo.getAssets(platform)
- .forEach(function(asset) {
- common.asset.install(asset, pluginDir, wwwDir);
- });
-
- pluginInfo.getJsModules(platform)
- .forEach(function(jsModule) {
- var moduleName = jsModule.name ? jsModule.name : path.basename(jsModule.src, '.js');
- var moduleId = pluginInfo.id + '.' + moduleName;
- var moduleMetadata = {file: jsModule.src, id: moduleId, name: moduleName};
-
- if (jsModule.clobbers.length > 0) {
- moduleMetadata.clobbers = jsModule.clobbers.map(function(o) { return o.target; });
- }
- if (jsModule.merges.length > 0) {
- moduleMetadata.merges = jsModule.merges.map(function(o) { return o.target; });
- }
- if (jsModule.runs) {
- moduleMetadata.runs = true;
- }
-
- modulesMetadata.push(moduleMetadata);
- libraryRelease.require(path.join(pluginDir, jsModule.src), { expose: moduleId });
- });
- });
-
- events.emit('verbose', 'Writing out cordova_plugins.js...');
-
- // Create a stream and write plugin metadata into it
- // instead of generating intermediate file on FS
- var cordova_plugins = new Readable();
- cordova_plugins.push(
- 'module.exports.metadata = ' + JSON.stringify(pluginMetadata, null, 4) + ';\n' +
- 'module.exports = ' + JSON.stringify(modulesMetadata, null, 4) + ';\n', 'utf8');
- cordova_plugins.push(null);
-
- var bootstrap = new Readable();
- bootstrap.push('require(\'cordova/init\');\n', 'utf8');
- bootstrap.push(null);
-
- var moduleAliases = modulesMetadata
- .reduce(function (accum, meta) {
- accum['./' + meta.name] = meta.id;
- return accum;
- }, {});
-
- libraryRelease
- .add(cordova_plugins, {file: path.join(wwwDir, 'cordova_plugins.js'), expose: 'cordova/plugin_list'})
- .add(bootstrap)
- .transform(aliasify, {aliases: moduleAliases});
-
- var outReleaseFile = path.join(wwwDir, 'cordova.js');
- return generateFinalBundle(platform, libraryRelease, outReleaseFile, commitId, platformVersion);
- });
-};
http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/07271a5c/cordova-lib/src/plugman/prepare.js
----------------------------------------------------------------------
diff --git a/cordova-lib/src/plugman/prepare.js b/cordova-lib/src/plugman/prepare.js
deleted file mode 100644
index c52d92e..0000000
--- a/cordova-lib/src/plugman/prepare.js
+++ /dev/null
@@ -1,159 +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 expr:true, quotmark:false */
-
-var platform_modules = require('../platforms/platforms'),
- path = require('path'),
- config_changes = require('./util/config-changes'),
- common = require('./platforms/common'),
- fs = require('fs'),
- shell = require('shelljs'),
- Q = require('q'),
- events = require('../events');
-var PlatformJson = require('./util/PlatformJson');
-var PluginInfoProvider = require('../PluginInfoProvider');
-
-// Called on --prepare.
-// Sets up each plugin's Javascript code to be loaded properly.
-// Expects a path to the project (platforms/android in CLI, . in plugman-only),
-// a path to where the plugins are downloaded, the www dir, and the platform ('android', 'ios', etc.).
-module.exports = function handlePrepare(project_dir, platform, plugins_dir, www_dir, is_top_level, pluginInfoProvider) {
- // Process:
- // - Do config munging by calling into config-changes module
- // - List all plugins in plugins_dir
- // - Load and parse their plugin.xml files.
- // - Skip those without support for this platform. (No <platform> tags means JS-only!)
- // - Build a list of all their js-modules, including platform-specific js-modules.
- // - For each js-module (general first, then platform) build up an object storing the path and any clobbers, merges and runs for it.
- // - Write this object into www/cordova_plugins.json.
- // - Cordova.js contains code to load them at runtime from that file.
- events.emit('verbose', 'Preparing ' + platform + ' project');
- pluginInfoProvider = pluginInfoProvider || new PluginInfoProvider(); // Allow null for backwards-compat.
- var platformJson = PlatformJson.load(plugins_dir, platform);
- var wwwDir = www_dir || platform_modules.getPlatformProject(platform, project_dir).www_dir();
-
- // Check if there are any plugins queued for uninstallation, and if so, remove any of their plugin web assets loaded in
- // via <js-module> elements
- var plugins_to_uninstall = platformJson.root.prepare_queue.uninstalled;
- if (plugins_to_uninstall && plugins_to_uninstall.length) {
- var plugins_www = path.join(wwwDir, 'plugins');
- if (fs.existsSync(plugins_www)) {
- plugins_to_uninstall.forEach(function(plug) {
- var id = plug.id;
- var plugin_modules = path.join(plugins_www, id);
- if (fs.existsSync(plugin_modules)) {
- events.emit('verbose', 'Removing plugins directory from www "'+plugin_modules+'"');
- shell.rm('-rf', plugin_modules);
- }
- });
- }
- }
-
- events.emit('verbose', 'Processing configuration changes for plugins.');
- config_changes.process(plugins_dir, project_dir, platform, platformJson, pluginInfoProvider);
-
- // This array holds all the metadata for each module and ends up in cordova_plugins.json
- var plugins = Object.keys(platformJson.root.installed_plugins).concat(Object.keys(platformJson.root.dependent_plugins));
- var moduleObjects = [];
- var pluginMetadata = {};
- events.emit('verbose', 'Iterating over installed plugins:', plugins);
-
- plugins && plugins.forEach(function(plugin) {
- var pluginDir = path.join(plugins_dir, plugin);
- var pluginInfo = pluginInfoProvider.get(pluginDir);
-
- var plugin_id = pluginInfo.id;
- // pluginMetadata is a mapping from plugin IDs to versions.
- pluginMetadata[plugin_id] = pluginInfo.version;
-
- // add the plugins dir to the platform's www.
- var platformPluginsDir = path.join(wwwDir, 'plugins');
- // XXX this should not be here if there are no js-module. It leaves an empty plugins/ directory
- shell.mkdir('-p', platformPluginsDir);
-
- var jsModules = pluginInfo.getJsModules(platform);
- var assets = pluginInfo.getAssets(platform);
-
- // Copy www assets described in <asset> tags.
- assets.forEach(function(asset) {
- common.asset.install(asset, pluginDir, wwwDir);
- });
-
- jsModules.forEach(function(module) {
- // Copy the plugin's files into the www directory.
- // NB: We can't always use path.* functions here, because they will use platform slashes.
- // But the path in the plugin.xml and in the cordova_plugins.js should be always forward slashes.
- var pathParts = module.src.split('/');
-
- var fsDirname = path.join.apply(path, pathParts.slice(0, -1));
- var fsDir = path.join(platformPluginsDir, plugin_id, fsDirname);
- shell.mkdir('-p', fsDir);
-
- // Read in the file, prepend the cordova.define, and write it back out.
- var moduleName = plugin_id + '.';
- if (module.name) {
- moduleName += module.name;
- } else {
- var result = module.src.match(/([^\/]+)\.js/);
- moduleName += result[1];
- }
-
- var fsPath = path.join.apply(path, pathParts);
- var scriptContent = fs.readFileSync(path.join(pluginDir, fsPath), 'utf-8').replace(/^\ufeff/, ''); // Window BOM
- if (fsPath.match(/.*\.json$/)) {
- scriptContent = 'module.exports = ' + scriptContent;
- }
- scriptContent = 'cordova.define("' + moduleName + '", function(require, exports, module) { ' + scriptContent + '\n});\n';
- fs.writeFileSync(path.join(platformPluginsDir, plugin_id, fsPath), scriptContent, 'utf-8');
-
- // Prepare the object for cordova_plugins.json.
- var obj = {
- file: ['plugins', plugin_id, module.src].join('/'),
- id: moduleName
- };
- if (module.clobbers.length > 0) {
- obj.clobbers = module.clobbers.map(function(o) { return o.target; });
- }
- if (module.merges.length > 0) {
- obj.merges = module.merges.map(function(o) { return o.target; });
- }
- if (module.runs) {
- obj.runs = true;
- }
-
- // Add it to the list of module objects bound for cordova_plugins.json
- moduleObjects.push(obj);
- });
- });
-
- // Write out moduleObjects as JSON wrapped in a cordova module to cordova_plugins.js
- var final_contents = "cordova.define('cordova/plugin_list', function(require, exports, module) {\n";
- final_contents += 'module.exports = ' + JSON.stringify(moduleObjects,null,' ') + ';\n';
- final_contents += 'module.exports.metadata = \n';
- final_contents += '// TOP OF METADATA\n';
- final_contents += JSON.stringify(pluginMetadata, null, ' ') + '\n';
- final_contents += '// BOTTOM OF METADATA\n';
- final_contents += '});'; // Close cordova.define.
-
- events.emit('verbose', 'Writing out cordova_plugins.js...');
- fs.writeFileSync(path.join(wwwDir, 'cordova_plugins.js'), final_contents, 'utf-8');
-
- return Q();
-};
http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/07271a5c/cordova-lib/src/plugman/uninstall.js
----------------------------------------------------------------------
diff --git a/cordova-lib/src/plugman/uninstall.js b/cordova-lib/src/plugman/uninstall.js
index 9fdc2e4..1bc1e2f 100644
--- a/cordova-lib/src/plugman/uninstall.js
+++ b/cordova-lib/src/plugman/uninstall.js
@@ -30,7 +30,6 @@ var path = require('path'),
Q = require('q'),
events = require('../events'),
platform_modules = require('../platforms/platforms'),
- plugman = require('./plugman'),
promiseutil = require('../util/promise-util'),
HooksRunner = require('../hooks/HooksRunner'),
cordovaUtil = require('../cordova/util');
@@ -299,49 +298,23 @@ function runUninstallPlatform(actions, platform, project_dir, plugin_dir, plugin
// Returns a promise.
function handleUninstall(actions, platform, pluginInfo, project_dir, www_dir, plugins_dir, is_top_level, options) {
- var plugin_id = pluginInfo.id;
- var plugin_dir = pluginInfo.dir;
- var handler = platform_modules.getPlatformProject(platform, project_dir);
- www_dir = www_dir || handler.www_dir();
- events.emit('log', 'Uninstalling ' + plugin_id + ' from ' + platform);
-
- var pluginItems = pluginInfo.getFilesAndFrameworks(platform);
- var assets = pluginInfo.getAssets(platform);
- var frameworkFiles = pluginInfo.getFrameworks(platform);
-
- // queue up native stuff
- pluginItems.forEach(function(item) {
- // CB-5238 Don't uninstall non custom frameworks.
- if (item.itemType == 'framework' && !item.custom) return;
- actions.push(actions.createAction(handler.getUninstaller(item.itemType),
- [item, plugin_id, options],
- handler.getInstaller(item.itemType),
- [item, plugin_dir, plugin_id, options]));
- });
-
- // queue up asset uninstallation
- var common = require('./platforms/common');
- assets.forEach(function(asset) {
- actions.push(actions.createAction(common.asset.uninstall, [asset, www_dir, plugin_id], common.asset.install, [asset, plugin_dir, www_dir]));
- });
+ events.emit('log', 'Uninstalling ' + pluginInfo.id + ' from ' + platform);
- // run through the action stack
- return actions.process(platform, project_dir)
+ // Set up platform to uninstall asset files/js modules
+ // from <platform>/platform_www dir instead of <platform>/www.
+ options.usePlatformWww = true;
+ return platform_modules.getPlatformApi(platform, project_dir)
+ .removePlugin(pluginInfo, options)
.then(function() {
- // WIN!
- events.emit('verbose', plugin_id + ' uninstalled from ' + platform + '.');
- // queue up the plugin so prepare can remove the config changes
- var platformJson = PlatformJson.load(plugins_dir, platform);
- platformJson.addUninstalledPluginToPrepareQueue(plugin_id, is_top_level);
- platformJson.save();
- // call prepare after a successful uninstall
- if (options.browserify) {
- return plugman.prepareBrowserify(project_dir, platform, plugins_dir, www_dir, is_top_level, options.pluginInfoProvider);
- } else {
- return plugman.prepare(project_dir, platform, plugins_dir, www_dir, is_top_level, options.pluginInfoProvider);
- }
- }).then(function() {
- if (platform == 'android' && semver.gte(options.platformVersion, '4.0.0-dev') && frameworkFiles.length > 0) {
+ // Remove plugin from installed list. This already done in platform,
+ // but need to be duplicated here to remove plugin entry from project's
+ // plugin list to manage dependencies properly.
+ PlatformJson.load(plugins_dir, platform)
+ .removePlugin(pluginInfo.id, is_top_level)
+ .save();
+
+ if (platform == 'android' && semver.gte(options.platformVersion, '4.0.0-dev') &&
+ pluginInfo.getFrameworks(platform).length > 0) {
events.emit('verbose', 'Updating build files since android plugin contained <framework>');
var buildModule;
try {
http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/07271a5c/cordova-lib/src/plugman/util/ConfigFile.js
----------------------------------------------------------------------
diff --git a/cordova-lib/src/plugman/util/ConfigFile.js b/cordova-lib/src/plugman/util/ConfigFile.js
index c317668..15191ad 100644
--- a/cordova-lib/src/plugman/util/ConfigFile.js
+++ b/cordova-lib/src/plugman/util/ConfigFile.js
@@ -69,7 +69,7 @@ function ConfigFile_load() {
self.data = xml_helpers.parseElementtreeSync(filepath);
} else if (ext == '.pbxproj') {
self.type = 'pbxproj';
- var projectFile = platforms.getPlatformProject('ios', self.project_dir).parseProjectFile(self.project_dir);
+ var projectFile = platforms.getPlatformApi('ios', self.project_dir)._handler.parseProjectFile(self.project_dir);
self.data = projectFile.xcode;
self.cordovaVersion = projectFile.cordovaVersion;
} else {
http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/07271a5c/cordova-lib/src/plugman/util/PlatformJson.js
----------------------------------------------------------------------
diff --git a/cordova-lib/src/plugman/util/PlatformJson.js b/cordova-lib/src/plugman/util/PlatformJson.js
index 1b9f05b..318a5d9 100644
--- a/cordova-lib/src/plugman/util/PlatformJson.js
+++ b/cordova-lib/src/plugman/util/PlatformJson.js
@@ -81,6 +81,26 @@ PlatformJson.prototype.isPluginInstalled = function(pluginId) {
this.isPluginDependent(pluginId);
};
+PlatformJson.prototype.addPlugin = function(pluginId, variables, isTopLevel) {
+ var pluginsList = isTopLevel ?
+ this.root.installed_plugins :
+ this.root.dependent_plugins;
+
+ pluginsList[pluginId] = variables;
+
+ return this;
+};
+
+PlatformJson.prototype.removePlugin = function(pluginId, isTopLevel) {
+ var pluginsList = isTopLevel ?
+ this.root.installed_plugins :
+ this.root.dependent_plugins;
+
+ delete pluginsList[pluginId];
+
+ return this;
+};
+
PlatformJson.prototype.addInstalledPluginToPrepareQueue = function(pluginDirName, vars, is_top_level) {
this.root.prepare_queue.installed.push({'plugin':pluginDirName, 'vars':vars, 'topLevel':is_top_level});
};
http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/07271a5c/cordova-lib/src/plugman/util/action-stack.js
----------------------------------------------------------------------
diff --git a/cordova-lib/src/plugman/util/action-stack.js b/cordova-lib/src/plugman/util/action-stack.js
index c8bd21b..c1c2a4e 100644
--- a/cordova-lib/src/plugman/util/action-stack.js
+++ b/cordova-lib/src/plugman/util/action-stack.js
@@ -19,8 +19,7 @@
/* jshint quotmark:false */
-var platforms = require("../../platforms/platforms"),
- events = require('../../events'),
+var events = require('../../events'),
Q = require('q');
function ActionStack() {
@@ -47,22 +46,11 @@ ActionStack.prototype = {
// Returns a promise.
process:function(platform, project_dir) {
events.emit('verbose', 'Beginning processing of action stack for ' + platform + ' project...');
- var project_files;
-
- // parse platform-specific project files once
- var platformProject = platforms.getPlatformProject(platform, project_dir);
- if (platformProject.parseProjectFile) {
- events.emit('verbose', 'Parsing ' + platform + ' project files...');
- project_files = platformProject.parseProjectFile(project_dir);
- }
while (this.stack.length) {
var action = this.stack.shift();
var handler = action.handler.run;
var action_params = action.handler.params;
- if (project_files) {
- action_params.push(project_files);
- }
try {
handler.apply(null, action_params);
@@ -76,10 +64,6 @@ ActionStack.prototype = {
var revert = undo.reverter.run;
var revert_params = undo.reverter.params;
- if (project_files) {
- revert_params.push(project_files);
- }
-
try {
revert.apply(null, revert_params);
} catch(err) {
@@ -94,10 +78,6 @@ ActionStack.prototype = {
}
events.emit('verbose', 'Action stack processing complete.');
- if (project_files) {
- events.emit('verbose', 'Writing out ' + platform + ' project files...');
- project_files.write();
- }
return Q();
}
};
http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/07271a5c/cordova-lib/src/plugman/util/config-changes.js
----------------------------------------------------------------------
diff --git a/cordova-lib/src/plugman/util/config-changes.js b/cordova-lib/src/plugman/util/config-changes.js
index 63c3ec3..ff23e2a 100644
--- a/cordova-lib/src/plugman/util/config-changes.js
+++ b/cordova-lib/src/plugman/util/config-changes.js
@@ -54,8 +54,8 @@ var keep_these_frameworks = [
exports.PlatformMunger = PlatformMunger;
exports.process = function(plugins_dir, project_dir, platform, platformJson, pluginInfoProvider) {
- var munger = new PlatformMunger(platform, project_dir, plugins_dir, platformJson, pluginInfoProvider);
- munger.process();
+ var munger = new PlatformMunger(platform, project_dir, platformJson, pluginInfoProvider);
+ munger.process(plugins_dir);
munger.save_all();
};
@@ -65,12 +65,10 @@ exports.process = function(plugins_dir, project_dir, platform, platformJson, plu
* Can deal with config file of a single project.
* Parsed config files are cached in a ConfigKeeper object.
******************************************************************************/
-function PlatformMunger(platform, project_dir, plugins_dir, platformJson, pluginInfoProvider) {
+function PlatformMunger(platform, project_dir, platformJson, pluginInfoProvider) {
checkPlatform(platform);
this.platform = platform;
this.project_dir = project_dir;
- this.plugins_dir = plugins_dir;
- this.platform_handler = platforms.getPlatformProject(platform, project_dir);
this.config_keeper = new ConfigKeeper(project_dir);
this.platformJson = platformJson;
this.pluginInfoProvider = pluginInfoProvider;
@@ -130,14 +128,15 @@ function PlatformMunger_apply_file_munge(file, munge, remove) {
PlatformMunger.prototype.remove_plugin_changes = remove_plugin_changes;
-function remove_plugin_changes(plugin_name, plugin_id, is_top_level) {
+function remove_plugin_changes(pluginInfo, is_top_level) {
var self = this;
var platform_config = self.platformJson.root;
- var plugin_dir = path.join(self.plugins_dir, plugin_name);
- var plugin_vars = (is_top_level ? platform_config.installed_plugins[plugin_id] : platform_config.dependent_plugins[plugin_id]);
+ var plugin_vars = is_top_level ?
+ platform_config.installed_plugins[pluginInfo.id] :
+ platform_config.dependent_plugins[pluginInfo.id];
// get config munge, aka how did this plugin change various config files
- var config_munge = self.generate_plugin_config_munge(plugin_dir, plugin_vars);
+ var config_munge = self.generate_plugin_config_munge(pluginInfo, plugin_vars);
// global munge looks at all plugins' changes to config files
var global_munge = platform_config.config_munge;
var munge = mungeutil.decrement_munge(global_munge, config_munge);
@@ -147,7 +146,7 @@ function remove_plugin_changes(plugin_name, plugin_id, is_top_level) {
// TODO: remove this check and <plugins-plist> sections in spec/plugins/../plugin.xml files.
events.emit(
'warn',
- 'WARNING: Plugin "' + plugin_id + '" uses <plugins-plist> element(s), ' +
+ 'WARNING: Plugin "' + pluginInfo.id + '" uses <plugins-plist> element(s), ' +
'which are no longer supported. Support has been removed as of Cordova 3.4.'
);
continue;
@@ -168,22 +167,18 @@ function remove_plugin_changes(plugin_name, plugin_id, is_top_level) {
}
// Remove from installed_plugins
- if (is_top_level) {
- delete platform_config.installed_plugins[plugin_id];
- } else {
- delete platform_config.dependent_plugins[plugin_id];
- }
+ self.platformJson.removePlugin(pluginInfo.id, is_top_level);
+ return self;
}
PlatformMunger.prototype.add_plugin_changes = add_plugin_changes;
-function add_plugin_changes(plugin_id, plugin_vars, is_top_level, should_increment) {
+function add_plugin_changes(pluginInfo, plugin_vars, is_top_level, should_increment) {
var self = this;
var platform_config = self.platformJson.root;
- var plugin_dir = path.join(self.plugins_dir, plugin_id);
// get config munge, aka how should this plugin change various config files
- var config_munge = self.generate_plugin_config_munge(plugin_dir, plugin_vars);
+ var config_munge = self.generate_plugin_config_munge(pluginInfo, plugin_vars);
// global munge looks at all plugins' changes to config files
// TODO: The should_increment param is only used by cordova-cli and is going away soon.
@@ -203,7 +198,7 @@ function add_plugin_changes(plugin_id, plugin_vars, is_top_level, should_increme
if (file == 'plugins-plist' && self.platform == 'ios') {
events.emit(
'warn',
- 'WARNING: Plugin "' + plugin_id + '" uses <plugins-plist> element(s), ' +
+ 'WARNING: Plugin "' + pluginInfo.id + '" uses <plugins-plist> element(s), ' +
'which are no longer supported. Support has been removed as of Cordova 3.4.'
);
continue;
@@ -222,12 +217,9 @@ function add_plugin_changes(plugin_id, plugin_vars, is_top_level, should_increme
self.apply_file_munge(file, munge.files[file]);
}
- // Move to installed_plugins if it is a top-level plugin
- if (is_top_level) {
- platform_config.installed_plugins[plugin_id] = plugin_vars || {};
- } else {
- platform_config.dependent_plugins[plugin_id] = plugin_vars || {};
- }
+ // Move to installed/dependent_plugins
+ self.platformJson.addPlugin(pluginInfo.id, plugin_vars || {}, is_top_level);
+ return self;
}
@@ -253,24 +245,19 @@ function reapply_global_munge () {
self.apply_file_munge(file, global_munge.files[file]);
}
+
+ return self;
}
// generate_plugin_config_munge
// Generate the munge object from plugin.xml + vars
PlatformMunger.prototype.generate_plugin_config_munge = generate_plugin_config_munge;
-function generate_plugin_config_munge(plugin_dir, vars) {
+function generate_plugin_config_munge(pluginInfo, vars) {
var self = this;
vars = vars || {};
- // Add PACKAGE_NAME variable into vars
- if (!vars['PACKAGE_NAME']) {
- vars['PACKAGE_NAME'] = self.platform_handler.package_name(self.project_dir);
- }
-
var munge = { files: {} };
- var pluginInfo = self.pluginInfoProvider.get(plugin_dir);
-
var changes = pluginInfo.getConfigFiles(self.platform);
// note down pbxproj framework munges in special section of munge obj
@@ -283,10 +270,14 @@ function generate_plugin_config_munge(plugin_dir, vars) {
}
});
}
-
+
// Demux 'package.appxmanifest' into relevant platform-specific appx manifests.
// Only spend the cycles if there are version-specific plugin settings
- if (self.platform === 'windows' && changes.some(function(change) { return ((typeof change.versions !== 'undefined') || (typeof change.deviceTarget !== 'undefined')); }))
+ if (self.platform === 'windows' &&
+ changes.some(function(change) {
+ return ((typeof change.versions !== 'undefined') ||
+ (typeof change.deviceTarget !== 'undefined'));
+ }))
{
var manifests = {
'windows': {
@@ -334,7 +325,7 @@ function generate_plugin_config_munge(plugin_dir, vars) {
// at this point, 'change' targets package.appxmanifest and has a version attribute
knownWindowsVersionsForTargetDeviceSet.forEach(function(winver) {
- // This is a local function that creates the new replacement representing the
+ // This is a local function that creates the new replacement representing the
// mutation. Used to save code further down.
var createReplacement = function(manifestFile, originalChange) {
var replacement = {
@@ -389,18 +380,20 @@ function generate_plugin_config_munge(plugin_dir, vars) {
// Go over the prepare queue and apply the config munges for each plugin
// that has been (un)installed.
PlatformMunger.prototype.process = PlatformMunger_process;
-function PlatformMunger_process() {
+function PlatformMunger_process(plugins_dir) {
var self = this;
var platform_config = self.platformJson.root;
// Uninstallation first
platform_config.prepare_queue.uninstalled.forEach(function(u) {
- self.remove_plugin_changes(u.plugin, u.id, u.topLevel);
+ var pluginInfo = self.pluginInfoProvider.get(path.join(plugins_dir, u.plugin));
+ self.remove_plugin_changes(pluginInfo, u.topLevel);
});
// Now handle installation
platform_config.prepare_queue.installed.forEach(function(u) {
- self.add_plugin_changes(u.plugin, u.vars, u.topLevel, true);
+ var pluginInfo = self.pluginInfoProvider.get(path.join(plugins_dir, u.plugin));
+ self.add_plugin_changes(pluginInfo, u.vars, u.topLevel, true);
});
// Empty out installed/ uninstalled queues.
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@cordova.apache.org
For additional commands, e-mail: commits-help@cordova.apache.org