From 5a692f2e649c433263453024a2ef9d4c2036008d Mon Sep 17 00:00:00 2001 From: fatme Date: Wed, 26 Jun 2019 17:04:31 +0300 Subject: [PATCH 1/3] fix: fix multiple installation on device when there is native java code in some plugin When there is native java code in some plugin, CLI rebuilt the .aar file. As there is a watcher that watches the .aar file, CLI decides that there is a native change. --- lib/bootstrap.ts | 2 ++ lib/controllers/prepare-controller.ts | 11 ++++++++--- lib/declarations.d.ts | 6 ++++++ lib/services/android-plugin-build-service.ts | 4 +++- lib/services/watch-ignore-list-service.ts | 16 ++++++++++++++++ 5 files changed, 35 insertions(+), 4 deletions(-) create mode 100644 lib/services/watch-ignore-list-service.ts diff --git a/lib/bootstrap.ts b/lib/bootstrap.ts index 447d76ac0f..c66924ab9f 100644 --- a/lib/bootstrap.ts +++ b/lib/bootstrap.ts @@ -223,4 +223,6 @@ $injector.require("applePortalSessionService", "./services/apple-portal/apple-po $injector.require("applePortalCookieService", "./services/apple-portal/apple-portal-cookie-service"); $injector.require("applePortalApplicationService", "./services/apple-portal/apple-portal-application-service"); +$injector.require("watchIgnoreListService", "./services/watch-ignore-list-service"); + $injector.requirePublicClass("initializeService", "./services/initialize-service"); diff --git a/lib/controllers/prepare-controller.ts b/lib/controllers/prepare-controller.ts index 03febd68ef..3598f6da46 100644 --- a/lib/controllers/prepare-controller.ts +++ b/lib/controllers/prepare-controller.ts @@ -25,7 +25,8 @@ export class PrepareController extends EventEmitter { private $prepareNativePlatformService: IPrepareNativePlatformService, private $projectChangesService: IProjectChangesService, private $projectDataService: IProjectDataService, - private $webpackCompilerService: IWebpackCompilerService + private $webpackCompilerService: IWebpackCompilerService, + private $watchIgnoreListService: IWatchIgnoreListService ) { super(); } @performanceLog() @@ -131,8 +132,12 @@ export class PrepareController extends EventEmitter { const watcher = choki.watch(patterns, watcherOptions) .on("all", async (event: string, filePath: string) => { filePath = path.join(projectData.projectDir, filePath); - this.$logger.trace(`Chokidar raised event ${event} for ${filePath}.`); - this.emitPrepareEvent({ files: [], hasOnlyHotUpdateFiles: false, hmrData: null, hasNativeChanges: true, platform: platformData.platformNameLowerCase }); + if (this.$watchIgnoreListService.isFileInIgnoreList(filePath)) { + this.$watchIgnoreListService.removeFileFromIgnoreList(filePath); + } else { + this.$logger.info(`Chokidar raised event ${event} for ${filePath}.`); + this.emitPrepareEvent({ files: [], hasOnlyHotUpdateFiles: false, hmrData: null, hasNativeChanges: true, platform: platformData.platformNameLowerCase }); + } }); this.watchersData[projectData.projectDir][platformData.platformNameLowerCase].nativeFilesWatcher = watcher; diff --git a/lib/declarations.d.ts b/lib/declarations.d.ts index 7c11063614..eed7ccdcf7 100644 --- a/lib/declarations.d.ts +++ b/lib/declarations.d.ts @@ -1049,4 +1049,10 @@ interface IPlatformCommandHelper { getAvailablePlatforms(projectData: IProjectData): string[]; getPreparedPlatforms(projectData: IProjectData): string[]; getCurrentPlatformVersion(platform: string, projectData: IProjectData): string; +} + +interface IWatchIgnoreListService { + addFileToIgnoreList(filePath: string): void; + removeFileFromIgnoreList(filePath: string): void; + isFileInIgnoreList(filePath: string): boolean; } \ No newline at end of file diff --git a/lib/services/android-plugin-build-service.ts b/lib/services/android-plugin-build-service.ts index 64ea547406..88f935cd65 100644 --- a/lib/services/android-plugin-build-service.ts +++ b/lib/services/android-plugin-build-service.ts @@ -20,7 +20,8 @@ export class AndroidPluginBuildService implements IAndroidPluginBuildService { private $errors: IErrors, private $filesHashService: IFilesHashService, public $hooksService: IHooksService, - private $injector: IInjector + private $injector: IInjector, + private $watchIgnoreListService: IWatchIgnoreListService ) { } private static MANIFEST_ROOT = { @@ -189,6 +190,7 @@ export class AndroidPluginBuildService implements IAndroidPluginBuildService { this.copySourceSetDirectories(androidSourceDirectories, pluginTempMainSrcDir); await this.setupGradle(pluginTempDir, options.platformsAndroidDirPath, options.projectDir); await this.buildPlugin({ pluginDir: pluginTempDir, pluginName: options.pluginName }); + this.$watchIgnoreListService.addFileToIgnoreList(path.join(options.aarOutputDir, `${shortPluginName}.aar`)); this.copyAar(shortPluginName, pluginTempDir, options.aarOutputDir); this.writePluginHashInfo(pluginSourceFileHashesInfo, pluginTempDir); } diff --git a/lib/services/watch-ignore-list-service.ts b/lib/services/watch-ignore-list-service.ts new file mode 100644 index 0000000000..aa69c75e98 --- /dev/null +++ b/lib/services/watch-ignore-list-service.ts @@ -0,0 +1,16 @@ +export class WatchIgnoreListService implements IWatchIgnoreListService { + private ignoreMap: IDictionary = {}; + + public addFileToIgnoreList(filePath: string): void { + this.ignoreMap[filePath] = true; + } + + public removeFileFromIgnoreList(filePath: string): void { + this.ignoreMap[filePath] = false; + } + + public isFileInIgnoreList(filePath: string): boolean { + return !!this.ignoreMap[filePath]; + } +} +$injector.register("watchIgnoreListService", WatchIgnoreListService); From a207a06944e7ecd060eeca8ad22ba5bd2bf09b0c Mon Sep 17 00:00:00 2001 From: fatme Date: Wed, 26 Jun 2019 17:05:56 +0300 Subject: [PATCH 2/3] fix: make rebuiltInformation context specific so the actions cannot affect each other --- lib/controllers/run-controller.ts | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/lib/controllers/run-controller.ts b/lib/controllers/run-controller.ts index d85e2f5df2..1351084f8b 100644 --- a/lib/controllers/run-controller.ts +++ b/lib/controllers/run-controller.ts @@ -4,8 +4,6 @@ import { cache, performanceLog } from "../common/decorators"; import { EventEmitter } from "events"; export class RunController extends EventEmitter implements IRunController { - private rebuiltInformation: IDictionary<{ packageFilePath: string, platform: string, isEmulator: boolean }> = { }; - constructor( protected $analyticsService: IAnalyticsService, private $buildController: IBuildController, @@ -246,7 +244,7 @@ export class RunController extends EventEmitter implements IRunController { } private async syncInitialDataOnDevices(projectData: IProjectData, liveSyncInfo: ILiveSyncInfo, deviceDescriptors: ILiveSyncDeviceDescriptor[]): Promise { - this.rebuiltInformation = {}; + const rebuiltInformation: IDictionary<{ packageFilePath: string, platform: string, isEmulator: boolean }> = { }; const deviceAction = async (device: Mobile.IDevice) => { const deviceDescriptor = _.find(deviceDescriptors, dd => dd.identifier === device.deviceInfo.identifier); @@ -267,14 +265,14 @@ export class RunController extends EventEmitter implements IRunController { // Case where we have three devices attached, a change that requires build is found, // we'll rebuild the app only for the first device, but we should install new package on all three devices. - if (this.rebuiltInformation[platformData.platformNameLowerCase] && (this.$mobileHelper.isAndroidPlatform(platformData.platformNameLowerCase) || this.rebuiltInformation[platformData.platformNameLowerCase].isEmulator === device.isEmulator)) { - packageFilePath = this.rebuiltInformation[platformData.platformNameLowerCase].packageFilePath; + if (rebuiltInformation[platformData.platformNameLowerCase] && (this.$mobileHelper.isAndroidPlatform(platformData.platformNameLowerCase) || rebuiltInformation[platformData.platformNameLowerCase].isEmulator === device.isEmulator)) { + packageFilePath = rebuiltInformation[platformData.platformNameLowerCase].packageFilePath; await this.$deviceInstallAppService.installOnDevice(device, buildData, packageFilePath); } else { const shouldBuild = prepareResultData.hasNativeChanges || await this.$buildController.shouldBuild(buildData); if (shouldBuild) { packageFilePath = await deviceDescriptor.buildAction(); - this.rebuiltInformation[platformData.platformNameLowerCase] = { isEmulator: device.isEmulator, platform: platformData.platformNameLowerCase, packageFilePath }; + rebuiltInformation[platformData.platformNameLowerCase] = { isEmulator: device.isEmulator, platform: platformData.platformNameLowerCase, packageFilePath }; } else { await this.$analyticsService.trackEventActionInGoogleAnalytics({ action: TrackActionNames.LiveSync, @@ -315,7 +313,7 @@ export class RunController extends EventEmitter implements IRunController { } private async syncChangedDataOnDevices(data: IFilesChangeEventData, projectData: IProjectData, liveSyncInfo: ILiveSyncInfo, deviceDescriptors: ILiveSyncDeviceDescriptor[]): Promise { - this.rebuiltInformation = {}; + const rebuiltInformation: IDictionary<{ packageFilePath: string, platform: string, isEmulator: boolean }> = { }; const deviceAction = async (device: Mobile.IDevice) => { const deviceDescriptor = _.find(deviceDescriptors, dd => dd.identifier === device.deviceInfo.identifier); @@ -343,14 +341,14 @@ export class RunController extends EventEmitter implements IRunController { const deviceAppData = await platformLiveSyncService.getAppData(_.merge({ device, watch: true }, watchInfo)); if (data.hasNativeChanges) { - const rebuiltInfo = this.rebuiltInformation[platformData.platformNameLowerCase] && (this.$mobileHelper.isAndroidPlatform(platformData.platformNameLowerCase) || this.rebuiltInformation[platformData.platformNameLowerCase].isEmulator === device.isEmulator); + const rebuiltInfo = rebuiltInformation[platformData.platformNameLowerCase] && (this.$mobileHelper.isAndroidPlatform(platformData.platformNameLowerCase) || rebuiltInformation[platformData.platformNameLowerCase].isEmulator === device.isEmulator); if (!rebuiltInfo) { await this.$prepareNativePlatformService.prepareNativePlatform(platformData, projectData, prepareData); await deviceDescriptor.buildAction(); - this.rebuiltInformation[platformData.platformNameLowerCase] = { isEmulator: device.isEmulator, platform: platformData.platformNameLowerCase, packageFilePath: null }; + rebuiltInformation[platformData.platformNameLowerCase] = { isEmulator: device.isEmulator, platform: platformData.platformNameLowerCase, packageFilePath: null }; } - await this.$deviceInstallAppService.installOnDevice(device, deviceDescriptor.buildData, this.rebuiltInformation[platformData.platformNameLowerCase].packageFilePath); + await this.$deviceInstallAppService.installOnDevice(device, deviceDescriptor.buildData, rebuiltInformation[platformData.platformNameLowerCase].packageFilePath); await platformLiveSyncService.syncAfterInstall(device, watchInfo); await platformLiveSyncService.restartApplication(projectData, { deviceAppData, modifiedFilesData: [], isFullSync: false, useHotModuleReload: liveSyncInfo.useHotModuleReload }); } else { From be5af8390226b8a2b4e8dd15d68f49007236a28e Mon Sep 17 00:00:00 2001 From: fatme Date: Wed, 26 Jun 2019 17:36:57 +0300 Subject: [PATCH 3/3] chore: fix unit tests --- test/controllers/prepare-controller.ts | 5 +++++ test/services/android-plugin-build-service.ts | 4 ++++ 2 files changed, 9 insertions(+) diff --git a/test/controllers/prepare-controller.ts b/test/controllers/prepare-controller.ts index 4f056804ed..ef0b4a0fd0 100644 --- a/test/controllers/prepare-controller.ts +++ b/test/controllers/prepare-controller.ts @@ -49,6 +49,11 @@ function createTestInjector(data: { hasNativeChanges: boolean }): IInjector { getProductionDependencies: () => ([]) }); + injector.register("watchIgnoreListService", { + addFileToIgnoreList: () => ({}), + isFileInIgnoreList: () => false + }); + const prepareController: PrepareController = injector.resolve("prepareController"); prepareController.emit = (eventName: string, eventData: any) => { emittedEventNames.push(eventName); diff --git a/test/services/android-plugin-build-service.ts b/test/services/android-plugin-build-service.ts index 962a0cdcd0..b920e2ab70 100644 --- a/test/services/android-plugin-build-service.ts +++ b/test/services/android-plugin-build-service.ts @@ -75,6 +75,10 @@ describe('androidPluginBuildService', () => { hasChangesInShasums: (oldHashes: IStringDictionary, newHashes: IStringDictionary): boolean => !!options.hasChangesInShasums }); + testInjector.register("watchIgnoreListService", { + addFileToIgnoreList: () => ({}) + }); + fs = testInjector.resolve("fs"); androidBuildPluginService = testInjector.resolve(AndroidPluginBuildService); }