diff --git a/bin/templates/cordova/Api.js b/bin/templates/cordova/Api.js index 0a207e4d..7c44b132 100644 --- a/bin/templates/cordova/Api.js +++ b/bin/templates/cordova/Api.js @@ -42,7 +42,7 @@ function setupEvents(externalEventEmitter) { return externalEventEmitter; } - // There is no logger if external emitter is not present, + // There is no logger if external emitter is not present, // so attach a console logger CordovaLogger.get().subscribe(selfEvents); return selfEvents; @@ -241,11 +241,14 @@ Api.prototype.addPlugin = function (plugin, installOptions) { require('./lib/builders/builders').getBuilder('gradle').prepBuildFiles(); } - var targetDir = installOptions.usePlatformWww ? - self.locations.platformWww : - self.locations.www; + var targetDirs = [self.locations.www]; + // CB-11022 if usePlatformWww is specified we need to mirror modules metadata to both directories + if (installOptions.usePlatformWww) targetDirs.push(self.locations.platformWww); + self._addModulesInfo(plugin, targetDirs); - self._addModulesInfo(plugin, targetDir); + // CB-11022 Indicate to caller that we have copied js-files and assets + // to both 'www' and 'platform_www' so prepare is not needed + return true; }); }; @@ -299,11 +302,14 @@ Api.prototype.removePlugin = function (plugin, uninstallOptions) { require('./lib/builders/builders').getBuilder('gradle').prepBuildFiles(); } - var targetDir = uninstallOptions.usePlatformWww ? - self.locations.platformWww : - self.locations.www; + var targetDirs = [self.locations.www]; + // CB-11022 if usePlatformWww is specified we need to mirror modules metadata to both directories + if (uninstallOptions.usePlatformWww) targetDirs.push(self.locations.platformWww); + self._removeModulesInfo(plugin, targetDirs); - self._removeModulesInfo(plugin, targetDir); + // CB-11022 Indicate to caller that we have copied js-files and assets + // to both 'www' and 'platform_www' so prepare is not needed + return true; }); }; @@ -425,10 +431,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) { @@ -463,7 +469,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(); }; @@ -473,10 +479,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 directories, 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) { @@ -493,19 +499,18 @@ Api.prototype._removeModulesInfo = function(plugin, targetDir) { delete this._platformJson.root.plugin_metadata[plugin.id]; } - this._writePluginModules(targetDir); + this._writePluginModules(targetDirs); this._platformJson.save(); }; /** * Fetches all installed modules, generates cordova_plugins contents and writes - * it to file. + * it to cordova_plugins.js file at specified directories. * - * @param {String} targetDir Directory, where write cordova_plugins.js to. - * Ususally it is either /www or /platform_www - * directories. + * @param {String[]} targetDirs Directories, where write cordova_plugins.js to. + * Ususally it is either /www or /platform_www or both. */ -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'; @@ -516,6 +521,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/bin/templates/cordova/lib/pluginHandlers.js b/bin/templates/cordova/lib/pluginHandlers.js index 83ccf372..d14bcf63 100644 --- a/bin/templates/cordova/lib/pluginHandlers.js +++ b/bin/templates/cordova/lib/pluginHandlers.js @@ -128,17 +128,24 @@ 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) { + // CB-11022 copy file to both directories if usePlatformWww is specified + 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); - removeFileF(path.resolve(www, 'plugins', plugin.id)); + removeFileF(path.resolve(project.www, target)); + removeFileF(path.resolve(project.www, 'plugins', plugin.id)); + if (options && options.usePlatformWww) { + // CB-11022 remove file from both directories if usePlatformWww is specified + removeFileF(path.resolve(project.platformWww, target)); + removeFileF(path.resolve(project.platformWww, 'plugins', plugin.id)); + } } }, 'js-module': { @@ -154,15 +161,24 @@ 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); - shell.mkdir('-p', path.dirname(moduleDestination)); - fs.writeFileSync(moduleDestination, scriptContent, 'utf-8'); + var wwwDest = path.resolve(project.www, 'plugins', plugin.id, obj.src); + shell.mkdir('-p', path.dirname(wwwDest)); + fs.writeFileSync(wwwDest, scriptContent, 'utf-8'); + + if (options && options.usePlatformWww) { + // CB-11022 copy file to both directories if usePlatformWww is specified + var platformWwwDest = path.resolve(project.platformWww, 'plugins', plugin.id, obj.src); + shell.mkdir('-p', path.dirname(platformWwwDest)); + fs.writeFileSync(platformWwwDest, 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) { + // CB-11022 remove file from both directories if usePlatformWww is specified + removeFileAndParents(project.platformWww, pluginRelativePath); + } } } }; diff --git a/spec/unit/pluginHandlers/handlers.spec.js b/spec/unit/pluginHandlers/handlers.spec.js index abeb48b9..93ac4a1f 100644 --- a/spec/unit/pluginHandlers/handlers.spec.js +++ b/spec/unit/pluginHandlers/handlers.spec.js @@ -50,6 +50,7 @@ describe('android project handler', function() { beforeEach(function() { shell.mkdir('-p', temp); dummyProject = AndroidProject.getProjectFile(temp); + copyFileSpy.reset(); common.__set__('copyFile', copyFileSpy); }); @@ -161,6 +162,51 @@ describe('android project handler', function() { expect(dummyProject.addGradleReference).toHaveBeenCalledWith(dummyProject.projectDir, someString); }); }); + + describe('of elements', function() { + var jsModule = {src: 'www/dummyPlugin.js'}; + var wwwDest, platformWwwDest; + + 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 () { + android['js-module'].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 () { + android['js-module'].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; + + beforeEach(function () { + 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 () { + android.asset.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 () { + android.asset.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() { @@ -254,5 +300,66 @@ describe('android project handler', function() { expect(dummyProject.removeGradleReference).toHaveBeenCalledWith(dummyProject.projectDir, someString); }); }); + + + describe('of elements', function() { + var jsModule = {src: 'www/dummyPlugin.js'}; + var wwwDest, platformWwwDest; + + 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 () { + android['js-module'].uninstall(jsModule, dummyPluginInfo, dummyProject, {usePlatformWww: true}); + expect(shell.rm).toHaveBeenCalledWith('-Rf', wwwDest); + expect(shell.rm).toHaveBeenCalledWith('-Rf', platformWwwDest); + }); + + it('should put module to www only when options.usePlatformWww flag is not specified', function () { + android['js-module'].uninstall(jsModule, dummyPluginInfo, dummyProject); + expect(shell.rm).toHaveBeenCalledWith('-Rf', wwwDest); + expect(shell.rm).not.toHaveBeenCalledWith('-Rf', platformWwwDest); + }); + }); + + describe('of elements', function() { + var asset = {src: 'www/dummyPlugin.js', target: 'foo/dummy.js'}; + var wwwDest, platformWwwDest; + + 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 () { + android.asset.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 () { + android.asset.uninstall(asset, dummyPluginInfo, dummyProject); + expect(shell.rm).toHaveBeenCalledWith(jasmine.any(String), wwwDest); + expect(shell.rm).not.toHaveBeenCalledWith(jasmine.any(String), platformWwwDest); + }); + }); }); });