From 12e8f6aa3f2d3b2b7b39cc9deec7341e9252c10f Mon Sep 17 00:00:00 2001 From: fatme Date: Tue, 25 Jun 2019 17:16:31 +0300 Subject: [PATCH 1/3] fix: fix native change during livesync Currently when a native file is changed during livesync on android, NativeScript CLI doesn't show the "Successfully synced application" message. This is due to the reason that NativeScript CLI tries to transfer native file on device (for example AndroidManifest.xml). After timeout of 30seconds, the socket on android device throws "Socket connection timeout" error but CLI doesn't show it as the parsing of received errors is not correct. This PR fixes the followings: * the behavior when native file is changed during liveSync * the parsing of errors during livesync * stops livesync process when an error occurs during livesync --- lib/controllers/run-controller.ts | 109 ++++++++---------- lib/definitions/livesync.d.ts | 1 + .../platform-livesync-service-base.ts | 2 +- 3 files changed, 49 insertions(+), 63 deletions(-) diff --git a/lib/controllers/run-controller.ts b/lib/controllers/run-controller.ts index fad79b8705..7d2f67e128 100644 --- a/lib/controllers/run-controller.ts +++ b/lib/controllers/run-controller.ts @@ -124,6 +124,16 @@ export class RunController extends EventEmitter implements IRunController { await this.refreshApplicationWithDebug(projectData, liveSyncResultInfo, filesChangeEventData, deviceDescriptor, settings) : await this.refreshApplicationWithoutDebug(projectData, liveSyncResultInfo, filesChangeEventData, deviceDescriptor, settings); + const device = liveSyncResultInfo.deviceAppData.device; + + this.emitCore(RunOnDeviceEvents.runOnDeviceExecuted, { + projectDir: projectData.projectDir, + deviceIdentifier: device.deviceInfo.identifier, + applicationIdentifier: projectData.projectIdentifiers[device.deviceInfo.platform.toLowerCase()], + syncedFiles: liveSyncResultInfo.modifiedFilesData.map(m => m.getLocalPath()), + isFullSync: liveSyncResultInfo.isFullSync + }); + return result; } @@ -282,14 +292,6 @@ export class RunController extends EventEmitter implements IRunController { await this.refreshApplication(projectData, liveSyncResultInfo, null, deviceDescriptor); - this.emitCore(RunOnDeviceEvents.runOnDeviceExecuted, { - projectDir: projectData.projectDir, - deviceIdentifier: device.deviceInfo.identifier, - applicationIdentifier: projectData.projectIdentifiers[device.deviceInfo.platform.toLowerCase()], - syncedFiles: liveSyncResultInfo.modifiedFilesData.map(m => m.getLocalPath()), - isFullSync: liveSyncResultInfo.isFullSync - }); - this.$logger.info(`Successfully synced application ${liveSyncResultInfo.deviceAppData.appIdentifier} on device ${liveSyncResultInfo.deviceAppData.device.deviceInfo.identifier}.`); this.emitCore(RunOnDeviceEvents.runOnDeviceStarted, { @@ -327,22 +329,6 @@ export class RunController extends EventEmitter implements IRunController { }); try { - if (data.hasNativeChanges) { - const rebuiltInfo = this.rebuiltInformation[platformData.platformNameLowerCase] && (this.$mobileHelper.isAndroidPlatform(platformData.platformNameLowerCase) || this.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 }; - } - - await this.$deviceInstallAppService.installOnDevice(device, deviceDescriptor.buildData, this.rebuiltInformation[platformData.platformNameLowerCase].packageFilePath); - } - - const isInHMRMode = liveSyncInfo.useHotModuleReload && data.hmrData && data.hmrData.hash; - if (isInHMRMode) { - this.$hmrStatusService.watchHmrStatus(device.deviceInfo.identifier, data.hmrData.hash); - } - const platformLiveSyncService = this.$liveSyncServiceResolver.resolveLiveSyncService(device.deviceInfo.platform); const watchInfo = { liveSyncDeviceData: deviceDescriptor, @@ -355,53 +341,52 @@ export class RunController extends EventEmitter implements IRunController { force: liveSyncInfo.force, connectTimeout: 1000 }; - let liveSyncResultInfo = await platformLiveSyncService.liveSyncWatchAction(device, watchInfo); + const deviceAppData = await platformLiveSyncService.getAppData(_.merge({ device, watch: true }, watchInfo)); - await this.refreshApplication(projectData, liveSyncResultInfo, data, deviceDescriptor); + if (data.hasNativeChanges) { + const rebuiltInfo = this.rebuiltInformation[platformData.platformNameLowerCase] && (this.$mobileHelper.isAndroidPlatform(platformData.platformNameLowerCase) || this.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 }; + } - this.emitCore(RunOnDeviceEvents.runOnDeviceExecuted, { - projectDir: projectData.projectDir, - deviceIdentifier: device.deviceInfo.identifier, - applicationIdentifier: projectData.projectIdentifiers[device.deviceInfo.platform.toLowerCase()], - syncedFiles: liveSyncResultInfo.modifiedFilesData.map(m => m.getLocalPath()), - isFullSync: liveSyncResultInfo.isFullSync - }); + await this.$deviceInstallAppService.installOnDevice(device, deviceDescriptor.buildData, this.rebuiltInformation[platformData.platformNameLowerCase].packageFilePath); + await platformLiveSyncService.restartApplication(projectData, { deviceAppData, modifiedFilesData: [], isFullSync: false, useHotModuleReload: liveSyncInfo.useHotModuleReload }); + } else { + const isInHMRMode = liveSyncInfo.useHotModuleReload && data.hmrData && data.hmrData.hash; + if (isInHMRMode) { + this.$hmrStatusService.watchHmrStatus(device.deviceInfo.identifier, data.hmrData.hash); + } - if (!liveSyncResultInfo.didRecover && isInHMRMode) { - const status = await this.$hmrStatusService.getHmrStatus(device.deviceInfo.identifier, data.hmrData.hash); - if (status === HmrConstants.HMR_ERROR_STATUS) { - watchInfo.filesToSync = data.hmrData.fallbackFiles; - liveSyncResultInfo = await platformLiveSyncService.liveSyncWatchAction(device, watchInfo); - // We want to force a restart of the application. - liveSyncResultInfo.isFullSync = true; - await this.refreshApplication(projectData, liveSyncResultInfo, data, deviceDescriptor); - - this.emitCore(RunOnDeviceEvents.runOnDeviceExecuted, { - projectDir: projectData.projectDir, - deviceIdentifier: device.deviceInfo.identifier, - applicationIdentifier: projectData.projectIdentifiers[device.deviceInfo.platform.toLowerCase()], - syncedFiles: liveSyncResultInfo.modifiedFilesData.map(m => m.getLocalPath()), - isFullSync: liveSyncResultInfo.isFullSync - }); + let liveSyncResultInfo = await platformLiveSyncService.liveSyncWatchAction(device, watchInfo); + + if (!liveSyncResultInfo.didRecover && isInHMRMode) { + const status = await this.$hmrStatusService.getHmrStatus(device.deviceInfo.identifier, data.hmrData.hash); + if (status === HmrConstants.HMR_ERROR_STATUS) { + watchInfo.filesToSync = data.hmrData.fallbackFiles; + liveSyncResultInfo = await platformLiveSyncService.liveSyncWatchAction(device, watchInfo); + // We want to force a restart of the application. + liveSyncResultInfo.isFullSync = true; + await this.refreshApplication(projectData, liveSyncResultInfo, data, deviceDescriptor); + } } + + await this.refreshApplication(projectData, liveSyncResultInfo, data, deviceDescriptor); } - this.$logger.info(`Successfully synced application ${liveSyncResultInfo.deviceAppData.appIdentifier} on device ${liveSyncResultInfo.deviceAppData.device.deviceInfo.identifier}.`); + this.$logger.info(`Successfully synced application ${deviceAppData.appIdentifier} on device ${device.deviceInfo.identifier}.`); } catch (err) { - const allErrors = (err).allErrors; + this.$logger.warn(`Unable to apply changes for device: ${device.deviceInfo.identifier}. Error is: ${err && err.message}.`); - if (allErrors && _.isArray(allErrors)) { - for (const deviceError of allErrors) { - this.$logger.warn(`Unable to apply changes for device: ${deviceError.deviceIdentifier}. Error is: ${deviceError.message}.`); + this.emitCore(RunOnDeviceEvents.runOnDeviceError, { + projectDir: projectData.projectDir, + deviceIdentifier: device.deviceInfo.identifier, + applicationIdentifier: projectData.projectIdentifiers[device.deviceInfo.platform.toLowerCase()], + error: err, + }); - this.emitCore(RunOnDeviceEvents.runOnDeviceError, { - projectDir: projectData.projectDir, - deviceIdentifier: device.deviceInfo.identifier, - applicationIdentifier: projectData.projectIdentifiers[device.deviceInfo.platform.toLowerCase()], - error: err, - }); - } - } + await this.stop({ projectDir: projectData.projectDir, deviceIdentifiers: [device.deviceInfo.identifier] }); } }; diff --git a/lib/definitions/livesync.d.ts b/lib/definitions/livesync.d.ts index b224149091..fa23ea7e5c 100644 --- a/lib/definitions/livesync.d.ts +++ b/lib/definitions/livesync.d.ts @@ -250,6 +250,7 @@ declare global { restartApplication(projectData: IProjectData, liveSyncInfo: ILiveSyncResultInfo): Promise; shouldRestart(projectData: IProjectData, liveSyncInfo: ILiveSyncResultInfo): Promise; getDeviceLiveSyncService(device: Mobile.IDevice, projectData: IProjectData): INativeScriptDeviceLiveSyncService; + getAppData(syncInfo: IFullSyncInfo): Promise; } interface IRestartApplicationInfo { diff --git a/lib/services/livesync/platform-livesync-service-base.ts b/lib/services/livesync/platform-livesync-service-base.ts index 2534daff0d..9be0e04924 100644 --- a/lib/services/livesync/platform-livesync-service-base.ts +++ b/lib/services/livesync/platform-livesync-service-base.ts @@ -141,7 +141,7 @@ export abstract class PlatformLiveSyncServiceBase { return transferredFiles; } - protected async getAppData(syncInfo: IFullSyncInfo): Promise { + public async getAppData(syncInfo: IFullSyncInfo): Promise { const platform = syncInfo.device.deviceInfo.platform.toLowerCase(); const appIdentifier = syncInfo.projectData.projectIdentifiers[platform]; const deviceProjectRootOptions: IDeviceProjectRootOptions = _.assign({ appIdentifier }, syncInfo); From e136ac96c7967031edbcce663f71479be8a413af Mon Sep 17 00:00:00 2001 From: fatme Date: Wed, 26 Jun 2019 12:26:36 +0300 Subject: [PATCH 2/3] fix: fix native change during livesync on iOS device We need to execute full sync after install on iOS device in order to create LiveSync folder on device. --- lib/controllers/run-controller.ts | 1 + lib/definitions/livesync.d.ts | 1 + lib/services/livesync/ios-livesync-service.ts | 9 +++------ lib/services/livesync/platform-livesync-service-base.ts | 4 ++++ 4 files changed, 9 insertions(+), 6 deletions(-) diff --git a/lib/controllers/run-controller.ts b/lib/controllers/run-controller.ts index 7d2f67e128..744e17c6e6 100644 --- a/lib/controllers/run-controller.ts +++ b/lib/controllers/run-controller.ts @@ -352,6 +352,7 @@ export class RunController extends EventEmitter implements IRunController { } await this.$deviceInstallAppService.installOnDevice(device, deviceDescriptor.buildData, this.rebuiltInformation[platformData.platformNameLowerCase].packageFilePath); + await platformLiveSyncService.syncAfterInstall(device, watchInfo); await platformLiveSyncService.restartApplication(projectData, { deviceAppData, modifiedFilesData: [], isFullSync: false, useHotModuleReload: liveSyncInfo.useHotModuleReload }); } else { const isInHMRMode = liveSyncInfo.useHotModuleReload && data.hmrData && data.hmrData.hash; diff --git a/lib/definitions/livesync.d.ts b/lib/definitions/livesync.d.ts index fa23ea7e5c..bd24b2b410 100644 --- a/lib/definitions/livesync.d.ts +++ b/lib/definitions/livesync.d.ts @@ -251,6 +251,7 @@ declare global { shouldRestart(projectData: IProjectData, liveSyncInfo: ILiveSyncResultInfo): Promise; getDeviceLiveSyncService(device: Mobile.IDevice, projectData: IProjectData): INativeScriptDeviceLiveSyncService; getAppData(syncInfo: IFullSyncInfo): Promise; + syncAfterInstall(device: Mobile.IDevice, liveSyncInfo: ILiveSyncWatchInfo): Promise; } interface IRestartApplicationInfo { diff --git a/lib/services/livesync/ios-livesync-service.ts b/lib/services/livesync/ios-livesync-service.ts index 70928ea873..df2d34e063 100644 --- a/lib/services/livesync/ios-livesync-service.ts +++ b/lib/services/livesync/ios-livesync-service.ts @@ -55,19 +55,16 @@ export class IOSLiveSyncService extends PlatformLiveSyncServiceBase implements I }; } - @performanceLog() - public liveSyncWatchAction(device: Mobile.IDevice, liveSyncInfo: ILiveSyncWatchInfo): Promise { - if (liveSyncInfo.isReinstalled) { + public async syncAfterInstall(device: Mobile.IDevice, liveSyncInfo: ILiveSyncWatchInfo): Promise { + if (!device.isEmulator) { // In this case we should execute fullsync because iOS Runtime requires the full content of app dir to be extracted in the root of sync dir. - return this.fullSync({ + await this.fullSync({ projectData: liveSyncInfo.projectData, device, liveSyncDeviceData: liveSyncInfo.liveSyncDeviceData, watch: true, useHotModuleReload: liveSyncInfo.useHotModuleReload }); - } else { - return super.liveSyncWatchAction(device, liveSyncInfo); } } diff --git a/lib/services/livesync/platform-livesync-service-base.ts b/lib/services/livesync/platform-livesync-service-base.ts index 9be0e04924..4471ad638f 100644 --- a/lib/services/livesync/platform-livesync-service-base.ts +++ b/lib/services/livesync/platform-livesync-service-base.ts @@ -2,6 +2,7 @@ import * as path from "path"; import * as util from "util"; import { APP_FOLDER_NAME } from "../../constants"; import { getHash } from "../../common/helpers"; +import { performanceLog } from "../../common/decorators"; export abstract class PlatformLiveSyncServiceBase { private _deviceLiveSyncServicesCache: IDictionary = {}; @@ -32,6 +33,8 @@ export abstract class PlatformLiveSyncServiceBase { return shouldRestart; } + public async syncAfterInstall(device: Mobile.IDevice, liveSyncInfo: ILiveSyncWatchInfo): Promise { /* intentionally left blank */ } + public async restartApplication(projectData: IProjectData, liveSyncInfo: ILiveSyncResultInfo): Promise { const deviceLiveSyncService = this.getDeviceLiveSyncService(liveSyncInfo.deviceAppData.device, projectData); this.$logger.info(`Restarting application on device ${liveSyncInfo.deviceAppData.device.deviceInfo.identifier}...`); @@ -72,6 +75,7 @@ export abstract class PlatformLiveSyncServiceBase { }; } + @performanceLog() public async liveSyncWatchAction(device: Mobile.IDevice, liveSyncInfo: ILiveSyncWatchInfo): Promise { const projectData = liveSyncInfo.projectData; const deviceLiveSyncService = this.getDeviceLiveSyncService(device, projectData); From 7441082946b24619673a8dc36634b426ef823257 Mon Sep 17 00:00:00 2001 From: fatme Date: Wed, 26 Jun 2019 13:53:02 +0300 Subject: [PATCH 3/3] fix: remove reinstalled option --- lib/controllers/run-controller.ts | 1 - lib/definitions/livesync.d.ts | 1 - lib/services/livesync/platform-livesync-service-base.ts | 2 +- 3 files changed, 1 insertion(+), 3 deletions(-) diff --git a/lib/controllers/run-controller.ts b/lib/controllers/run-controller.ts index 744e17c6e6..d85e2f5df2 100644 --- a/lib/controllers/run-controller.ts +++ b/lib/controllers/run-controller.ts @@ -335,7 +335,6 @@ export class RunController extends EventEmitter implements IRunController { projectData, filesToRemove: [], filesToSync: data.files, - isReinstalled: false, hmrData: data.hmrData, useHotModuleReload: liveSyncInfo.useHotModuleReload, force: liveSyncInfo.force, diff --git a/lib/definitions/livesync.d.ts b/lib/definitions/livesync.d.ts index bd24b2b410..b692609ccb 100644 --- a/lib/definitions/livesync.d.ts +++ b/lib/definitions/livesync.d.ts @@ -210,7 +210,6 @@ declare global { interface ILiveSyncWatchInfo extends IProjectDataComposition, IHasUseHotModuleReloadOption, IConnectTimeoutOption { filesToRemove: string[]; filesToSync: string[]; - isReinstalled: boolean; liveSyncDeviceData: ILiveSyncDeviceDescriptor; hmrData: IPlatformHmrData; force?: boolean; diff --git a/lib/services/livesync/platform-livesync-service-base.ts b/lib/services/livesync/platform-livesync-service-base.ts index 4471ad638f..c2be0b0adf 100644 --- a/lib/services/livesync/platform-livesync-service-base.ts +++ b/lib/services/livesync/platform-livesync-service-base.ts @@ -126,7 +126,7 @@ export abstract class PlatformLiveSyncServiceBase { return { modifiedFilesData: modifiedLocalToDevicePaths, - isFullSync: liveSyncInfo.isReinstalled, + isFullSync: false, deviceAppData, useHotModuleReload: liveSyncInfo.useHotModuleReload };