diff --git a/declarations.d.ts b/declarations.d.ts index bb9c628c..feadf11b 100644 --- a/declarations.d.ts +++ b/declarations.d.ts @@ -867,7 +867,7 @@ interface ILiveSyncServiceBase { * If watch option is not specified executes full sync * If watch option is specified executes partial sync */ - sync(data: ILiveSyncData[], projectId: string, filePaths?: string[]): Promise; + sync(data: ILiveSyncData[], projectId: string, projectFilesConfig: IProjectFilesConfig, filePaths?: string[]): Promise; /** * Returns the `canExecute` method which defines if LiveSync operation can be executed on specified device. @@ -1489,7 +1489,7 @@ interface IProjectFilesManager { * @param {string[]} excludedDirs Directories which should be skipped. * @returns {void} */ - processPlatformSpecificFiles(directoryPath: string, platform: string, excludedDirs?: string[]): void; + processPlatformSpecificFiles(directoryPath: string, platform: string, projectFilesConfig?: IProjectFilesConfig, excludedDirs?: string[]): void; } interface IProjectFilesProvider { @@ -1500,7 +1500,7 @@ interface IProjectFilesProvider { /** * Performs local file path mapping */ - mapFilePath(filePath: string, platform: string, projectData?: any): string; + mapFilePath(filePath: string, platform: string, projectData: any, projectFilesConfig?: IProjectFilesConfig): string; /** * Returns information about file in the project, that includes file's name on device after removing platform or configuration from the name. @@ -1509,13 +1509,13 @@ interface IProjectFilesProvider { * @param {IProjectFilesConfig} projectFilesConfig configuration for additional parsing * @return {IProjectFileInfo} */ - getProjectFileInfo(filePath: string, platform: string, projectFilesConfig?: IProjectFilesConfig): IProjectFileInfo; + getProjectFileInfo(filePath: string, platform: string, projectFilesConfig: IProjectFilesConfig): IProjectFileInfo; /** * Parses file by removing platform or configuration from its name. * @param {string} filePath Path to the project file. * @return {string} Parsed file name or original file name in case it does not have platform/configuration in the filename. */ - getPreparedFilePath(filePath: string): string; + getPreparedFilePath(filePath: string, projectFilesConfig: IProjectFilesConfig): string; } /** diff --git a/helpers.ts b/helpers.ts index c7a5c89a..a16473cb 100644 --- a/helpers.ts +++ b/helpers.ts @@ -3,6 +3,7 @@ import * as net from "net"; let Table = require("cli-table"); import { platform, EOL } from "os"; import { ReadStream } from "tty"; +import { Configurations } from "./constants"; import { EventEmitter } from "events"; import * as crypto from "crypto"; @@ -405,6 +406,13 @@ export async function connectEventuallyUntilTimeout(factory: () => net.Socket, t }); } +export function getProjectFilesConfig(opts: { isReleaseBuild: boolean }): IProjectFilesConfig { + const projectFilesConfig: IProjectFilesConfig = { + configuration: opts.isReleaseBuild ? Configurations.Release.toLowerCase() : Configurations.Debug.toLowerCase() + }; + return projectFilesConfig; +} + /** * Tries to find the process id (PID) of the specified application identifier. * This is specific implementation for iOS Simulator, where the running applications are real processes. diff --git a/services/livesync-service-base.ts b/services/livesync-service-base.ts index f0687acd..193a055b 100644 --- a/services/livesync-service-base.ts +++ b/services/livesync-service-base.ts @@ -28,11 +28,11 @@ class LiveSyncServiceBase implements ILiveSyncServiceBase { this.fileHashes = Object.create(null); } - public async sync(data: ILiveSyncData[], projectId: string, filePaths?: string[]): Promise { + public async sync(data: ILiveSyncData[], projectId: string, projectFilesConfig: IProjectFilesConfig, filePaths?: string[]): Promise { await this.syncCore(data, filePaths); if (this.$options.watch) { await this.$hooksService.executeBeforeHooks('watch'); - this.partialSync(data, data[0].syncWorkingDirectory, projectId); + this.partialSync(data, data[0].syncWorkingDirectory, projectId, projectFilesConfig); } } @@ -48,7 +48,7 @@ class LiveSyncServiceBase implements ILiveSyncServiceBase { return isFileExcluded; } - private partialSync(data: ILiveSyncData[], syncWorkingDirectory: string, projectId: string): void { + private partialSync(data: ILiveSyncData[], syncWorkingDirectory: string, projectId: string, projectFilesConfig: IProjectFilesConfig): void { let that = this; this.showFullLiveSyncInformation = true; const gazeInstance = gaze(["**/*", "!node_modules/**/*", "!platforms/**/*"], { cwd: syncWorkingDirectory }, function (err: any, watcher: any) { @@ -76,7 +76,7 @@ class LiveSyncServiceBase implements ILiveSyncServiceBase { that.$logger.trace(`Skipping livesync for changed file ${filePath} as it is excluded in the patterns: ${dataItem.excludedProjectDirsAndFiles.join(", ")}`); continue; } - let mappedFilePath = that.$projectFilesProvider.mapFilePath(filePath, dataItem.platform, projectId); + let mappedFilePath = that.$projectFilesProvider.mapFilePath(filePath, dataItem.platform, projectId, projectFilesConfig); that.$logger.trace(`Syncing filePath ${filePath}, mappedFilePath is ${mappedFilePath}`); if (!mappedFilePath) { that.$logger.warn(`Unable to sync ${filePath}.`); diff --git a/services/project-files-manager.ts b/services/project-files-manager.ts index 0edff83f..32e6b331 100644 --- a/services/project-files-manager.ts +++ b/services/project-files-manager.ts @@ -37,7 +37,7 @@ export class ProjectFilesManager implements IProjectFilesManager { return localToDevicePaths; } - public processPlatformSpecificFiles(directoryPath: string, platform: string, excludedDirs?: string[]): void { + public processPlatformSpecificFiles(directoryPath: string, platform: string, projectFilesConfig: IProjectFilesConfig, excludedDirs?: string[]): void { let contents = this.$fs.readDirectory(directoryPath); let files: string[] = []; @@ -45,19 +45,19 @@ export class ProjectFilesManager implements IProjectFilesManager { let filePath = path.join(directoryPath, fileName); let fsStat = this.$fs.getFsStats(filePath); if (fsStat.isDirectory() && !_.includes(excludedDirs, fileName)) { - this.processPlatformSpecificFilesCore(platform, this.$fs.enumerateFilesInDirectorySync(filePath)); + this.processPlatformSpecificFilesCore(platform, this.$fs.enumerateFilesInDirectorySync(filePath), projectFilesConfig); } else if (fsStat.isFile()) { files.push(filePath); } }); - this.processPlatformSpecificFilesCore(platform, files); + this.processPlatformSpecificFilesCore(platform, files, projectFilesConfig); } - private processPlatformSpecificFilesCore(platform: string, files: string[]): void { + private processPlatformSpecificFilesCore(platform: string, files: string[], projectFilesConfig: IProjectFilesConfig): void { // Renames the files that have `platform` as substring and removes the files from other platform _.each(files, filePath => { - let projectFileInfo = this.$projectFilesProvider.getProjectFileInfo(filePath, platform); + let projectFileInfo = this.$projectFilesProvider.getProjectFileInfo(filePath, platform, projectFilesConfig); if (!projectFileInfo.shouldIncludeFile) { this.$fs.deleteFile(filePath); } else if (projectFileInfo.onDeviceFileName) { diff --git a/services/project-files-provider-base.ts b/services/project-files-provider-base.ts index 3e678aeb..8dfa4402 100644 --- a/services/project-files-provider-base.ts +++ b/services/project-files-provider-base.ts @@ -4,13 +4,13 @@ import { Configurations } from "../constants"; export abstract class ProjectFilesProviderBase implements IProjectFilesProvider { abstract isFileExcluded(filePath: string): boolean; - abstract mapFilePath(filePath: string, platform: string, projectData: any): string; + abstract mapFilePath(filePath: string, platform: string, projectData: any, projectFilesConfig: IProjectFilesConfig): string; constructor(private $mobileHelper: Mobile.IMobileHelper, protected $options: ICommonOptions) { } - public getPreparedFilePath(filePath: string): string { - let projectFileInfo = this.getProjectFileInfo(filePath, ""); + public getPreparedFilePath(filePath: string, projectFilesConfig?: IProjectFilesConfig): string { + let projectFileInfo = this.getProjectFileInfo(filePath, "", projectFilesConfig); return path.join(path.dirname(filePath), projectFileInfo.onDeviceFileName); } @@ -18,6 +18,7 @@ export abstract class ProjectFilesProviderBase implements IProjectFilesProvider let parsed = this.parseFile(filePath, this.$mobileHelper.platformNames, platform || ""); let basicConfigurations = [Configurations.Debug.toLowerCase(), Configurations.Release.toLowerCase()]; if (!parsed) { + let validValues = basicConfigurations.concat(projectFilesConfig && projectFilesConfig.additionalConfigurations || []), value = projectFilesConfig && projectFilesConfig.configuration || basicConfigurations[0]; parsed = this.parseFile(filePath, validValues, value); diff --git a/test/unit-tests/mobile/project-files-manager.ts b/test/unit-tests/mobile/project-files-manager.ts index 975179f9..053df82e 100644 --- a/test/unit-tests/mobile/project-files-manager.ts +++ b/test/unit-tests/mobile/project-files-manager.ts @@ -104,10 +104,18 @@ function createTestInjector(): IInjector { } async function createFiles(testInjector: IInjector, filesToCreate: string[]): Promise { - let fs = testInjector.resolve("fs"); let directoryPath = temp.mkdirSync("Project Files Manager Tests"); - _.each(filesToCreate, file => fs.writeFile(path.join(directoryPath, file), "")); + _.each(filesToCreate, file => createFile(testInjector, file, "", directoryPath)); + + return directoryPath; +} + +function createFile(testInjector: IInjector, fileToCreate: string, fileContent: string, directoryPath?: string): string { + let fs = testInjector.resolve("fs"); + directoryPath = !directoryPath ? temp.mkdirSync("Project Files Manager Tests") : directoryPath; + + fs.writeFile(path.join(directoryPath, fileToCreate), fileContent); return directoryPath; } @@ -170,7 +178,7 @@ describe("Project Files Manager Tests", () => { let files = ["test.ios.x", "test.android.x"]; let directoryPath = await createFiles(testInjector, files); - projectFilesManager.processPlatformSpecificFiles(directoryPath, "android"); + projectFilesManager.processPlatformSpecificFiles(directoryPath, "android", {}); let fs = testInjector.resolve("fs"); assert.isFalse(fs.exists(path.join(directoryPath, "test.ios.x"))); @@ -182,7 +190,7 @@ describe("Project Files Manager Tests", () => { let files = ["index.ios.html", "index1.android.html", "a.test"]; let directoryPath = await createFiles(testInjector, files); - projectFilesManager.processPlatformSpecificFiles(directoryPath, "ios"); + projectFilesManager.processPlatformSpecificFiles(directoryPath, "ios", {}); let fs = testInjector.resolve("fs"); assert.isFalse(fs.exists(path.join(directoryPath, "index1.android.html"))); @@ -191,11 +199,39 @@ describe("Project Files Manager Tests", () => { assert.isTrue(fs.exists(path.join(directoryPath, "a.test"))); }); + it("filters release specific files", async () => { + const directoryPath = createFile(testInjector, "test.debug.x", "debug"); + const releaseFileContent = "release"; + createFile(testInjector, "test.release.x", releaseFileContent, directoryPath); + + projectFilesManager.processPlatformSpecificFiles(directoryPath, "android", { configuration: "release" }); + + const fs = testInjector.resolve("fs"); + assert.isFalse(fs.exists(path.join(directoryPath, "test.debug.x"))); + assert.isTrue(fs.exists(path.join(directoryPath, "test.x"))); + assert.isFalse(fs.exists(path.join(directoryPath, "test.release.x"))); + assert.isTrue(fs.readFile(path.join(directoryPath, "test.x")).toString() === releaseFileContent); + }); + + it("filters debug specific files by default", async () => { + const directoryPath = createFile(testInjector, "test.release.x", "release"); + const debugFileContent = "debug"; + createFile(testInjector, "test.debug.x", debugFileContent, directoryPath); + + projectFilesManager.processPlatformSpecificFiles(directoryPath, "android", {}); + + const fs = testInjector.resolve("fs"); + assert.isFalse(fs.exists(path.join(directoryPath, "test.debug.x"))); + assert.isTrue(fs.exists(path.join(directoryPath, "test.x"))); + assert.isFalse(fs.exists(path.join(directoryPath, "test.release.x"))); + assert.isTrue(fs.readFile(path.join(directoryPath, "test.x")).toString() === debugFileContent); + }); + it("doesn't filter non platform specific files", async () => { let files = ["index1.js", "index2.js", "index3.js"]; let directoryPath = await createFiles(testInjector, files); - projectFilesManager.processPlatformSpecificFiles(directoryPath, "ios"); + projectFilesManager.processPlatformSpecificFiles(directoryPath, "ios", {}); let fs = testInjector.resolve("fs"); assert.isTrue(fs.exists(path.join(directoryPath, "index1.js"))); diff --git a/test/unit-tests/project-files-provider-base.ts b/test/unit-tests/project-files-provider-base.ts index 9a01cfa8..821973b0 100644 --- a/test/unit-tests/project-files-provider-base.ts +++ b/test/unit-tests/project-files-provider-base.ts @@ -42,49 +42,49 @@ describe("ProjectFilesProviderBase", () => { describe("getPreparedFilePath", () => { it("returns correct path, when fileName does not contain platforms", () => { let filePath = "/test/filePath.ts", - preparedPath = projectFilesProviderBase.getPreparedFilePath(filePath); + preparedPath = projectFilesProviderBase.getPreparedFilePath(filePath, {}); assert.deepEqual(preparedPath, expectedFilePath); }); it("returns correct path, when fileName contains android platform", () => { let filePath = "/test/filePath.android.ts", - preparedPath = projectFilesProviderBase.getPreparedFilePath(filePath); + preparedPath = projectFilesProviderBase.getPreparedFilePath(filePath, {}); assert.deepEqual(preparedPath, expectedFilePath); }); it("returns correct path, when fileName contains ios platform", () => { let filePath = "/test/filePath.iOS.ts", - preparedPath = projectFilesProviderBase.getPreparedFilePath(filePath); + preparedPath = projectFilesProviderBase.getPreparedFilePath(filePath, {}); assert.deepEqual(preparedPath, expectedFilePath); }); it("returns correct path, when fileName contains platform (case insensitive test)", () => { let filePath = "/test/filePath.AnDroId.ts", - preparedPath = projectFilesProviderBase.getPreparedFilePath(filePath); + preparedPath = projectFilesProviderBase.getPreparedFilePath(filePath, {}); assert.deepEqual(preparedPath, expectedFilePath); }); it("returns correct path, when fileName contains debug configuration", () => { let filePath = "/test/filePath.debug.ts", - preparedPath = projectFilesProviderBase.getPreparedFilePath(filePath); + preparedPath = projectFilesProviderBase.getPreparedFilePath(filePath, {}); assert.deepEqual(preparedPath, expectedFilePath); }); it("returns correct path, when fileName contains debug configuration (case insensitive test)", () => { let filePath = "/test/filePath.DebUG.ts", - preparedPath = projectFilesProviderBase.getPreparedFilePath(filePath); + preparedPath = projectFilesProviderBase.getPreparedFilePath(filePath, {}); assert.deepEqual(preparedPath, expectedFilePath); }); it("returns correct path, when fileName contains release configuration", () => { let filePath = "/test/filePath.release.ts", - preparedPath = projectFilesProviderBase.getPreparedFilePath(filePath); + preparedPath = projectFilesProviderBase.getPreparedFilePath(filePath, {}); assert.deepEqual(preparedPath, expectedFilePath); }); @@ -101,42 +101,42 @@ describe("ProjectFilesProviderBase", () => { it("process file without platforms in the name", () => { let filePath = "/test/filePath.ts", - projectFileInfo = projectFilesProviderBase.getProjectFileInfo(filePath, ""); + projectFileInfo = projectFilesProviderBase.getProjectFileInfo(filePath, "", {}); assert.deepEqual(projectFileInfo, getExpectedProjectFileInfo(filePath, true)); }); it("process file with android platform in the name", () => { let filePath = "/test/filePath.android.ts", - projectFileInfo = projectFilesProviderBase.getProjectFileInfo(filePath, "android"); + projectFileInfo = projectFilesProviderBase.getProjectFileInfo(filePath, "android", {}); assert.deepEqual(projectFileInfo, getExpectedProjectFileInfo(filePath, true)); }); it("process file with android platform in the name (case insensitive test)", () => { let filePath = "/test/filePath.AndRoID.ts", - projectFileInfo = projectFilesProviderBase.getProjectFileInfo(filePath, "android"); + projectFileInfo = projectFilesProviderBase.getProjectFileInfo(filePath, "android", {}); assert.deepEqual(projectFileInfo, getExpectedProjectFileInfo(filePath, true)); }); it("process file with iOS platform in the name", () => { let filePath = "/test/filePath.ios.ts", - projectFileInfo = projectFilesProviderBase.getProjectFileInfo(filePath, "android"); + projectFileInfo = projectFilesProviderBase.getProjectFileInfo(filePath, "android", {}); assert.deepEqual(projectFileInfo, getExpectedProjectFileInfo(filePath, false)); }); it("process file with debug configuration in the name", () => { let filePath = "/test/filePath.debug.ts", - projectFileInfo = projectFilesProviderBase.getProjectFileInfo(filePath, "android"); + projectFileInfo = projectFilesProviderBase.getProjectFileInfo(filePath, "android", {}); assert.deepEqual(projectFileInfo, getExpectedProjectFileInfo(filePath, true)); }); it("process file with release configuration in the name", () => { let filePath = "/test/filePath.release.ts", - projectFileInfo = projectFilesProviderBase.getProjectFileInfo(filePath, "android"); + projectFileInfo = projectFilesProviderBase.getProjectFileInfo(filePath, "android", {}); assert.deepEqual(projectFileInfo, getExpectedProjectFileInfo(filePath, false)); });