From 4c9eb1311bbca379d6140264b21d725290406f2a Mon Sep 17 00:00:00 2001 From: Vladimir Kotikov Date: Thu, 14 Apr 2016 12:55:55 +0300 Subject: [PATCH] CB-11022 Duplicate www files on plugin installtion --- spec/unit/pluginHandler/windows.spec.js | 112 ++++++++++++++++++++++++ template/cordova/Api.js | 42 +++++---- template/cordova/lib/PluginHandler.js | 35 +++++--- 3 files changed, 156 insertions(+), 33 deletions(-) diff --git a/spec/unit/pluginHandler/windows.spec.js b/spec/unit/pluginHandler/windows.spec.js index 89fe7f80..38cad375 100644 --- a/spec/unit/pluginHandler/windows.spec.js +++ b/spec/unit/pluginHandler/windows.spec.js @@ -326,6 +326,55 @@ describe('windows project handler', function () { process.chdir(path.join(curDir, '..', '..', '..')); }); }); + + describe('of elements', function() { + var jsModule = {src: 'www/dummyplugin.js'}; + var wwwDest, platformWwwDest; + + var install = PluginHandler.getInstaller('js-module'); + + beforeEach(function () { + spyOn(fs, 'writeFileSync'); + wwwDest = path.resolve(dummyProject.www, 'plugins', dummyPluginInfo.id, jsModule.src); + platformWwwDest = path.resolve(dummyProject.platformWww, 'plugins', dummyPluginInfo.id, jsModule.src); + }); + + it('should put module to both www and platform_www when options.usePlatformWww flag is specified', function () { + install(jsModule, dummyPluginInfo, dummyProject, {usePlatformWww: true}); + expect(fs.writeFileSync).toHaveBeenCalledWith(wwwDest, jasmine.any(String), 'utf-8'); + expect(fs.writeFileSync).toHaveBeenCalledWith(platformWwwDest, jasmine.any(String), 'utf-8'); + }); + + it('should put module to www only when options.usePlatformWww flag is not specified', function () { + install(jsModule, dummyPluginInfo, dummyProject); + expect(fs.writeFileSync).toHaveBeenCalledWith(wwwDest, jasmine.any(String), 'utf-8'); + expect(fs.writeFileSync).not.toHaveBeenCalledWith(platformWwwDest, jasmine.any(String), 'utf-8'); + }); + }); + + describe('of elements', function() { + var asset = {src: 'www/dummyplugin.js', target: 'foo/dummy.js'}; + var wwwDest, platformWwwDest; + var install = PluginHandler.getInstaller('asset'); + + beforeEach(function () { + copyFileSpy.reset(); + wwwDest = path.resolve(dummyProject.www, asset.target); + platformWwwDest = path.resolve(dummyProject.platformWww, asset.target); + }); + + it('should put asset to both www and platform_www when options.usePlatformWww flag is specified', function () { + install(asset, dummyPluginInfo, dummyProject, {usePlatformWww: true}); + expect(copyFileSpy).toHaveBeenCalledWith(dummyPluginInfo.dir, asset.src, dummyProject.www, asset.target); + expect(copyFileSpy).toHaveBeenCalledWith(dummyPluginInfo.dir, asset.src, dummyProject.platformWww, asset.target); + }); + + it('should put asset to www only when options.usePlatformWww flag is not specified', function () { + install(asset, dummyPluginInfo, dummyProject); + expect(copyFileSpy).toHaveBeenCalledWith(dummyPluginInfo.dir, asset.src, dummyProject.www, asset.target); + expect(copyFileSpy).not.toHaveBeenCalledWith(dummyPluginInfo.dir, asset.src, dummyProject.platformWww, asset.target); + }); + }); }); describe('uninstallation', function () { @@ -526,5 +575,68 @@ describe('windows project handler', function () { process.chdir(path.join(curDir, '..', '..', '..')); }); }); + + describe('of elements', function() { + var jsModule = {src: 'www/dummyPlugin.js'}; + var wwwDest, platformWwwDest; + + var uninstall = PluginHandler.getUninstaller('js-module'); + + beforeEach(function () { + wwwDest = path.resolve(dummyProject.www, 'plugins', dummyPluginInfo.id, jsModule.src); + platformWwwDest = path.resolve(dummyProject.platformWww, 'plugins', dummyPluginInfo.id, jsModule.src); + + spyOn(shell, 'rm'); + + var existsSyncOrig = fs.existsSync; + spyOn(fs, 'existsSync').andCallFake(function (file) { + if ([wwwDest, platformWwwDest].indexOf(file) >= 0 ) return true; + return existsSyncOrig.call(fs, file); + }); + }); + + it('should put module to both www and platform_www when options.usePlatformWww flag is specified', function () { + uninstall(jsModule, dummyPluginInfo, dummyProject, {usePlatformWww: true}); + expect(shell.rm).toHaveBeenCalledWith(jasmine.any(String), wwwDest); + expect(shell.rm).toHaveBeenCalledWith(jasmine.any(String), platformWwwDest); + }); + + it('should put module to www only when options.usePlatformWww flag is not specified', function () { + uninstall(jsModule, dummyPluginInfo, dummyProject); + expect(shell.rm).toHaveBeenCalledWith(jasmine.any(String), wwwDest); + expect(shell.rm).not.toHaveBeenCalledWith(jasmine.any(String), platformWwwDest); + }); + }); + + describe('of elements', function() { + var asset = {src: 'www/dummyPlugin.js', target: 'foo/dummy.js'}; + var wwwDest, platformWwwDest; + var uninstall = PluginHandler.getUninstaller('asset'); + + beforeEach(function () { + wwwDest = path.resolve(dummyProject.www, asset.target); + platformWwwDest = path.resolve(dummyProject.platformWww, asset.target); + + spyOn(shell, 'rm'); + + var existsSyncOrig = fs.existsSync; + spyOn(fs, 'existsSync').andCallFake(function (file) { + if ([wwwDest, platformWwwDest].indexOf(file) >= 0 ) return true; + return existsSyncOrig.call(fs, file); + }); + }); + + it('should put module to both www and platform_www when options.usePlatformWww flag is specified', function () { + uninstall(asset, dummyPluginInfo, dummyProject, {usePlatformWww: true}); + expect(shell.rm).toHaveBeenCalledWith(jasmine.any(String), wwwDest); + expect(shell.rm).toHaveBeenCalledWith(jasmine.any(String), platformWwwDest); + }); + + it('should put module to www only when options.usePlatformWww flag is not specified', function () { + uninstall(asset, dummyPluginInfo, dummyProject); + expect(shell.rm).toHaveBeenCalledWith(jasmine.any(String), wwwDest); + expect(shell.rm).not.toHaveBeenCalledWith(jasmine.any(String), platformWwwDest); + }); + }); }); }); diff --git a/template/cordova/Api.js b/template/cordova/Api.js index c78e922d..56a42bc7 100644 --- a/template/cordova/Api.js +++ b/template/cordova/Api.js @@ -230,11 +230,12 @@ Api.prototype.addPlugin = function (plugin, installOptions) { .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; + var targetDirs = [self.getPlatformInfo().locations.www]; + if (installOptions.usePlatformWww) targetDirs.push(self.getPlatformInfo().locations.platformWww); + self._addModulesInfo(plugin, targetDirs); - self._addModulesInfo(plugin, targetDir); + // CB-11022 return non-falsy value to indicate that there is no need to run prepare after that + return true; }); }; @@ -278,13 +279,14 @@ Api.prototype.removePlugin = function (plugin, uninstallOptions) { .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); + var targetDirs = [self.getPlatformInfo().locations.www]; + if (uninstallOptions.usePlatformWww) targetDirs.push(self.getPlatformInfo().locations.platformWww); + self._removeModulesInfo(plugin, targetDirs); // Remove stale plugin directory shell.rm('-rf', path.resolve(self.root, 'Plugins', plugin.id)); + + // CB-11022 return non-falsy value to indicate that there is no need to run prepare after that + return true; }); }; @@ -390,10 +392,10 @@ module.exports = Api; * * @param {PluginInfo} plugin PluginInfo instance for plugin, which modules * needs to be added. - * @param {String} targetDir The directory, where updated cordova_plugins.js + * @param {String[]} targetDirs The directories, where updated cordova_plugins.js * should be written to. */ -Api.prototype._addModulesInfo = function(plugin, targetDir) { +Api.prototype._addModulesInfo = function(plugin, targetDirs) { var installedModules = this._platformJson.root.modules || []; var installedPaths = installedModules.map(function (installedModule) { @@ -429,7 +431,7 @@ Api.prototype._addModulesInfo = function(plugin, targetDir) { } this._platformJson.root.plugin_metadata[plugin.id] = plugin.version; - this._writePluginModules(targetDir); + this._writePluginModules(targetDirs); this._platformJson.save(); }; @@ -439,10 +441,10 @@ Api.prototype._addModulesInfo = function(plugin, targetDir) { * * @param {PluginInfo} plugin PluginInfo instance for plugin, which modules * needs to be removed. - * @param {String} targetDir The directory, where updated cordova_plugins.js + * @param {String[]} targetDirs The directory, where updated cordova_plugins.js * should be written to. */ -Api.prototype._removeModulesInfo = function(plugin, targetDir) { +Api.prototype._removeModulesInfo = function(plugin, targetDirs) { var installedModules = this._platformJson.root.modules || []; var modulesToRemove = plugin.getJsModules(this.platform) .map(function (jsModule) { @@ -459,7 +461,7 @@ Api.prototype._removeModulesInfo = function(plugin, targetDir) { delete this._platformJson.root.plugin_metadata[plugin.id]; } - this._writePluginModules(targetDir); + this._writePluginModules(targetDirs); this._platformJson.save(); }; @@ -467,11 +469,11 @@ Api.prototype._removeModulesInfo = function(plugin, targetDir) { * Fetches all installed modules, generates cordova_plugins contents and writes * it to file. * - * @param {String} targetDir Directory, where write cordova_plugins.js to. + * @param {String[]} targetDirs Directory, where write cordova_plugins.js to. * Ususally it is either /www or /platform_www * directories. */ -Api.prototype._writePluginModules = function (targetDir) { +Api.prototype._writePluginModules = function (targetDirs) { // 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'; @@ -482,6 +484,8 @@ Api.prototype._writePluginModules = function (targetDir) { 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'); + targetDirs.forEach(function (targetDir) { + shell.mkdir('-p', targetDir); + fs.writeFileSync(path.join(targetDir, 'cordova_plugins.js'), final_contents, 'utf-8'); + }); }; diff --git a/template/cordova/lib/PluginHandler.js b/template/cordova/lib/PluginHandler.js index ab2f3159..7ec07957 100644 --- a/template/cordova/lib/PluginHandler.js +++ b/template/cordova/lib/PluginHandler.js @@ -25,8 +25,8 @@ var shell = require('shelljs'); var events = require('cordova-common').events; var CordovaError = require('cordova-common').CordovaError; -// returns relative file path for a file in the plugin's folder that can be referenced -// from a project file. +// returns relative file path for a file in the plugin's folder that can be referenced +// from a project file. function getPluginFilePath(plugin, pluginFile, targetDir) { var src = path.resolve(plugin.dir, pluginFile); return '$(ProjectDir)' + path.relative(targetDir, src); @@ -53,10 +53,10 @@ var handlers = { }, 'resource-file':{ install:function(obj, plugin, project, options) { - // do not copy, but reference the file in the plugin folder. This allows to + // do not copy, but reference the file in the plugin folder. This allows to // have multiple source files map to the same target and select the appropriate // one based on the current build settings, e.g. architecture. - // also, we don't check for existence. This allows to insert build variables + // also, we don't check for existence. This allows to insert build variables // into the source file name, e.g. // var relativeSrcPath = getPluginFilePath(plugin, obj.src, project.projectFolder); @@ -123,24 +123,27 @@ var handlers = { throw new CordovaError(' tag without required "target" attribute'); } - var www = options.usePlatformWww ? project.platformWww : project.www; - copyFile(plugin.dir, obj.src, www, obj.target); + copyFile(plugin.dir, obj.src, project.www, obj.target); + if (options && options.usePlatformWww) copyFile(plugin.dir, obj.src, project.platformWww, obj.target); }, uninstall:function(obj, plugin, project, options) { var target = obj.target || obj.src; if (!target) throw new CordovaError(' tag without required "target" attribute'); - var www = options.usePlatformWww ? project.platformWww : project.www; - removeFile(www, target); - shell.rm('-Rf', path.resolve(www, 'plugins', plugin.id)); + removeFile(project.www, target); + removeFile(project.www, path.join('plugins', plugin.id)); + if (options && options.usePlatformWww) { + removeFile(project.platformWww, target); + removeFile(project.platformWww, path.join('plugins', plugin.id)); + } } }, 'js-module': { install: function (obj, plugin, project, options) { // Copy the plugin's files into the www directory. var moduleSource = path.resolve(plugin.dir, obj.src); - var moduleName = plugin.id + '.' + (obj.name || path.parse(obj.src).name); + var moduleName = plugin.id + '.' + (obj.name || path.basename(obj.src, path.extname (obj.src))); // Read in the file, prepend the cordova.define, and write it back out. var scriptContent = fs.readFileSync(moduleSource, 'utf-8').replace(/^\ufeff/, ''); // Window BOM @@ -149,15 +152,19 @@ var handlers = { } scriptContent = 'cordova.define("' + moduleName + '", function(require, exports, module) {\n' + scriptContent + '\n});\n'; - var www = options.usePlatformWww ? project.platformWww : project.www; - var moduleDestination = path.resolve(www, 'plugins', plugin.id, obj.src); + var moduleDestination = path.resolve(project.www, 'plugins', plugin.id, obj.src); shell.mkdir('-p', path.dirname(moduleDestination)); fs.writeFileSync(moduleDestination, scriptContent, 'utf-8'); + if (options && options.usePlatformWww) { + var platformWwwDestination = path.resolve(project.platformWww, 'plugins', plugin.id, obj.src); + shell.mkdir('-p', path.dirname(platformWwwDestination)); + fs.writeFileSync(platformWwwDestination, scriptContent, 'utf-8'); + } }, uninstall: function (obj, plugin, project, options) { var pluginRelativePath = path.join('plugins', plugin.id, obj.src); - var www = options.usePlatformWww ? project.platformWww : project.www; - removeFileAndParents(www, pluginRelativePath); + removeFileAndParents(project.www, pluginRelativePath); + if (options && options.usePlatformWww) removeFileAndParents(project.platformWww, pluginRelativePath); } } };