diff --git a/lib/common/services/commands-service.ts b/lib/common/services/commands-service.ts index 8cb47a8e9f..d441a2959a 100644 --- a/lib/common/services/commands-service.ts +++ b/lib/common/services/commands-service.ts @@ -27,7 +27,16 @@ export class CommandsService implements ICommandsService { private $staticConfig: Config.IStaticConfig, private $helpService: IHelpService, private $extensibilityService: IExtensibilityService, - private $optionsTracker: IOptionsTracker) { + private $optionsTracker: IOptionsTracker, + private $projectDataService: IProjectDataService) { + let projectData = null; + try { + projectData = this.$projectDataService.getProjectData(); + } catch (err) { + this.$logger.trace(`Error while trying to get project data. More info: ${err}`); + } + + this.$options.setupOptions(projectData); } public allCommands(opts: { includeDevCommands: boolean }): string[] { diff --git a/lib/declarations.d.ts b/lib/declarations.d.ts index 0b20e2139f..e7c4a4456d 100644 --- a/lib/declarations.d.ts +++ b/lib/declarations.d.ts @@ -568,6 +568,7 @@ interface IOptions extends IRelease, IDeviceIdentifier, IJustLaunch, IAvd, IAvai link: boolean; analyticsLogFile: string; performance: Object; + setupOptions(projectData: IProjectData): void; } interface IEnvOptions { diff --git a/lib/definitions/project.d.ts b/lib/definitions/project.d.ts index 4af5382abc..693d433772 100644 --- a/lib/definitions/project.d.ts +++ b/lib/definitions/project.d.ts @@ -74,6 +74,7 @@ interface INsConfig { appPath?: string; appResourcesPath?: string; shared?: boolean; + useLegacyWorkflow?: boolean; } interface IProjectData extends ICreateProjectData { @@ -99,6 +100,11 @@ interface IProjectData extends ICreateProjectData { */ isShared: boolean; + /** + * Defines if the project has hmr enabled by default + */ + useLegacyWorkflow: boolean; + /** * Initializes project data with the given project directory. If none supplied defaults to --path option or cwd. * @param {string} projectDir Project root directory. diff --git a/lib/options.ts b/lib/options.ts index 9c1000f297..79931e43e7 100644 --- a/lib/options.ts +++ b/lib/options.ts @@ -21,6 +21,35 @@ export class Options { public options: IDictionary; + public setupOptions(projectData: IProjectData): void { + if (this.argv.release && this.argv.hmr) { + this.$errors.failWithoutHelp("The options --release and --hmr cannot be used simultaneously."); + } + + // HACK: temporary solution for 5.3.0 release (until the webpack only feature) + const parsed = require("yargs-parser")(process.argv.slice(2), { 'boolean-negation': false }); + const noBundle = parsed && (parsed.bundle === false || parsed.bundle === 'false'); + if (noBundle && this.argv.hmr) { + this.$errors.failWithoutHelp("The options --no-bundle and --hmr cannot be used simultaneously."); + } + + if (projectData && projectData.useLegacyWorkflow === false) { + this.argv.bundle = this.argv.bundle !== undefined ? this.argv.bundle : "webpack"; + this.argv.hmr = !this.argv.release; + } + + // --no-hmr -> hmr: false or --hmr false -> hmr: 'false' + const noHmr = parsed && (parsed.hmr === false || parsed.hmr === 'false'); + if (noHmr) { + this.argv.hmr = false; + } + + if (noBundle) { + this.argv.bundle = undefined; + this.argv.hmr = false; + } + } + constructor(private $errors: IErrors, private $staticConfig: Config.IStaticConfig, private $settingsService: ISettingsService) { diff --git a/lib/project-data.ts b/lib/project-data.ts index 2fe31b0f2f..a139e78eee 100644 --- a/lib/project-data.ts +++ b/lib/project-data.ts @@ -61,6 +61,7 @@ export class ProjectData implements IProjectData { public buildXcconfigPath: string; public podfilePath: string; public isShared: boolean; + public useLegacyWorkflow: boolean; constructor(private $fs: IFileSystem, private $errors: IErrors, @@ -135,6 +136,7 @@ export class ProjectData implements IProjectData { this.buildXcconfigPath = path.join(this.appResourcesDirectoryPath, this.$devicePlatformsConstants.iOS, constants.BUILD_XCCONFIG_FILE_NAME); this.podfilePath = path.join(this.appResourcesDirectoryPath, this.$devicePlatformsConstants.iOS, constants.PODFILE_NAME); this.isShared = !!(this.nsConfig && this.nsConfig.shared); + this.useLegacyWorkflow = this.nsConfig && this.nsConfig.useLegacyWorkflow; return; } diff --git a/test/options.ts b/test/options.ts index cfa225e2f7..1727991746 100644 --- a/test/options.ts +++ b/test/options.ts @@ -261,6 +261,113 @@ describe("options", () => { }); }); + + describe("setupOptions", () => { + const testCases = [ + { + name: "no options are provided", + args: [], + data: [ + { useLegacyWorkflow: undefined, expectedHmr: false, expectedBundle: false }, + { useLegacyWorkflow: false, expectedHmr: true, expectedBundle: true }, + { useLegacyWorkflow: true, expectedHmr: false, expectedBundle: false } + ] + }, + { + name: " --hmr is provided", + args: ["--hmr"], + data: [ + { useLegacyWorkflow: undefined, expectedHmr: true, expectedBundle: true }, + { useLegacyWorkflow: false, expectedHmr: true, expectedBundle: true }, + { useLegacyWorkflow: true, expectedHmr: true, expectedBundle: true } + ] + }, + { + name: " --no-hmr is provided", + args: ["--no-hmr"], + data: [ + { useLegacyWorkflow: undefined, expectedHmr: false, expectedBundle: false }, + { useLegacyWorkflow: false, expectedHmr: false, expectedBundle: true }, + { useLegacyWorkflow: true, expectedHmr: false, expectedBundle: false } + ] + }, + { + name: " --bundle is provided", + args: ["--bundle"], + data: [ + { useLegacyWorkflow: undefined, expectedHmr: false, expectedBundle: true }, + { useLegacyWorkflow: false, expectedHmr: true, expectedBundle: true }, + { useLegacyWorkflow: true, expectedHmr: false, expectedBundle: true } + ] + }, + { + name: " --no-bundle is provided", + args: ["--no-bundle"], + data: [ + { useLegacyWorkflow: undefined, expectedHmr: false, expectedBundle: false }, + { useLegacyWorkflow: false, expectedHmr: false, expectedBundle: false }, + { useLegacyWorkflow: true, expectedHmr: false, expectedBundle: false } + ] + }, + { + name: " --release is provided", + args: ["--release"], + data: [ + { useLegacyWorkflow: undefined, expectedHmr: false, expectedBundle: false }, + { useLegacyWorkflow: false, expectedHmr: false, expectedBundle: true }, + { useLegacyWorkflow: true, expectedHmr: false, expectedBundle: false } + ] + } + ]; + + _.each([undefined, false, true], useLegacyWorkflow => { + _.each(testCases, testCase => { + it(`should pass correctly when ${testCase.name} and useLegacyWorkflow is ${useLegacyWorkflow}`, () => { + (testCase.args || []).forEach(arg => process.argv.push(arg)); + + const options = createOptions(testInjector); + const projectData = { useLegacyWorkflow }; + options.setupOptions(projectData); + + (testCase.args || []).forEach(arg => process.argv.pop()); + + const data = testCase.data.find(item => item.useLegacyWorkflow === useLegacyWorkflow); + + assert.equal(!!options.argv.hmr, !!data.expectedHmr); + assert.equal(!!options.argv.bundle, !!data.expectedBundle); + }); + }); + }); + + const testCasesExpectingToThrow = [ + { + name: "--release --hmr", + args: ["--release", "--hmr"], + expectedError: "The options --release and --hmr cannot be used simultaneously." + }, + { + name: "--no-bundle --hmr", + args: ["--no-bundle", "--hmr"], + expectedError: "The options --no-bundle and --hmr cannot be used simultaneously." + } + ]; + + _.each(testCasesExpectingToThrow, testCase => { + it(`should fail when ${testCase.name}`, () => { + let actualError = null; + const errors = testInjector.resolve("errors"); + errors.failWithoutHelp = (error: string) => actualError = error; + (testCase.args || []).forEach(arg => process.argv.push(arg)); + + const options = createOptions(testInjector); + options.setupOptions(null); + + (testCase.args || []).forEach(arg => process.argv.pop()); + + assert.deepEqual(actualError, testCase.expectedError); + }); + }); + }); }); function createOptionsWithProfileDir(defaultProfileDir?: string): IOptions { diff --git a/test/stubs.ts b/test/stubs.ts index 45c04dd3c9..c98362dda3 100644 --- a/test/stubs.ts +++ b/test/stubs.ts @@ -331,6 +331,7 @@ export class ProjectDataStub implements IProjectData { public buildXcconfigPath: string; public podfilePath: string; public isShared: boolean; + public useLegacyWorkflow: boolean; public initializeProjectData(projectDir?: string): void { this.projectDir = this.projectDir || projectDir;