Skip to content

Commit 2514a17

Browse files
authored
Merge pull request #1939 from NativeScript/raikov/fix-debug-livesync
Fixed first time debug with livesync
2 parents af5e63d + ece558e commit 2514a17

13 files changed

+103
-29
lines changed

lib/commands/debug.ts

+37-8
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,37 @@
11
export class DebugPlatformCommand implements ICommand {
22
constructor(private debugService: IDebugService,
33
private $devicesService: Mobile.IDevicesService,
4-
private $usbLiveSyncService: ILiveSyncService,
4+
private $injector: IInjector,
55
private $logger: ILogger,
6+
private $childProcess: IChildProcess,
7+
private $devicePlatformsConstants: Mobile.IDevicePlatformsConstants,
8+
private $config: IConfiguration,
69
protected $options: IOptions) { }
710

811
execute(args: string[]): IFuture<void> {
9-
if (!this.$options.rebuild) {
10-
this.$options.debug = true;
11-
return this.$usbLiveSyncService.liveSync(this.$devicesService.platform);
12+
if (!this.$options.rebuild && !this.$options.start) {
13+
this.$config.debugLivesync = true;
14+
let usbLiveSyncService: ILiveSyncService = this.$injector.resolve("usbLiveSyncService");
15+
let liveSyncServiceBase: any = this.$injector.resolve("liveSyncServiceBase");
16+
let liveSyncProvider: ILiveSyncProvider = this.$injector.resolve("liveSyncProvider");
17+
18+
liveSyncServiceBase.on("sync", (device: Mobile.IDevice, data: ILiveSyncData) => {
19+
let platformLiveSyncService: IPlatformLiveSyncService = this.$injector.resolve(liveSyncProvider.platformSpecificLiveSyncServices[data.platform.toLowerCase()], { _device: device });
20+
let projectData: IProjectData = this.$injector.resolve("projectData");
21+
let appId = device.isEmulator ? projectData.projectName : data.appIdentifier;
22+
if (data.platform === this.$devicePlatformsConstants.iOS) {
23+
platformLiveSyncService.debugService.debugStop().wait();
24+
}
25+
device.applicationManager.stopApplication(appId).wait();
26+
platformLiveSyncService.debugService.debug().wait();
27+
});
28+
29+
liveSyncServiceBase.on("syncAfterInstall", (device: Mobile.IDevice, data: ILiveSyncData) => {
30+
let platformLiveSyncService: IPlatformLiveSyncService = this.$injector.resolve(liveSyncProvider.platformSpecificLiveSyncServices[data.platform.toLowerCase()], { _device: device });
31+
platformLiveSyncService.debugService.debug().wait();
32+
});
33+
34+
return usbLiveSyncService.liveSync(this.$devicesService.platform);
1235
}
1336
return this.debugService.debug();
1437
}
@@ -38,21 +61,27 @@
3861
export class DebugIOSCommand extends DebugPlatformCommand {
3962
constructor($iOSDebugService: IDebugService,
4063
$devicesService: Mobile.IDevicesService,
41-
$usbLiveSyncService: ILiveSyncService,
64+
$injector: IInjector,
4265
$logger: ILogger,
66+
$childProcess: IChildProcess,
67+
$devicePlatformsConstants: Mobile.IDevicePlatformsConstants,
68+
$config: IConfiguration,
4369
$options: IOptions) {
44-
super($iOSDebugService, $devicesService, $usbLiveSyncService, $logger, $options);
70+
super($iOSDebugService, $devicesService, $injector, $logger, $childProcess, $devicePlatformsConstants, $config, $options);
4571
}
4672
}
4773
$injector.registerCommand("debug|ios", DebugIOSCommand);
4874

4975
export class DebugAndroidCommand extends DebugPlatformCommand {
5076
constructor($androidDebugService: IDebugService,
5177
$devicesService: Mobile.IDevicesService,
52-
$usbLiveSyncService: ILiveSyncService,
78+
$injector: IInjector,
5379
$logger: ILogger,
80+
$childProcess: IChildProcess,
81+
$devicePlatformsConstants: Mobile.IDevicePlatformsConstants,
82+
$config: IConfiguration,
5483
$options: IOptions) {
55-
super($androidDebugService, $devicesService, $usbLiveSyncService, $logger, $options);
84+
super($androidDebugService, $devicesService, $injector, $logger, $childProcess, $devicePlatformsConstants, $config, $options);
5685
}
5786
}
5887
$injector.registerCommand("debug|android", DebugAndroidCommand);

lib/config.ts

+1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ export class Configuration extends ConfigBase implements IConfiguration { // Use
1010
USE_PROXY = false;
1111
ANDROID_DEBUG_UI: string = null;
1212
USE_POD_SANDBOX: boolean = true;
13+
debugLivesync: boolean = false;
1314

1415
/*don't require logger and everything that has logger as dependency in config.js due to cyclic dependency*/
1516
constructor(protected $fs: IFileSystem) {

lib/declarations.ts

+1
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ interface IStaticConfig extends Config.IStaticConfig { }
3838
interface IConfiguration extends Config.IConfig {
3939
ANDROID_DEBUG_UI: string;
4040
USE_POD_SANDBOX: boolean;
41+
debugLivesync: boolean;
4142
}
4243

4344
interface IApplicationPackage {

lib/definitions/debug.d.ts

+1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
interface IDebugService {
22
debug(shouldBreak?: boolean): IFuture<void>;
33
debugStart(): IFuture<void>;
4+
debugStop?(): IFuture<void>
45
platform: string;
56
}

lib/definitions/platform.d.ts

+1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ interface IPlatformService {
1111
buildForDeploy(platform: string, buildConfig?: IBuildConfig): IFuture<void>;
1212
installOnDevice(platform: string, buildConfig?: IBuildConfig): IFuture<void>;
1313
deployOnDevice(platform: string, buildConfig?: IBuildConfig): IFuture<void>;
14+
startOnDevice(platform: string): IFuture<void>;
1415
deployOnEmulator(platform: string, buildConfig?: IBuildConfig): IFuture<void>;
1516
validatePlatformInstalled(platform: string): void;
1617
validatePlatform(platform: string): void;

lib/device-sockets/ios/socket-proxy-factory.ts

+7-2
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import * as helpers from "../../common/helpers";
77

88
export class SocketProxyFactory implements ISocketProxyFactory {
99
constructor(private $logger: ILogger,
10+
private $config: IConfiguration,
1011
private $projectData: IProjectData,
1112
private $projectDataService: IProjectDataService,
1213
private $options: IOptions) { }
@@ -98,15 +99,19 @@ export class SocketProxyFactory implements ISocketProxyFactory {
9899

99100
frontendSocket.on("end", () => {
100101
this.$logger.info('Frontend socket closed!');
101-
process.exit(0);
102+
if (!(this.$config.debugLivesync && this.$options.watch)) {
103+
process.exit(0);
104+
}
102105
});
103106

104107
socketFactory((backendSocket: net.Socket) => {
105108
this.$logger.info("Backend socket created.");
106109

107110
backendSocket.on("end", () => {
108111
this.$logger.info("Backend socket closed!");
109-
process.exit(0);
112+
if (!(this.$config.debugLivesync && this.$options.watch)) {
113+
process.exit(0);
114+
}
110115
});
111116

112117
backendSocket.pipe(frontendSocket);

lib/services/ios-debug-service.ts

+25-5
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import * as iOSDevice from "../common/mobile/ios/device/ios-device";
22
import * as net from "net";
33
import * as path from "path";
44
import * as semver from "semver";
5+
import {ChildProcess} from "child_process";
56
import byline = require("byline");
67

78
const inspectorBackendPort = 18181;
@@ -13,6 +14,7 @@ const TIMEOUT_SECONDS = 90;
1314

1415
class IOSDebugService implements IDebugService {
1516
constructor(
17+
private $config: IConfiguration,
1618
private $platformService: IPlatformService,
1719
private $iOSEmulatorServices: Mobile.IEmulatorPlatformServices,
1820
private $devicesService: Mobile.IDevicesService,
@@ -31,6 +33,8 @@ class IOSDebugService implements IDebugService {
3133
private $iOSSocketRequestExecutor: IiOSSocketRequestExecutor,
3234
private $socketProxyFactory: ISocketProxyFactory) { }
3335

36+
private _lldbProcess: ChildProcess;
37+
3438
public get platform(): string {
3539
return "ios";
3640
}
@@ -70,6 +74,16 @@ class IOSDebugService implements IDebugService {
7074
}).future<void>()();
7175
}
7276

77+
public debugStop(): IFuture<void> {
78+
return (() => {
79+
if (this._lldbProcess) {
80+
this._lldbProcess.stdin.write("process detach\n");
81+
this._lldbProcess.kill();
82+
this._lldbProcess = undefined;
83+
}
84+
}).future<void>()();
85+
}
86+
7387
private emulatorDebugBrk(shouldBreak?: boolean): IFuture<void> {
7488
return (() => {
7589
let platformData = this.$platformsData.getPlatformData(this.platform);
@@ -81,16 +95,17 @@ class IOSDebugService implements IDebugService {
8195
let args = shouldBreak ? "--nativescript-debug-brk" : "--nativescript-debug-start";
8296
let child_process = this.$iOSEmulatorServices.runApplicationOnEmulator(emulatorPackage.packageName, {
8397
waitForDebugger: true, captureStdin: true,
84-
args: args, appId: this.$projectData.projectId
98+
args: args, appId: this.$projectData.projectId,
99+
skipInstall: this.$config.debugLivesync
85100
}).wait();
86101
let lineStream = byline(child_process.stdout);
87102

88103
lineStream.on('data', (line: NodeBuffer) => {
89104
let lineText = line.toString();
90105
if (lineText && _.startsWith(lineText, this.$projectData.projectId)) {
91106
let pid = _.trimStart(lineText, this.$projectData.projectId + ": ");
92-
93-
this.$childProcess.exec(`lldb -p ${pid} -o "process continue"`);
107+
this._lldbProcess = this.$childProcess.spawn("lldb", [ "-p", pid]);
108+
this._lldbProcess.stdin.write("process continue\n");
94109
} else {
95110
process.stdout.write(line + "\n");
96111
}
@@ -119,9 +134,14 @@ class IOSDebugService implements IDebugService {
119134
return this.emulatorDebugBrk(shouldBreak).wait();
120135
}
121136
// we intentionally do not wait on this here, because if we did, we'd miss the AppLaunching notification
122-
let deploy = this.$platformService.deployOnDevice(this.platform);
137+
let action: IFuture<void>;
138+
if (this.$config.debugLivesync) {
139+
action = this.$platformService.startOnDevice(this.platform);
140+
} else {
141+
action = this.$platformService.deployOnDevice(this.platform);
142+
}
123143
this.debugBrkCore(device, shouldBreak).wait();
124-
deploy.wait();
144+
action.wait();
125145
}).future<void>()()).wait();
126146
}).future<void>()();
127147
}

lib/services/livesync/android-livesync-service.ts

+4-3
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,11 @@ class AndroidLiveSyncService extends PlatformLiveSyncServiceBase<Mobile.IAndroid
2020
super(_device, $liveSyncProvider);
2121
}
2222

23+
public get debugService(): IDebugService {
24+
return this.$androidDebugService;
25+
}
26+
2327
public restartApplication(deviceAppData: Mobile.IDeviceAppData): IFuture<void> {
24-
if (this.$options.debug) {
25-
return this.$androidDebugService.debug();
26-
}
2728
return (() => {
2829
this.device.adb.executeShellCommand(["chmod", "777", deviceAppData.deviceProjectRootPath, `/data/local/tmp/${deviceAppData.appIdentifier}`]).wait();
2930

lib/services/livesync/ios-livesync-service.ts

+7-6
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,15 @@ class IOSLiveSyncService extends PlatformLiveSyncServiceBase<Mobile.IiOSDevice>
1616
private $logger: ILogger,
1717
private $options: IOptions,
1818
private $iOSDebugService: IDebugService,
19+
private $childProcess: IChildProcess,
1920
$liveSyncProvider: ILiveSyncProvider) {
2021
super(_device, $liveSyncProvider);
2122
}
2223

24+
public get debugService(): IDebugService {
25+
return this.$iOSDebugService;
26+
}
27+
2328
public afterInstallApplicationAction(deviceAppData: Mobile.IDeviceAppData, localToDevicePaths: Mobile.ILocalToDevicePathData[]): IFuture<boolean> {
2429
return (() => {
2530
return this.$options.watch;
@@ -33,12 +38,8 @@ class IOSLiveSyncService extends PlatformLiveSyncServiceBase<Mobile.IiOSDevice>
3338
}
3439

3540
protected restartApplication(deviceAppData: Mobile.IDeviceAppData): IFuture<void> {
36-
if (this.$options.debug) {
37-
return this.$iOSDebugService.debug();
38-
} else {
39-
let projectData: IProjectData = this.$injector.resolve("projectData");
40-
return this.device.applicationManager.restartApplication(deviceAppData.appIdentifier, projectData.projectName);
41-
}
41+
let projectData: IProjectData = this.$injector.resolve("projectData");
42+
return this.device.applicationManager.restartApplication(deviceAppData.appIdentifier, projectData.projectName);
4243
}
4344

4445
protected reloadPage(deviceAppData: Mobile.IDeviceAppData): IFuture<void> {

lib/services/livesync/livesync-service-base.ts

+11-3
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,11 @@ import * as temp from "temp";
66
import * as minimatch from "minimatch";
77
import * as constants from "../../common/constants";
88
import * as util from "util";
9+
import { EventEmitter } from "events";
910

1011
let gaze = require("gaze");
1112

12-
class LiveSyncServiceBase implements ILiveSyncServiceBase {
13+
class LiveSyncServiceBase extends EventEmitter implements ILiveSyncServiceBase {
1314
private showFullLiveSyncInformation: boolean = false;
1415
private fileHashes: IDictionary<string>;
1516

@@ -25,7 +26,9 @@ class LiveSyncServiceBase implements ILiveSyncServiceBase {
2526
private $projectFilesProvider: IProjectFilesProvider,
2627
private $liveSyncProvider: ILiveSyncProvider,
2728
private $devicePlatformsConstants: Mobile.IDevicePlatformsConstants,
29+
private $iOSDebugService: IDebugService,
2830
private $dispatcher: IFutureDispatcher) {
31+
super();
2932
this.fileHashes = Object.create(null);
3033
}
3134

@@ -196,7 +199,9 @@ class LiveSyncServiceBase implements ILiveSyncServiceBase {
196199
shouldRefreshApplication = platformLiveSyncService.afterInstallApplicationAction(deviceAppData, localToDevicePaths).wait();
197200

198201
if (device.applicationManager.canStartApplication() && !shouldRefreshApplication) {
199-
device.applicationManager.startApplication(appIdentifier).wait();
202+
if (!this.emit("syncAfterInstall", device, data)) {
203+
device.applicationManager.startApplication(appIdentifier).wait();
204+
}
200205
}
201206
wasInstalled = false;
202207
}
@@ -212,9 +217,12 @@ class LiveSyncServiceBase implements ILiveSyncServiceBase {
212217
}
213218

214219
this.$logger.info("Applying changes...");
215-
platformLiveSyncService.refreshApplication(deviceAppData, localToDevicePaths, data.forceExecuteFullSync || !wasInstalled).wait();
220+
if (!this.emit("sync", device, data)) {
221+
platformLiveSyncService.refreshApplication(deviceAppData, localToDevicePaths, data.forceExecuteFullSync || !wasInstalled).wait();
222+
}
216223
this.$logger.info(`Successfully synced application ${data.appIdentifier} on device ${device.deviceInfo.identifier}.`);
217224
}
225+
218226
}).future<void>()();
219227
};
220228

lib/services/platform-service.ts

+6
Original file line numberDiff line numberDiff line change
@@ -462,6 +462,12 @@ export class PlatformService implements IPlatformService {
462462
public deployOnDevice(platform: string, buildConfig?: IBuildConfig): IFuture<void> {
463463
return (() => {
464464
this.installOnDevice(platform, buildConfig).wait();
465+
this.startOnDevice(platform).wait();
466+
}).future<void>()();
467+
}
468+
469+
public startOnDevice(platform: string): IFuture<void> {
470+
return (() => {
465471
let action = (device: Mobile.IDevice) => device.applicationManager.startApplication(this.$projectData.projectId);
466472
this.$devicesService.execute(action, this.getCanExecuteAction(platform)).wait();
467473
}).future<void>()();

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@
4646
"glob": "^7.0.3",
4747
"iconv-lite": "0.4.11",
4848
"inquirer": "0.9.0",
49-
"ios-sim-portable": "~1.1.0",
49+
"ios-sim-portable": "~1.2.0",
5050
"lockfile": "1.0.1",
5151
"lodash": "4.13.1",
5252
"log4js": "0.6.26",

0 commit comments

Comments
 (0)