diff --git a/lib/bootstrap.ts b/lib/bootstrap.ts index 00e03f8d5e..81657d844f 100644 --- a/lib/bootstrap.ts +++ b/lib/bootstrap.ts @@ -59,4 +59,6 @@ $injector.require("broccoliPluginWrapper", "./tools/broccoli/broccoli-plugin-wra $injector.require("pluginsService", "./services/plugins-service"); $injector.requireCommand("plugin|add", "./commands/plugin/add-plugin"); $injector.requireCommand("plugin|remove", "./commands/plugin/remove-plugin"); -$injector.requireCommand("install", "./commands/install"); \ No newline at end of file +$injector.requireCommand("install", "./commands/install"); + +$injector.require("projectFilesManager", "./services/project-files-manager"); diff --git a/lib/declarations.ts b/lib/declarations.ts index 031322e9c5..5f7abb2e7d 100644 --- a/lib/declarations.ts +++ b/lib/declarations.ts @@ -64,3 +64,7 @@ interface IOptions extends ICommonOptions { keyStoreAliasPassword: string; sdk: string; } + +interface IProjectFilesManager { + processPlatformSpecificFiles(directoryPath: string, platform: string, excludedDirs?: string[]): IFuture; +} \ No newline at end of file diff --git a/lib/services/platform-service.ts b/lib/services/platform-service.ts index bde1e242ce..192d539482 100644 --- a/lib/services/platform-service.ts +++ b/lib/services/platform-service.ts @@ -23,7 +23,8 @@ export class PlatformService implements IPlatformService { private $commandsService: ICommandsService, private $options: IOptions, private $broccoliBuilder: IBroccoliBuilder, - private $pluginsService: IPluginsService) { } + private $pluginsService: IPluginsService, + private $projectFilesManager: IProjectFilesManager) { } public addPlatforms(platforms: string[]): IFuture { return (() => { @@ -165,19 +166,9 @@ export class PlatformService implements IPlatformService { } // Process platform specific files - var contents = this.$fs.readDirectory(path.join(platformData.appDestinationDirectoryPath, constants.APP_FOLDER_NAME)).wait(); - var files: string[] = []; - - _.each(contents, d => { - let filePath = path.join(platformData.appDestinationDirectoryPath, constants.APP_FOLDER_NAME, d); - let fsStat = this.$fs.getFsStats(filePath).wait(); - if(fsStat.isDirectory() && d !== constants.APP_RESOURCES_FOLDER_NAME) { - this.processPlatformSpecificFiles(platform, this.$fs.enumerateFilesInDirectorySync(filePath)).wait(); - } else if(fsStat.isFile()) { - files.push(filePath); - } - }); - this.processPlatformSpecificFiles(platform, files).wait(); + let directoryPath = path.join(platformData.appDestinationDirectoryPath, constants.APP_FOLDER_NAME); + let excludedDirs = [constants.APP_RESOURCES_FOLDER_NAME]; + this.$projectFilesManager.processPlatformSpecificFiles(directoryPath, platform, excludedDirs).wait(); // Process node_modules folder this.$pluginsService.ensureAllDependenciesAreInstalled().wait(); @@ -341,33 +332,6 @@ export class PlatformService implements IPlatformService { return platformData.platformProjectService.isPlatformPrepared(platformData.projectRoot); } - private static parsePlatformSpecificFileName(fileName: string, platforms: string[]): any { - var regex = util.format("^(.+?)\.(%s)(\..+?)$", platforms.join("|")); - var parsed = fileName.toLowerCase().match(new RegExp(regex, "i")); - if (parsed) { - return { - platform: parsed[2], - onDeviceName: parsed[1] + parsed[3] - }; - } - return undefined; - } - - private processPlatformSpecificFiles( platform: string, files: string[]): IFuture { - // Renames the files that have `platform` as substring and removes the files from other platform - return (() => { - _.each(files, fileName => { - var platformInfo = PlatformService.parsePlatformSpecificFileName(path.basename(fileName), this.$platformsData.platformsNames); - var shouldExcludeFile = platformInfo && platformInfo.platform !== platform; - if (shouldExcludeFile) { - this.$fs.deleteFile(fileName).wait(); - } else if (platformInfo && platformInfo.onDeviceName) { - this.$fs.rename(fileName, path.join(path.dirname(fileName), platformInfo.onDeviceName)).wait(); - } - }); - }).future()(); - } - private getApplicationPackages(buildOutputPath: string, validPackageNames: string[]): IFuture { return (() => { // Get latest package that is produced from build diff --git a/lib/services/plugins-service.ts b/lib/services/plugins-service.ts index de68eebb41..b5e5b10559 100644 --- a/lib/services/plugins-service.ts +++ b/lib/services/plugins-service.ts @@ -24,7 +24,7 @@ export class PluginsService implements IPluginsService { private $options: IOptions, private $logger: ILogger, private $errors: IErrors, - private $injector: IInjector) { } + private $projectFilesManager: IProjectFilesManager) { } public add(plugin: string): IFuture { return (() => { @@ -101,7 +101,9 @@ export class PluginsService implements IPluginsService { if(this.$fs.exists(pluginPlatformsFolderPath).wait()) { shelljs.rm("-rf", pluginPlatformsFolderPath); - } + } + + this.$projectFilesManager.processPlatformSpecificFiles(pluginDestinationPath, platform).wait(); // TODO: Add libraries diff --git a/lib/services/project-files-manager.ts b/lib/services/project-files-manager.ts new file mode 100644 index 0000000000..40be8f4336 --- /dev/null +++ b/lib/services/project-files-manager.ts @@ -0,0 +1,56 @@ +/// +"use strict"; +import path = require("path"); +import util = require("util"); + +export class ProjectFilesManager implements IProjectFilesManager { + constructor(private $fs: IFileSystem, + private $platformsData: IPlatformsData) { } + + public processPlatformSpecificFiles(directoryPath: string, platform: string, excludedDirs?: string[]): IFuture { + return (() => { + var contents = this.$fs.readDirectory(directoryPath).wait(); + var files: string[] = []; + + _.each(contents, fileName => { + let filePath = path.join(directoryPath, fileName); + let fsStat = this.$fs.getFsStats(filePath).wait(); + if(fsStat.isDirectory() && !_.contains(excludedDirs, fileName)) { + this.processPlatformSpecificFilesCore(platform, this.$fs.enumerateFilesInDirectorySync(filePath)).wait(); + } else if(fsStat.isFile()) { + files.push(filePath); + } + }); + this.processPlatformSpecificFilesCore(platform, files).wait(); + + }).future()(); + } + + private processPlatformSpecificFilesCore(platform: string, files: string[]): IFuture { + // Renames the files that have `platform` as substring and removes the files from other platform + return (() => { + _.each(files, fileName => { + var platformInfo = ProjectFilesManager.parsePlatformSpecificFileName(path.basename(fileName), this.$platformsData.platformsNames); + var shouldExcludeFile = platformInfo && platformInfo.platform !== platform; + if (shouldExcludeFile) { + this.$fs.deleteFile(fileName).wait(); + } else if (platformInfo && platformInfo.onDeviceName) { + this.$fs.rename(fileName, path.join(path.dirname(fileName), platformInfo.onDeviceName)).wait(); + } + }); + }).future()(); + } + + private static parsePlatformSpecificFileName(fileName: string, platforms: string[]): any { + var regex = util.format("^(.+?)\\.(%s)(\\..+?)$", platforms.join("|")); + var parsed = fileName.match(new RegExp(regex, "i")); + if (parsed) { + return { + platform: parsed[2], + onDeviceName: parsed[1] + parsed[3] + }; + } + return undefined; + } +} +$injector.register("projectFilesManager", ProjectFilesManager); diff --git a/test/npm-support.ts b/test/npm-support.ts index d7a557f79e..ce66886dfa 100644 --- a/test/npm-support.ts +++ b/test/npm-support.ts @@ -19,6 +19,8 @@ import BroccoliBuilderLib = require("../lib/tools/broccoli/builder"); import NodeModulesTreeLib = require("../lib/tools/broccoli/trees/node-modules-tree"); import PluginsServiceLib = require("../lib/services/plugins-service"); import ChildProcessLib = require("../lib/common/child-process"); +import ProjectFilesManagerLib = require("../lib/services/project-files-manager"); +import Future = require("fibers/future"); import path = require("path"); import temp = require("temp"); @@ -53,6 +55,7 @@ function createTestInjector(): IInjector { testInjector.register("pluginsService", PluginsServiceLib.PluginsService); testInjector.register("npm", NpmLib.NodePackageManager); testInjector.register("childProcess", ChildProcessLib.ChildProcess); + testInjector.register("projectFilesManager", ProjectFilesManagerLib.ProjectFilesManager); testInjector.register("commandsServiceProvider", { registerDynamicSubCommands: () => {} }); diff --git a/test/platform-commands.ts b/test/platform-commands.ts index 3038102f2e..f5a56e7031 100644 --- a/test/platform-commands.ts +++ b/test/platform-commands.ts @@ -11,6 +11,7 @@ import StaticConfigLib = require("../lib/config"); import CommandsServiceLib = require("../lib/common/services/commands-service"); import optionsLib = require("../lib/options"); import hostInfoLib = require("../lib/common/host-info"); +import ProjectFilesManagerLib = require("../lib/services/project-files-manager"); import path = require("path"); import Future = require("fibers/future"); var assert = require("chai").assert; @@ -115,6 +116,7 @@ function createTestInjector() { }).future()(); } }); + testInjector.register("projectFilesManager", ProjectFilesManagerLib.ProjectFilesManager); return testInjector; } diff --git a/test/platform-service.ts b/test/platform-service.ts index ce2782d899..e2fc5ea3bf 100644 --- a/test/platform-service.ts +++ b/test/platform-service.ts @@ -18,6 +18,7 @@ import ProjectDataLib = require("../lib/project-data"); import ProjectHelperLib = require("../lib/common/project-helper"); import optionsLib = require("../lib/options"); import hostInfoLib = require("../lib/common/host-info"); +import ProjectFilesManagerLib = require("../lib/services/project-files-manager"); import path = require("path"); import Future = require("fibers/future"); @@ -63,6 +64,7 @@ function createTestInjector() { return (() => { }).future()(); } }); + testInjector.register("projectFilesManager", ProjectFilesManagerLib.ProjectFilesManager); return testInjector; } @@ -235,7 +237,7 @@ describe('Platform Service Tests', () => { // Asserts that the files in app folder are process as platform specific assert.isTrue(fs.exists(path.join(appDestFolderPath, "app" , "test1.js")).wait()); - assert.isTrue(fs.exists(path.join(appDestFolderPath, "app", "test1-js")).wait()); + assert.isFalse(fs.exists(path.join(appDestFolderPath, "app", "test1-js")).wait()); assert.isFalse(fs.exists(path.join(appDestFolderPath, "app", "test2.js")).wait()); assert.isFalse(fs.exists(path.join(appDestFolderPath, "app", "test2-js")).wait()); @@ -286,7 +288,7 @@ describe('Platform Service Tests', () => { // Asserts that the files in app folder are process as platform specific assert.isTrue(fs.exists(path.join(appDestFolderPath, "app" , "test2.js")).wait()); - assert.isTrue(fs.exists(path.join(appDestFolderPath, "app", "test2-js")).wait()); + assert.isFalse(fs.exists(path.join(appDestFolderPath, "app", "test2-js")).wait()); assert.isFalse(fs.exists(path.join(appDestFolderPath, "app", "test1.js")).wait()); assert.isFalse(fs.exists(path.join(appDestFolderPath, "app", "test1-js")).wait()); diff --git a/test/plugins-service.ts b/test/plugins-service.ts index 781410308b..fdb5cd2083 100644 --- a/test/plugins-service.ts +++ b/test/plugins-service.ts @@ -17,6 +17,7 @@ import ProjectHelperLib = require("../lib/common/project-helper"); import PlatformsDataLib = require("../lib/platforms-data"); import ProjectDataServiceLib = require("../lib/services/project-data-service"); import helpers = require("../lib/common/helpers"); +import ProjectFilesManagerLib = require("../lib/services/project-files-manager"); import os = require("os"); import PluginsServiceLib = require("../lib/services/plugins-service"); @@ -64,6 +65,7 @@ function createTestInjector() { checkConsent: () => { return (() => { }).future()(); }, trackFeature: () => { return (() => { }).future()(); } }); + testInjector.register("projectFilesManager", ProjectFilesManagerLib.ProjectFilesManager); return testInjector; } diff --git a/test/project-files-manager.ts b/test/project-files-manager.ts new file mode 100644 index 0000000000..8b4cf41997 --- /dev/null +++ b/test/project-files-manager.ts @@ -0,0 +1,81 @@ +/// +"use strict"; + +import yok = require('../lib/common/yok'); +import fsLib = require("../lib/common/file-system"); +import projectFilesManagerLib = require("../lib/services/project-files-manager"); +import hostInfoLib = require("../lib/common/host-info"); +import StaticConfigLib = require("../lib/config"); +import ErrorsLib = require("../lib/common/errors"); +import path = require("path"); +import temp = require("temp"); +temp.track(); + +var assert = require("chai").assert; + +function createTestInjector() { + let testInjector = new yok.Yok(); + testInjector.register("fs", fsLib.FileSystem); + testInjector.register("hostInfo", hostInfoLib.HostInfo); + testInjector.register("staticConfig", StaticConfigLib.StaticConfig); + testInjector.register("projectFilesManager", projectFilesManagerLib.ProjectFilesManager); + testInjector.register("errors", ErrorsLib.Errors); + testInjector.register("platformsData", { + platformsNames: ["ios", "android"] + }); + + return testInjector; +} + +function createFiles(testInjector: IInjector, filesToCreate: string[]): IFuture { + return (() => { + let fs = testInjector.resolve("fs"); + let directoryPath = temp.mkdirSync("Project Files Manager Tests"); + + _.each(filesToCreate, file => fs.writeFile(path.join(directoryPath, file), "").wait()); + + return directoryPath; + }).future()(); +} + +describe('Project Files Manager Tests', () => { + let testInjector: IInjector, projectFilesManager: IProjectFilesManager; + beforeEach(() => { + testInjector = createTestInjector(); + projectFilesManager = testInjector.resolve("projectFilesManager"); + }); + it("filters android specific files", () => { + let files = ["test.ios.x", "test.android.x"]; + let directoryPath = createFiles(testInjector, files).wait(); + + projectFilesManager.processPlatformSpecificFiles(directoryPath, "android").wait(); + + let fs = testInjector.resolve("fs"); + assert.isFalse(fs.exists(path.join(directoryPath, "test.ios.x")).wait()); + assert.isTrue(fs.exists(path.join(directoryPath, "test.x")).wait()); + assert.isFalse(fs.exists(path.join(directoryPath, "test.android.x")).wait()); + }); + it("filters ios specific files", () => { + let files = ["index.ios.html", "index1.android.html", "a.test"]; + let directoryPath = createFiles(testInjector, files).wait(); + + projectFilesManager.processPlatformSpecificFiles(directoryPath, "ios").wait(); + + let fs = testInjector.resolve("fs"); + assert.isFalse(fs.exists(path.join(directoryPath, "index1.android.html")).wait()); + assert.isFalse(fs.exists(path.join(directoryPath, "index1.html")).wait()); + assert.isTrue(fs.exists(path.join(directoryPath, "index.html")).wait()); + assert.isTrue(fs.exists(path.join(directoryPath, "a.test")).wait()); + }); + it("doesn't filter non platform specific files", () => { + let files = ["index1.js", "index2.js", "index3.js"]; + let directoryPath = createFiles(testInjector, files).wait(); + + projectFilesManager.processPlatformSpecificFiles(directoryPath, "ios").wait(); + + let fs = testInjector.resolve("fs"); + assert.isTrue(fs.exists(path.join(directoryPath, "index1.js")).wait()); + assert.isTrue(fs.exists(path.join(directoryPath, "index2.js")).wait()); + assert.isTrue(fs.exists(path.join(directoryPath, "index3.js")).wait()); + }); +}); \ No newline at end of file